Version 2.6.0-dev.1.0
Merge commit 'cbdbb464ca0301060f95c861d5fe0069d0d372f7' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c6555d2..8574697 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,29 @@
### Language
+### Core libraries
+
+### Dart VM
+
+### Tools
+
+#### Pub
+
+#### Linter
+
+The Linter was updated to `0.1.97+1`, which includes:
+
+* internal migration away from using analyzer `resolutionMap`
+* various fixes and improvements to anticipate support for extension-methods
+* new lint: `camel_case_extensions`
+* rule template generation improvements
+* new lint: `avoid_equals_and_hash_code_on_mutable_classes`
+* extended `avoid_slow_async_io` to flag async `Directory` methods
+
+## 2.5.0 - 2019-09-10
+
+### Language
+
The set of operations allowed in constant expressions has been expanded as
described in
the [constant update proposal](https://github.com/dart-lang/language/issues/61).
@@ -124,7 +147,7 @@
#### `dart:io`
-* **Breaking change** [#37192](https://github.com/dart-lang/sdk/issues/37192):
+* **Breaking change** [#37192](https://github.com/dart-lang/sdk/issues/37192):
The `Cookie` class's constructor's `name` and `value`
optional positional parameters are now mandatory. The
signature changes from:
@@ -142,7 +165,7 @@
Since code could not previously correctly omit the parameters, this is not
really a breaking change.
-* **Breaking change** [#37192](https://github.com/dart-lang/sdk/issues/37192):
+* **Breaking change** [#37192](https://github.com/dart-lang/sdk/issues/37192):
The `Cookie` class's `name` and `value` setters now
validates that the strings are made from the allowed character set and are not
null. The constructor already made these checks and this
@@ -161,14 +184,11 @@
#### Linter
-The Linter was updated to `0.1.97+1`, which includes:
+The Linter was updated to `0.1.96`, which includes:
-* internal migration away from using analyzer `resolutionMap`
-* various fixes and improvements to anticipate support for extension-methods
-* new lint: `camel_case_extensions`
-* rule template generation improvements
-* new lint: `avoid_equals_and_hash_code_on_mutable_classes`
-* extended `avoid_slow_async_io` to flag async `Directory` methods
+* fixed false positives in `unnecessary_parens`
+* various changes to migrate to preferred analyzer APIs
+* rule test fixes
#### Dartdoc
diff --git a/DEPS b/DEPS
index 6033eca..dc46d63 100644
--- a/DEPS
+++ b/DEPS
@@ -174,7 +174,7 @@
Var("dart_root") + "/tools/sdks": {
"packages": [{
"package": "dart/dart-sdk/${{platform}}",
- "version": "version:2.5.0-dev.1.0",
+ "version": "version:2.5.0",
}],
"dep_type": "cipd",
},
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 7beb3f8..63a5b47 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -57,16 +57,6 @@
return unformatted_files
-def _CheckBuildStatus(input_api, output_api):
- results = []
- status_check = input_api.canned_checks.CheckTreeIsOpen(
- input_api,
- output_api,
- json_url='http://dart-status.appspot.com/current?format=json')
- results.extend(status_check)
- return results
-
-
def _CheckDartFormat(input_api, output_api):
local_root = input_api.change.RepositoryRoot()
upstream = input_api.change._upstream
@@ -250,16 +240,22 @@
long_text=stdout)
]
+
+def _CommonChecks(input_api, output_api):
+ results = []
+ results.extend(_CheckValidHostsInDEPS(input_api, output_api))
+ results.extend(_CheckDartFormat(input_api, output_api))
+ results.extend(_CheckStatusFiles(input_api, output_api))
+ results.extend(_CheckLayering(input_api, output_api))
+ results.extend(_CheckClangTidy(input_api, output_api))
+ results.extend(
+ input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
+ return results
+
+
def CheckChangeOnCommit(input_api, output_api):
- return (_CheckValidHostsInDEPS(input_api, output_api) + _CheckBuildStatus(
- input_api, output_api) + _CheckDartFormat(input_api, output_api) +
- _CheckStatusFiles(input_api, output_api) + _CheckLayering(
- input_api, output_api) + _CheckClangTidy(
- input_api, output_api))
+ return _CommonChecks(input_api, output_api)
def CheckChangeOnUpload(input_api, output_api):
- return (_CheckValidHostsInDEPS(input_api, output_api) + _CheckDartFormat(
- input_api, output_api) + _CheckStatusFiles(input_api, output_api) +
- _CheckLayering(input_api, output_api) + _CheckClangTidy(
- input_api, output_api))
+ return _CommonChecks(input_api, output_api)
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 9e1113b..4d77c9c 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -214,6 +214,7 @@
if (opType.includeReturnValueSuggestions) {
kinds.add(protocol.ElementKind.CONSTRUCTOR);
kinds.add(protocol.ElementKind.ENUM_CONSTANT);
+ kinds.add(protocol.ElementKind.EXTENSION);
kinds.add(protocol.ElementKind.FUNCTION);
kinds.add(protocol.ElementKind.TOP_LEVEL_VARIABLE);
}
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 9cb8c62..3d37042 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -104,9 +104,7 @@
static const CONVERT_TO_PACKAGE_IMPORT = const AssistKind(
'dart.assist.convert.relativeToPackageImport',
30,
- "Convert to 'package:' import",
- // todo (pq): migrate to (conditional) fix
- associatedErrorCodes: <String>['avoid_relative_lib_imports']);
+ "Convert to 'package:' import");
static const CONVERT_TO_SET_LITERAL = const AssistKind(
'dart.assist.convert.toSetLiteral', 30, "Convert to set literal",
// todo (brianwilkerson): unify w/ fix
@@ -114,13 +112,9 @@
static const CONVERT_TO_SINGLE_QUOTED_STRING = const AssistKind(
'dart.assist.convert.toSingleQuotedString',
30,
- "Convert to single quoted string",
- // todo (pq): migrate to (conditional) fix
- associatedErrorCodes: <String>['prefer_single_quotes']);
- static const CONVERT_TO_SPREAD =
- const AssistKind('dart.assist.convertToSpread', 30, "Convert to a spread",
- // todo (pq): migrate to (conditional) fix
- associatedErrorCodes: <String>['prefer_spread_collections']);
+ "Convert to single quoted string");
+ static const CONVERT_TO_SPREAD = const AssistKind(
+ 'dart.assist.convertToSpread', 30, "Convert to a spread");
static const ENCAPSULATE_FIELD =
const AssistKind('dart.assist.encapsulateField', 30, "Encapsulate field");
static const EXCHANGE_OPERANDS =
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index f3ba612..8d88015 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -101,8 +101,16 @@
)) {
await _addProposal_convertToNullAware();
}
- await _addProposal_convertToPackageImport();
- await _addProposal_convertToSingleQuotedString();
+ if (!_containsErrorCode(
+ {LintNames.avoid_relative_lib_imports},
+ )) {
+ await _addProposal_convertToPackageImport();
+ }
+ if (!_containsErrorCode(
+ {LintNames.prefer_single_quotes},
+ )) {
+ await _addProposal_convertToSingleQuotedString();
+ }
await _addProposal_encapsulateField();
await _addProposal_exchangeOperands();
await _addProposal_flutterConvertToChildren();
@@ -151,7 +159,11 @@
}
}
if (experimentStatus.spread_collections) {
- await _addProposal_convertAddAllToSpread();
+ if (!_containsErrorCode(
+ {LintNames.prefer_spread_collections},
+ )) {
+ await _addProposal_convertAddAllToSpread();
+ }
}
return assists;
@@ -252,83 +264,13 @@
}
Future<void> _addProposal_convertAddAllToSpread() async {
- AstNode node = this.node;
- if (node is! SimpleIdentifier || node.parent is! MethodInvocation) {
- _coverageMarker();
- return;
+ final change = await createBuilder_convertAddAllToSpread();
+ if (change != null) {
+ final kind = change.isLineInvocation
+ ? DartAssistKind.INLINE_INVOCATION
+ : DartAssistKind.CONVERT_TO_SPREAD;
+ _addAssistFromBuilder(change.builder, kind, args: change.args);
}
- SimpleIdentifier name = node;
- MethodInvocation invocation = node.parent;
- if (name != invocation.methodName ||
- name.name != 'addAll' ||
- !invocation.isCascaded ||
- invocation.argumentList.arguments.length != 1) {
- _coverageMarker();
- return;
- }
- CascadeExpression cascade = invocation.thisOrAncestorOfType();
- NodeList<Expression> sections = cascade.cascadeSections;
- Expression target = cascade.target;
- if (target is! ListLiteral || sections[0] != invocation) {
- // TODO(brianwilkerson) Consider extending this to handle set literals.
- _coverageMarker();
- return;
- }
-
- bool isEmptyListLiteral(Expression expression) =>
- expression is ListLiteral && expression.elements.isEmpty;
-
- ListLiteral list = target;
- Expression argument = invocation.argumentList.arguments[0];
- String elementText;
- AssistKind kind = DartAssistKind.CONVERT_TO_SPREAD;
- List<String> args = null;
- if (argument is BinaryExpression &&
- argument.operator.type == TokenType.QUESTION_QUESTION) {
- Expression right = argument.rightOperand;
- if (isEmptyListLiteral(right)) {
- // ..addAll(things ?? const [])
- // ..addAll(things ?? [])
- elementText = '...?${utils.getNodeText(argument.leftOperand)}';
- }
- } else if (experimentStatus.control_flow_collections &&
- argument is ConditionalExpression) {
- Expression elseExpression = argument.elseExpression;
- if (isEmptyListLiteral(elseExpression)) {
- // ..addAll(condition ? things : const [])
- // ..addAll(condition ? things : [])
- String conditionText = utils.getNodeText(argument.condition);
- String thenText = utils.getNodeText(argument.thenExpression);
- elementText = 'if ($conditionText) ...$thenText';
- }
- } else if (argument is ListLiteral) {
- // ..addAll([ ... ])
- NodeList<CollectionElement> elements = argument.elements;
- if (elements.isEmpty) {
- // TODO(brianwilkerson) Consider adding a cleanup for the empty list
- // case. We can essentially remove the whole invocation because it does
- // nothing.
- return;
- }
- int startOffset = elements.first.offset;
- int endOffset = elements.last.end;
- elementText = utils.getText(startOffset, endOffset - startOffset);
- kind = DartAssistKind.INLINE_INVOCATION;
- args = ['addAll'];
- }
- elementText ??= '...${utils.getNodeText(argument)}';
- DartChangeBuilder changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- if (list.elements.isNotEmpty) {
- // ['a']..addAll(['b', 'c']);
- builder.addSimpleInsertion(list.elements.last.end, ', $elementText');
- } else {
- // []..addAll(['b', 'c']);
- builder.addSimpleInsertion(list.leftBracket.end, elementText);
- }
- builder.addDeletion(range.node(invocation));
- });
- _addAssistFromBuilder(changeBuilder, kind, args: args);
}
Future<void> _addProposal_convertClassToMixin() async {
@@ -1310,45 +1252,9 @@
}
Future<void> _addProposal_convertToPackageImport() async {
- var node = this.node;
- if (node is StringLiteral) {
- node = node.parent;
- }
- if (node is ImportDirective) {
- ImportDirective importDirective = node;
- var uriSource = importDirective.uriSource;
-
- // Ignore if invalid URI.
- if (uriSource == null) {
- return;
- }
-
- var importUri = uriSource.uri;
- if (importUri.scheme != 'package') {
- return;
- }
-
- // Don't offer to convert a 'package:' URI to itself.
- try {
- if (Uri.parse(importDirective.uriContent).scheme == 'package') {
- return;
- }
- } on FormatException {
- return;
- }
-
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (builder) {
- builder.addSimpleReplacement(
- range.node(importDirective.uri),
- "'$importUri'",
- );
- });
- _addAssistFromBuilder(
- changeBuilder,
- DartAssistKind.CONVERT_TO_PACKAGE_IMPORT,
- );
- }
+ final changeBuilder = await createBuilder_convertToPackageImport();
+ _addAssistFromBuilder(
+ changeBuilder, DartAssistKind.CONVERT_TO_PACKAGE_IMPORT);
}
Future<void> _addProposal_convertToSingleQuotedString() async {
@@ -3432,57 +3338,8 @@
}
Future<void> _convertQuotes(bool fromDouble, AssistKind kind) async {
- if (node is SimpleStringLiteral) {
- SimpleStringLiteral literal = node;
- if (fromDouble ? !literal.isSingleQuoted : literal.isSingleQuoted) {
- String newQuote = literal.isMultiline
- ? (fromDouble ? "'''" : '"""')
- : (fromDouble ? "'" : '"');
- int quoteLength = literal.isMultiline ? 3 : 1;
- String lexeme = literal.literal.lexeme;
- if (lexeme.indexOf(newQuote) < 0) {
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addSimpleReplacement(
- new SourceRange(
- literal.offset + (literal.isRaw ? 1 : 0), quoteLength),
- newQuote);
- builder.addSimpleReplacement(
- new SourceRange(literal.end - quoteLength, quoteLength),
- newQuote);
- });
- _addAssistFromBuilder(changeBuilder, kind);
- }
- }
- } else if (node is InterpolationString) {
- StringInterpolation parent = node.parent;
- if (fromDouble ? !parent.isSingleQuoted : parent.isSingleQuoted) {
- String newQuote = parent.isMultiline
- ? (fromDouble ? "'''" : '"""')
- : (fromDouble ? "'" : '"');
- int quoteLength = parent.isMultiline ? 3 : 1;
- NodeList<InterpolationElement> elements = parent.elements;
- for (int i = 0; i < elements.length; i++) {
- InterpolationElement element = elements[i];
- if (element is InterpolationString) {
- String lexeme = element.contents.lexeme;
- if (lexeme.indexOf(newQuote) >= 0) {
- return;
- }
- }
- }
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addSimpleReplacement(
- new SourceRange(
- parent.offset + (parent.isRaw ? 1 : 0), quoteLength),
- newQuote);
- builder.addSimpleReplacement(
- new SourceRange(parent.end - quoteLength, quoteLength), newQuote);
- });
- _addAssistFromBuilder(changeBuilder, kind);
- }
- }
+ final changeBuilder = await createBuilder_convertQuotes(fromDouble);
+ _addAssistFromBuilder(changeBuilder, kind);
}
/**
diff --git a/pkg/analysis_server/lib/src/services/correction/base_processor.dart b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
index a67b7ca..e054c8f 100644
--- a/pkg/analysis_server/lib/src/services/correction/base_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
@@ -155,182 +155,6 @@
return validChange ? changeBuilder : null;
}
- Future<ChangeBuilder> createBuilder_convertToNullAware() async {
- AstNode node = this.node;
- if (node is! ConditionalExpression) {
- _coverageMarker();
- return null;
- }
- ConditionalExpression conditional = node;
- Expression condition = conditional.condition.unParenthesized;
- SimpleIdentifier identifier;
- Expression nullExpression;
- Expression nonNullExpression;
- int periodOffset;
-
- if (condition is BinaryExpression) {
- //
- // Identify the variable being compared to `null`, or return if the
- // condition isn't a simple comparison of `null` to a variable's value.
- //
- Expression leftOperand = condition.leftOperand;
- Expression rightOperand = condition.rightOperand;
- if (leftOperand is NullLiteral && rightOperand is SimpleIdentifier) {
- identifier = rightOperand;
- } else if (rightOperand is NullLiteral &&
- leftOperand is SimpleIdentifier) {
- identifier = leftOperand;
- } else {
- _coverageMarker();
- return null;
- }
- if (identifier.staticElement is! LocalElement) {
- _coverageMarker();
- return null;
- }
- //
- // Identify the expression executed when the variable is `null` and when
- // it is non-`null`. Return if the `null` expression isn't a null literal
- // or if the non-`null` expression isn't a method invocation whose target
- // is the save variable being compared to `null`.
- //
- if (condition.operator.type == TokenType.EQ_EQ) {
- nullExpression = conditional.thenExpression;
- nonNullExpression = conditional.elseExpression;
- } else if (condition.operator.type == TokenType.BANG_EQ) {
- nonNullExpression = conditional.thenExpression;
- nullExpression = conditional.elseExpression;
- }
- if (nullExpression == null || nonNullExpression == null) {
- _coverageMarker();
- return null;
- }
- if (nullExpression.unParenthesized is! NullLiteral) {
- _coverageMarker();
- return null;
- }
- Expression unwrappedExpression = nonNullExpression.unParenthesized;
- Expression target;
- Token operator;
- if (unwrappedExpression is MethodInvocation) {
- target = unwrappedExpression.target;
- operator = unwrappedExpression.operator;
- } else if (unwrappedExpression is PrefixedIdentifier) {
- target = unwrappedExpression.prefix;
- operator = unwrappedExpression.period;
- } else {
- _coverageMarker();
- return null;
- }
- if (operator.type != TokenType.PERIOD) {
- _coverageMarker();
- return null;
- }
- if (!(target is SimpleIdentifier &&
- target.staticElement == identifier.staticElement)) {
- _coverageMarker();
- return null;
- }
- periodOffset = operator.offset;
-
- DartChangeBuilder changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addDeletion(range.startStart(node, nonNullExpression));
- builder.addSimpleInsertion(periodOffset, '?');
- builder.addDeletion(range.endEnd(nonNullExpression, node));
- });
- return changeBuilder;
- }
- return null;
- }
-
- Future<ChangeBuilder> createBuilder_convertToExpressionFunctionBody() async {
- // prepare current body
- FunctionBody body = getEnclosingFunctionBody();
- if (body is! BlockFunctionBody || body.isGenerator) {
- _coverageMarker();
- return null;
- }
- // prepare return statement
- List<Statement> statements = (body as BlockFunctionBody).block.statements;
- if (statements.length != 1) {
- _coverageMarker();
- return null;
- }
- Statement onlyStatement = statements.first;
- // prepare returned expression
- Expression returnExpression;
- if (onlyStatement is ReturnStatement) {
- returnExpression = onlyStatement.expression;
- } else if (onlyStatement is ExpressionStatement) {
- returnExpression = onlyStatement.expression;
- }
- if (returnExpression == null) {
- _coverageMarker();
- return null;
- }
-
- // Return expressions can be quite large, e.g. Flutter build() methods.
- // It is surprising to see this Quick Assist deep in the function body.
- if (selectionOffset >= returnExpression.offset) {
- _coverageMarker();
- return null;
- }
-
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addReplacement(range.node(body), (DartEditBuilder builder) {
- if (body.isAsynchronous) {
- builder.write('async ');
- }
- builder.write('=> ');
- builder.write(_getNodeText(returnExpression));
- if (body.parent is! FunctionExpression ||
- body.parent.parent is FunctionDeclaration) {
- builder.write(';');
- }
- });
- });
- return changeBuilder;
- }
-
- /// Returns the text of the given node in the unit.
- String /* TODO (pq): make visible */ _getNodeText(AstNode node) =>
- utils.getNodeText(node);
-
- FunctionBody getEnclosingFunctionBody() {
- // TODO(brianwilkerson) Determine whether there is a reason why this method
- // isn't just "return node.getAncestor((node) => node is FunctionBody);"
- {
- FunctionExpression function =
- node.thisOrAncestorOfType<FunctionExpression>();
- if (function != null) {
- return function.body;
- }
- }
- {
- FunctionDeclaration function =
- node.thisOrAncestorOfType<FunctionDeclaration>();
- if (function != null) {
- return function.functionExpression.body;
- }
- }
- {
- ConstructorDeclaration constructor =
- node.thisOrAncestorOfType<ConstructorDeclaration>();
- if (constructor != null) {
- return constructor.body;
- }
- }
- {
- MethodDeclaration method = node.thisOrAncestorOfType<MethodDeclaration>();
- if (method != null) {
- return method.body;
- }
- }
- return null;
- }
-
Future<ChangeBuilder>
createBuilder_addTypeAnnotation_VariableDeclaration() async {
AstNode node = this.node;
@@ -391,6 +215,90 @@
return validChange ? changeBuilder : null;
}
+ Future<ConvertToSpreadCollectionsChange>
+ createBuilder_convertAddAllToSpread() async {
+ AstNode node = this.node;
+ if (node is! SimpleIdentifier || node.parent is! MethodInvocation) {
+ _coverageMarker();
+ return null;
+ }
+ SimpleIdentifier name = node;
+ MethodInvocation invocation = node.parent;
+ if (name != invocation.methodName ||
+ name.name != 'addAll' ||
+ !invocation.isCascaded ||
+ invocation.argumentList.arguments.length != 1) {
+ _coverageMarker();
+ return null;
+ }
+ CascadeExpression cascade = invocation.thisOrAncestorOfType();
+ NodeList<Expression> sections = cascade.cascadeSections;
+ Expression target = cascade.target;
+ if (target is! ListLiteral || sections[0] != invocation) {
+ // TODO(brianwilkerson) Consider extending this to handle set literals.
+ _coverageMarker();
+ return null;
+ }
+
+ bool isEmptyListLiteral(Expression expression) =>
+ expression is ListLiteral && expression.elements.isEmpty;
+
+ ListLiteral list = target;
+ Expression argument = invocation.argumentList.arguments[0];
+ String elementText;
+ ConvertToSpreadCollectionsChange change =
+ ConvertToSpreadCollectionsChange();
+ List<String> args = null;
+ if (argument is BinaryExpression &&
+ argument.operator.type == TokenType.QUESTION_QUESTION) {
+ Expression right = argument.rightOperand;
+ if (isEmptyListLiteral(right)) {
+ // ..addAll(things ?? const [])
+ // ..addAll(things ?? [])
+ elementText = '...?${utils.getNodeText(argument.leftOperand)}';
+ }
+ } else if (experimentStatus.control_flow_collections &&
+ argument is ConditionalExpression) {
+ Expression elseExpression = argument.elseExpression;
+ if (isEmptyListLiteral(elseExpression)) {
+ // ..addAll(condition ? things : const [])
+ // ..addAll(condition ? things : [])
+ String conditionText = utils.getNodeText(argument.condition);
+ String thenText = utils.getNodeText(argument.thenExpression);
+ elementText = 'if ($conditionText) ...$thenText';
+ }
+ } else if (argument is ListLiteral) {
+ // ..addAll([ ... ])
+ NodeList<CollectionElement> elements = argument.elements;
+ if (elements.isEmpty) {
+ // TODO(brianwilkerson) Consider adding a cleanup for the empty list
+ // case. We can essentially remove the whole invocation because it does
+ // nothing.
+ return null;
+ }
+ int startOffset = elements.first.offset;
+ int endOffset = elements.last.end;
+ elementText = utils.getText(startOffset, endOffset - startOffset);
+ change.isLineInvocation = true;
+ args = ['addAll'];
+ }
+ elementText ??= '...${utils.getNodeText(argument)}';
+ DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ if (list.elements.isNotEmpty) {
+ // ['a']..addAll(['b', 'c']);
+ builder.addSimpleInsertion(list.elements.last.end, ', $elementText');
+ } else {
+ // []..addAll(['b', 'c']);
+ builder.addSimpleInsertion(list.leftBracket.end, elementText);
+ }
+ builder.addDeletion(range.node(invocation));
+ });
+ change.args = args;
+ change.builder = changeBuilder;
+ return change;
+ }
+
Future<ChangeBuilder>
createBuilder_convertConditionalExpressionToIfElement() async {
AstNode node = this.node.thisOrAncestorOfType<ConditionalExpression>();
@@ -649,6 +557,111 @@
return changeBuilder;
}
+ Future<ChangeBuilder> createBuilder_convertQuotes(bool fromDouble) async {
+ if (node is SimpleStringLiteral) {
+ SimpleStringLiteral literal = node;
+ if (fromDouble ? !literal.isSingleQuoted : literal.isSingleQuoted) {
+ String newQuote = literal.isMultiline
+ ? (fromDouble ? "'''" : '"""')
+ : (fromDouble ? "'" : '"');
+ int quoteLength = literal.isMultiline ? 3 : 1;
+ String lexeme = literal.literal.lexeme;
+ if (lexeme.indexOf(newQuote) < 0) {
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addSimpleReplacement(
+ new SourceRange(
+ literal.offset + (literal.isRaw ? 1 : 0), quoteLength),
+ newQuote);
+ builder.addSimpleReplacement(
+ new SourceRange(literal.end - quoteLength, quoteLength),
+ newQuote);
+ });
+ return changeBuilder;
+ }
+ }
+ } else if (node is InterpolationString) {
+ StringInterpolation parent = node.parent;
+ if (fromDouble ? !parent.isSingleQuoted : parent.isSingleQuoted) {
+ String newQuote = parent.isMultiline
+ ? (fromDouble ? "'''" : '"""')
+ : (fromDouble ? "'" : '"');
+ int quoteLength = parent.isMultiline ? 3 : 1;
+ NodeList<InterpolationElement> elements = parent.elements;
+ for (int i = 0; i < elements.length; i++) {
+ InterpolationElement element = elements[i];
+ if (element is InterpolationString) {
+ String lexeme = element.contents.lexeme;
+ if (lexeme.indexOf(newQuote) >= 0) {
+ return null;
+ }
+ }
+ }
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addSimpleReplacement(
+ new SourceRange(
+ parent.offset + (parent.isRaw ? 1 : 0), quoteLength),
+ newQuote);
+ builder.addSimpleReplacement(
+ new SourceRange(parent.end - quoteLength, quoteLength), newQuote);
+ });
+ return changeBuilder;
+ }
+ }
+ return null;
+ }
+
+ Future<ChangeBuilder> createBuilder_convertToExpressionFunctionBody() async {
+ // prepare current body
+ FunctionBody body = getEnclosingFunctionBody();
+ if (body is! BlockFunctionBody || body.isGenerator) {
+ _coverageMarker();
+ return null;
+ }
+ // prepare return statement
+ List<Statement> statements = (body as BlockFunctionBody).block.statements;
+ if (statements.length != 1) {
+ _coverageMarker();
+ return null;
+ }
+ Statement onlyStatement = statements.first;
+ // prepare returned expression
+ Expression returnExpression;
+ if (onlyStatement is ReturnStatement) {
+ returnExpression = onlyStatement.expression;
+ } else if (onlyStatement is ExpressionStatement) {
+ returnExpression = onlyStatement.expression;
+ }
+ if (returnExpression == null) {
+ _coverageMarker();
+ return null;
+ }
+
+ // Return expressions can be quite large, e.g. Flutter build() methods.
+ // It is surprising to see this Quick Assist deep in the function body.
+ if (selectionOffset >= returnExpression.offset) {
+ _coverageMarker();
+ return null;
+ }
+
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addReplacement(range.node(body), (DartEditBuilder builder) {
+ if (body.isAsynchronous) {
+ builder.write('async ');
+ }
+ builder.write('=> ');
+ builder.write(_getNodeText(returnExpression));
+ if (body.parent is! FunctionExpression ||
+ body.parent.parent is FunctionDeclaration) {
+ builder.write(';');
+ }
+ });
+ });
+ return changeBuilder;
+ }
+
Future<ChangeBuilder> createBuilder_convertToIntLiteral() async {
if (node is! DoubleLiteral) {
_coverageMarker();
@@ -676,6 +689,135 @@
return changeBuilder;
}
+ Future<ChangeBuilder> createBuilder_convertToNullAware() async {
+ AstNode node = this.node;
+ if (node is! ConditionalExpression) {
+ _coverageMarker();
+ return null;
+ }
+ ConditionalExpression conditional = node;
+ Expression condition = conditional.condition.unParenthesized;
+ SimpleIdentifier identifier;
+ Expression nullExpression;
+ Expression nonNullExpression;
+ int periodOffset;
+
+ if (condition is BinaryExpression) {
+ //
+ // Identify the variable being compared to `null`, or return if the
+ // condition isn't a simple comparison of `null` to a variable's value.
+ //
+ Expression leftOperand = condition.leftOperand;
+ Expression rightOperand = condition.rightOperand;
+ if (leftOperand is NullLiteral && rightOperand is SimpleIdentifier) {
+ identifier = rightOperand;
+ } else if (rightOperand is NullLiteral &&
+ leftOperand is SimpleIdentifier) {
+ identifier = leftOperand;
+ } else {
+ _coverageMarker();
+ return null;
+ }
+ if (identifier.staticElement is! LocalElement) {
+ _coverageMarker();
+ return null;
+ }
+ //
+ // Identify the expression executed when the variable is `null` and when
+ // it is non-`null`. Return if the `null` expression isn't a null literal
+ // or if the non-`null` expression isn't a method invocation whose target
+ // is the save variable being compared to `null`.
+ //
+ if (condition.operator.type == TokenType.EQ_EQ) {
+ nullExpression = conditional.thenExpression;
+ nonNullExpression = conditional.elseExpression;
+ } else if (condition.operator.type == TokenType.BANG_EQ) {
+ nonNullExpression = conditional.thenExpression;
+ nullExpression = conditional.elseExpression;
+ }
+ if (nullExpression == null || nonNullExpression == null) {
+ _coverageMarker();
+ return null;
+ }
+ if (nullExpression.unParenthesized is! NullLiteral) {
+ _coverageMarker();
+ return null;
+ }
+ Expression unwrappedExpression = nonNullExpression.unParenthesized;
+ Expression target;
+ Token operator;
+ if (unwrappedExpression is MethodInvocation) {
+ target = unwrappedExpression.target;
+ operator = unwrappedExpression.operator;
+ } else if (unwrappedExpression is PrefixedIdentifier) {
+ target = unwrappedExpression.prefix;
+ operator = unwrappedExpression.period;
+ } else {
+ _coverageMarker();
+ return null;
+ }
+ if (operator.type != TokenType.PERIOD) {
+ _coverageMarker();
+ return null;
+ }
+ if (!(target is SimpleIdentifier &&
+ target.staticElement == identifier.staticElement)) {
+ _coverageMarker();
+ return null;
+ }
+ periodOffset = operator.offset;
+
+ DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addDeletion(range.startStart(node, nonNullExpression));
+ builder.addSimpleInsertion(periodOffset, '?');
+ builder.addDeletion(range.endEnd(nonNullExpression, node));
+ });
+ return changeBuilder;
+ }
+ return null;
+ }
+
+ Future<ChangeBuilder> createBuilder_convertToPackageImport() async {
+ var node = this.node;
+ if (node is StringLiteral) {
+ node = node.parent;
+ }
+ if (node is ImportDirective) {
+ ImportDirective importDirective = node;
+ var uriSource = importDirective.uriSource;
+
+ // Ignore if invalid URI.
+ if (uriSource == null) {
+ return null;
+ }
+
+ var importUri = uriSource.uri;
+ if (importUri.scheme != 'package') {
+ return null;
+ }
+
+ // Don't offer to convert a 'package:' URI to itself.
+ try {
+ if (Uri.parse(importDirective.uriContent).scheme == 'package') {
+ return null;
+ }
+ } on FormatException {
+ return null;
+ }
+
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (builder) {
+ builder.addSimpleReplacement(
+ range.node(importDirective.uri),
+ "'$importUri'",
+ );
+ });
+ return changeBuilder;
+ }
+ return null;
+ }
+
@protected
Future<ChangeBuilder> createBuilder_useCurlyBraces() async {
Future<ChangeBuilder> doStatement(DoStatement node) async {
@@ -803,6 +945,39 @@
return null;
}
+ FunctionBody getEnclosingFunctionBody() {
+ // TODO(brianwilkerson) Determine whether there is a reason why this method
+ // isn't just "return node.getAncestor((node) => node is FunctionBody);"
+ {
+ FunctionExpression function =
+ node.thisOrAncestorOfType<FunctionExpression>();
+ if (function != null) {
+ return function.body;
+ }
+ }
+ {
+ FunctionDeclaration function =
+ node.thisOrAncestorOfType<FunctionDeclaration>();
+ if (function != null) {
+ return function.functionExpression.body;
+ }
+ }
+ {
+ ConstructorDeclaration constructor =
+ node.thisOrAncestorOfType<ConstructorDeclaration>();
+ if (constructor != null) {
+ return constructor.body;
+ }
+ }
+ {
+ MethodDeclaration method = node.thisOrAncestorOfType<MethodDeclaration>();
+ if (method != null) {
+ return method.body;
+ }
+ }
+ return null;
+ }
+
@protected
bool setupCompute() {
final locator = NodeLocator(selectionOffset, selectionEnd);
@@ -822,6 +997,10 @@
}
}
+ /// Returns the text of the given node in the unit.
+ String /* TODO (pq): make visible */ _getNodeText(AstNode node) =>
+ utils.getNodeText(node);
+
DartChangeBuilder _newDartChangeBuilder() =>
DartChangeBuilderImpl.forWorkspace(workspace);
@@ -833,6 +1012,12 @@
static void _coverageMarker() {}
}
+class ConvertToSpreadCollectionsChange {
+ ChangeBuilder builder;
+ List<String> args;
+ bool isLineInvocation = false;
+}
+
/// A visitor that can be used to find references to a parameter.
class _ParameterReferenceFinder extends RecursiveAstVisitor<void> {
/// The parameter for which references are being sought, or `null` if we are
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index ff70d93..bac44cb 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -199,6 +199,12 @@
'CONVERT_TO_NAMED_ARGUMENTS', 50, "Convert to named arguments");
static const CONVERT_TO_NULL_AWARE =
const FixKind('CONVERT_TO_NULL_AWARE', 50, "Convert to use '?.'");
+ static const CONVERT_TO_PACKAGE_IMPORT = const FixKind(
+ 'CONVERT_TO_PACKAGE_IMPORT', 50, "Convert to 'package:' import");
+ static const CONVERT_TO_SINGLE_QUOTED_STRING = const FixKind(
+ 'CONVERT_TO_SINGLE_QUOTED_STRING', 50, "Convert to single quoted string");
+ static const CONVERT_TO_SPREAD =
+ const FixKind('CONVERT_TO_SPREAD', 50, "Convert to a spread");
static const CREATE_CLASS =
const FixKind('CREATE_CLASS', 50, "Create class '{0}'");
static const CREATE_CONSTRUCTOR =
@@ -245,6 +251,8 @@
const FixKind('IMPORT_LIBRARY_SDK', 54, "Import library '{0}'");
static const IMPORT_LIBRARY_SHOW =
const FixKind('IMPORT_LIBRARY_SHOW', 55, "Update library '{0}' import");
+ static const INLINE_INVOCATION =
+ const FixKind('INLINE_INVOCATION', 30, "Inline invocation of '{0}'");
static const INSERT_SEMICOLON =
const FixKind('INSERT_SEMICOLON', 50, "Insert ';'");
static const MAKE_CLASS_ABSTRACT =
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 0a857ce..491d0e2 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -585,6 +585,9 @@
if (name == LintNames.avoid_init_to_null) {
await _addFix_removeInitializer();
}
+ if (name == LintNames.avoid_relative_lib_imports) {
+ await _addFix_convertToPackageImport();
+ }
if (name == LintNames.avoid_return_types_on_setters) {
await _addFix_removeTypeAnnotation();
}
@@ -656,9 +659,15 @@
if (name == LintNames.prefer_null_aware_operators) {
await _addFix_convertToNullAware();
}
+ if (name == LintNames.prefer_single_quotes) {
+ await _addFix_convertSingleQuotes();
+ }
if (errorCode.name == LintNames.slash_for_doc_comments) {
await _addFix_convertDocumentationIntoLine();
}
+ if (name == LintNames.prefer_spread_collections) {
+ await _addFix_convertAddAllToSpread();
+ }
if (name == LintNames.type_init_formals) {
await _addFix_removeTypeAnnotation();
}
@@ -738,11 +747,6 @@
_addFixFromBuilder(changeBuilder, DartFixKind.ADD_CURLY_BRACES);
}
- Future<void> _addFix_convertToNullAware() async {
- final changeBuilder = await createBuilder_convertToNullAware();
- _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_NULL_AWARE);
- }
-
Future<void> _addFix_addExplicitCast() async {
if (coveredNode is! Expression) {
return;
@@ -1368,6 +1372,12 @@
_addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_FOR_ELEMENT);
}
+ Future<void> _addFix_convertSingleQuotes() async {
+ final changeBuilder = await createBuilder_convertQuotes(true);
+ _addFixFromBuilder(
+ changeBuilder, DartFixKind.CONVERT_TO_SINGLE_QUOTED_STRING);
+ }
+
Future<void> _addFix_convertToExpressionBody() async {
final changeBuilder = await createBuilder_convertToExpressionFunctionBody();
_addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_INTO_EXPRESSION_BODY);
@@ -1449,6 +1459,16 @@
}
}
+ Future<void> _addFix_convertToNullAware() async {
+ final changeBuilder = await createBuilder_convertToNullAware();
+ _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_NULL_AWARE);
+ }
+
+ Future<void> _addFix_convertToPackageImport() async {
+ final changeBuilder = await createBuilder_convertToPackageImport();
+ _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_PACKAGE_IMPORT);
+ }
+
Future<void> _addFix_createClass() async {
Element prefixElement = null;
String name = null;
@@ -1857,6 +1877,16 @@
}
}
+ Future<void> _addFix_convertAddAllToSpread() async {
+ final change = await createBuilder_convertAddAllToSpread();
+ if (change != null) {
+ final kind = change.isLineInvocation
+ ? DartFixKind.INLINE_INVOCATION
+ : DartFixKind.CONVERT_TO_SPREAD;
+ _addFixFromBuilder(change.builder, kind, args: change.args);
+ }
+ }
+
Future<void> _addFix_createField() async {
if (node is! SimpleIdentifier) {
return;
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index c52000b..b935e7f 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -12,6 +12,7 @@
'avoid_annotating_with_dynamic';
static const String avoid_empty_else = 'avoid_empty_else';
static const String avoid_init_to_null = 'avoid_init_to_null';
+ static const String avoid_relative_lib_imports = 'avoid_relative_lib_imports';
static const String avoid_return_types_on_setters =
'avoid_return_types_on_setters';
static const String avoid_types_on_closure_parameters =
@@ -46,7 +47,9 @@
static const String prefer_is_not_empty = 'prefer_is_not_empty';
static const String prefer_null_aware_operators =
'prefer_null_aware_operators';
+ static const String prefer_single_quotes = 'prefer_single_quotes';
static const String slash_for_doc_comments = 'slash_for_doc_comments';
+ static const String prefer_spread_collections = 'prefer_spread_collections';
static const String type_annotate_public_apis = 'type_annotate_public_apis';
static const String type_init_formals = 'type_init_formals';
static const String unawaited_futures = 'unawaited_futures';
diff --git a/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart b/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
index e6704f8..d9f168d 100644
--- a/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
+++ b/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
@@ -181,6 +181,7 @@
ElementKind.CONSTRUCTOR,
ElementKind.ENUM,
ElementKind.ENUM_CONSTANT,
+ ElementKind.EXTENSION,
ElementKind.FUNCTION,
ElementKind.FUNCTION_TYPE_ALIAS,
ElementKind.MIXIN,
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_package_import_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_package_import_test.dart
index 84df167..9da35b6 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_package_import_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_package_import_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -52,7 +53,7 @@
test_nonPackage_Uri() async {
addSource('/home/test/lib/foo.dart', '');
-
+ testFile = convertPath('/home/test/lib/src/test.dart');
await resolveTestUnit('''
import 'dart:core';
''');
@@ -83,4 +84,15 @@
import 'package:test/foo/bar.dart';
''');
}
+
+ test_relativeImport_noAssistWithLint() async {
+ createAnalysisOptionsFile(lints: [LintNames.avoid_relative_lib_imports]);
+ verifyNoTestUnitErrors = false;
+ addSource('/home/test/lib/foo.dart', '');
+
+ await resolveTestUnit('''
+import '../lib/foo.dart';
+''');
+ await assertNoAssist();
+ }
}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_single_quoted_string_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_single_quoted_string_test.dart
index 161f62c..6c34598 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_single_quoted_string_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_single_quoted_string_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -80,6 +81,17 @@
''');
}
+ test_one_simple_noAssistWithLint() async {
+ createAnalysisOptionsFile(lints: [LintNames.prefer_single_quotes]);
+ verifyNoTestUnitErrors = false;
+ await resolveTestUnit('''
+main() {
+ print("abc");
+}
+''');
+ await assertNoAssist();
+ }
+
test_three_embeddedTarget() async {
await resolveTestUnit('''
main() {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_spread_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_spread_test.dart
index 6242b56..4e354c7 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_spread_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_spread_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -41,6 +42,18 @@
''');
}
+ test_addAll_expression_noAssistWithLint() async {
+ createAnalysisOptionsFile(lints: [LintNames.prefer_spread_collections]);
+ verifyNoTestUnitErrors = false;
+ await resolveTestUnit('''
+f() {
+ var ints = [1, 2, 3];
+ print(['a']..addAl/*caret*/l(ints.map((i) => i.toString()))..addAll(['c']));
+}
+''');
+ await assertNoAssist();
+ }
+
test_addAll_expression_toEmptyList() async {
await resolveTestUnit('''
f() {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_package_import_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_package_import_test.dart
new file mode 100644
index 0000000..dfa4706
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_package_import_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ConvertToPackageImportTest);
+ });
+}
+
+@reflectiveTest
+class ConvertToPackageImportTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.CONVERT_TO_PACKAGE_IMPORT;
+
+ @override
+ String get lintCode => LintNames.avoid_relative_lib_imports;
+
+ /// More coverage in the `convert_to_package_import_test.dart` assist test.
+ test_relativeImport() async {
+ addSource('/home/test/lib/foo.dart', '');
+ testFile = convertPath('/home/test/lib/src/test.dart');
+ await resolveTestUnit('''
+import /*LINT*/'../lib/foo.dart';
+''');
+
+ await assertHasFix('''
+import /*LINT*/'package:test/lib/foo.dart';
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_single_quoted_string_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_single_quoted_string_test.dart
new file mode 100644
index 0000000..97e2746
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_single_quoted_string_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ConvertToSingleQuotedStringTest);
+ });
+}
+
+@reflectiveTest
+class ConvertToSingleQuotedStringTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.CONVERT_TO_SINGLE_QUOTED_STRING;
+
+ @override
+ String get lintCode => LintNames.prefer_single_quotes;
+
+ /// More coverage in the `convert_to_single_quoted_string_test.dart` assist test.
+ test_one_simple() async {
+ await resolveTestUnit('''
+main() {
+ print(/*LINT*/"abc");
+}
+''');
+ await assertHasFix('''
+main() {
+ print(/*LINT*/'abc');
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_spread_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_spread_test.dart
new file mode 100644
index 0000000..a2cf96e
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_spread_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ConvertToSpreadTest);
+ });
+}
+
+@reflectiveTest
+class ConvertToSpreadTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.CONVERT_TO_SPREAD;
+
+ @override
+ String get lintCode => LintNames.prefer_spread_collections;
+
+ /// More coverage in the `convert_to_spread_test.dart` assist test.
+ test_addAll_expression() async {
+ await resolveTestUnit('''
+f() {
+ var ints = [1, 2, 3];
+ print(['a']../*LINT*/addAll(ints.map((i) => i.toString()))..addAll(['c']));
+}
+''');
+ await assertHasFix('''
+f() {
+ var ints = [1, 2, 3];
+ print(['a', ...ints.map((i) => i.toString())]..addAll(['c']));
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index 67efef9..4e74718 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -43,6 +43,10 @@
import 'convert_to_int_literal_test.dart' as convert_to_int_literal;
import 'convert_to_named_arguments_test.dart' as convert_to_named_arguments;
import 'convert_to_null_aware_test.dart' as convert_to_null_aware;
+import 'convert_to_package_import_test.dart' as convert_to_package_import;
+import 'convert_to_single_quoted_string_test.dart'
+ as convert_to_single_quoted_string;
+import 'convert_to_spread_test.dart' as convert_to_spread;
import 'create_class_test.dart' as create_class;
import 'create_constructor_for_final_fields_test.dart'
as create_constructor_for_final_field;
@@ -156,6 +160,9 @@
convert_to_int_literal.main();
convert_to_named_arguments.main();
convert_to_null_aware.main();
+ convert_to_package_import.main();
+ convert_to_single_quoted_string.main();
+ convert_to_spread.main();
create_class.main();
create_constructor_for_final_field.main();
create_constructor_super.main();
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 1b18be9..02fdde9 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -825,7 +825,8 @@
/// [Expression] cascadeSection*
///
/// cascadeSection ::=
-/// '..' (cascadeSelector arguments*) (assignableSelector arguments*)*
+/// ('..' | '?..') (cascadeSelector arguments*)
+/// (assignableSelector arguments*)*
/// (assignmentOperator expressionWithoutCascade)?
///
/// cascadeSelector ::=
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 2b09546..0d75a23 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -2396,6 +2396,8 @@
ErrorCode errorCode = error.errorCode;
if (errorCode is CompileTimeErrorCode) {
switch (errorCode) {
+ case CompileTimeErrorCode
+ .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST:
case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL:
case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_INT:
case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING:
@@ -2405,8 +2407,7 @@
case CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE:
case CompileTimeErrorCode.CONST_WITH_NON_CONST:
case CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT:
- case CompileTimeErrorCode
- .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST:
+ case CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS:
case CompileTimeErrorCode.INVALID_CONSTANT:
case CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL:
case CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL:
@@ -5912,8 +5913,8 @@
/// index expression is part of a cascade expression.
ExpressionImpl _target;
- /// The period ("..") before a cascaded index expression, or `null` if this
- /// index expression is not part of a cascade expression.
+ /// The period (".." | "?..") before a cascaded index expression,
+ /// or `null` if this index expression is not part of a cascade expression.
@override
Token period;
@@ -7130,7 +7131,7 @@
/// The operator that separates the target from the method name, or `null`
/// if there is no target. In an ordinary method invocation this will be a
/// period ('.'). In a cascade section this will be the cascade operator
- /// ('..').
+ /// ('..' | '?..').
@override
Token operator;
@@ -7179,7 +7180,9 @@
@override
bool get isCascaded =>
- operator != null && operator.type == TokenType.PERIOD_PERIOD;
+ operator != null &&
+ (operator.type == TokenType.PERIOD_PERIOD ||
+ operator.type == TokenType.QUESTION_PERIOD_PERIOD);
@override
SimpleIdentifier get methodName => _methodName;
@@ -8436,7 +8439,9 @@
@override
bool get isCascaded =>
- operator != null && operator.type == TokenType.PERIOD_PERIOD;
+ operator != null &&
+ (operator.type == TokenType.PERIOD_PERIOD ||
+ operator.type == TokenType.QUESTION_PERIOD_PERIOD);
@override
Precedence get precedence => Precedence.postfix;
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index bbff1e7..86d5b66 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -7526,7 +7526,7 @@
@override
void visitIndexExpression(IndexExpression node) {
if (node.isCascaded) {
- _writer.print("..");
+ _writer.print(node.period.lexeme);
} else {
_visitNode(node.target);
}
@@ -7635,7 +7635,7 @@
@override
void visitMethodInvocation(MethodInvocation node) {
if (node.isCascaded) {
- _writer.print("..");
+ _writer.print(node.operator.lexeme);
} else {
if (node.target != null) {
node.target.accept(this);
@@ -7735,7 +7735,7 @@
@override
void visitPropertyAccess(PropertyAccess node) {
if (node.isCascaded) {
- _writer.print("..");
+ _writer.print(node.operator.lexeme);
} else {
_visitNode(node.target);
_writer.print(node.operator.lexeme);
@@ -8833,7 +8833,7 @@
@override
void visitIndexExpression(IndexExpression node) {
if (node.isCascaded) {
- sink.write("..");
+ sink.write(node.period.lexeme);
} else {
safelyVisitNode(node.target);
}
@@ -8942,7 +8942,7 @@
@override
void visitMethodInvocation(MethodInvocation node) {
if (node.isCascaded) {
- sink.write("..");
+ sink.write(node.operator.lexeme);
} else {
if (node.target != null) {
node.target.accept(this);
@@ -9042,7 +9042,7 @@
@override
void visitPropertyAccess(PropertyAccess node) {
if (node.isCascaded) {
- sink.write("..");
+ sink.write(node.operator.lexeme);
} else {
safelyVisitNode(node.target);
sink.write(node.operator.lexeme);
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 76ba63d..0d8b1c2 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -734,7 +734,7 @@
*/
static const HintCode SDK_VERSION_EXTENSION_METHODS = const HintCode(
'SDK_VERSION_EXTENSION_METHODS',
- "Extension methods weren't supported until version 2.X.0, "
+ "Extension methods weren't supported until version 2.6.0, "
"but this code is required to be able to run on earlier versions.",
correction: "Try updating the SDK constraints.");
diff --git a/pkg/analyzer/lib/src/error/literal_element_verifier.dart b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
index 5e2e26c..fb2cced 100644
--- a/pkg/analyzer/lib/src/error/literal_element_verifier.dart
+++ b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
@@ -4,7 +4,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/element/type.dart';
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index f45a35a..fa944a9 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -169,7 +169,7 @@
}
void beginCascade(Token token) {
- assert(optional('..', token));
+ assert(optional('..', token) || optional('?..', token));
debugEvent("beginCascade");
Expression expression = pop();
@@ -577,12 +577,14 @@
assert(operatorToken.isOperator ||
optional('.', operatorToken) ||
optional('?.', operatorToken) ||
- optional('..', operatorToken));
+ optional('..', operatorToken) ||
+ optional('?..', operatorToken));
debugEvent("BinaryExpression");
if (identical(".", operatorToken.stringValue) ||
identical("?.", operatorToken.stringValue) ||
- identical("..", operatorToken.stringValue)) {
+ identical("..", operatorToken.stringValue) ||
+ identical("?..", operatorToken.stringValue)) {
doDotExpression(operatorToken);
} else {
Expression right = pop();
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 8518284..e91190e 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -173,8 +173,8 @@
String methodName = operatorType.lexeme;
// TODO(brianwilkerson) Change the [methodNameNode] from the left hand
// side to the operator.
- ResolutionResult result =
- _lookUpMethod(leftHandSide, staticType, methodName, leftHandSide);
+ var result = _newPropertyResolver().resolveOperator(
+ leftHandSide, staticType, methodName, leftHandSide);
node.staticElement = result.function;
if (_shouldReportInvalidMember(staticType, result)) {
_recordUndefinedToken(
@@ -266,20 +266,11 @@
}
if (node.newKeyword == null) {
if (element is ClassElement) {
- Element memberElement =
- _lookupGetterOrMethod(element.type, name.name);
- if (memberElement == null) {
- memberElement = element.getNamedConstructor(name.name);
- if (memberElement == null) {
- memberElement =
- _lookUpSetter(prefix, element.type, name.name, name).setter;
- }
- }
- if (memberElement == null) {
-// reportGetterOrSetterNotFound(identifier, name, element.getDisplayName());
- } else {
- name.staticElement = memberElement;
- }
+ var propertyResolver = _newPropertyResolver();
+ propertyResolver.resolve(prefix, element.type, name.name, name);
+ name.staticElement = propertyResolver.getterResult.getter ??
+ propertyResolver.setterResult.setter ??
+ element.getNamedConstructor(name.name);
} else {
// TODO(brianwilkerson) Report this error.
}
@@ -481,16 +472,16 @@
bool isInSetterContext = node.inSetterContext();
if (isInGetterContext && isInSetterContext) {
// lookup setter
- ResolutionResult setterResult =
- _lookUpMethod(target, staticType, setterMethodName, target);
+ ResolutionResult setterResult = _newPropertyResolver()
+ .resolveOperator(target, staticType, setterMethodName, target);
// set setter element
node.staticElement = setterResult.function;
// generate undefined method warning
_checkForUndefinedIndexOperator(
node, target, setterMethodName, setterResult, staticType);
// lookup getter method
- ResolutionResult getterResult =
- _lookUpMethod(target, staticType, getterMethodName, target);
+ ResolutionResult getterResult = _newPropertyResolver()
+ .resolveOperator(target, staticType, getterMethodName, target);
// set getter element
AuxiliaryElements auxiliaryElements =
new AuxiliaryElements(getterResult.function, null);
@@ -500,8 +491,8 @@
node, target, getterMethodName, getterResult, staticType);
} else if (isInGetterContext) {
// lookup getter method
- ResolutionResult methodResult =
- _lookUpMethod(target, staticType, getterMethodName, target);
+ ResolutionResult methodResult = _newPropertyResolver()
+ .resolveOperator(target, staticType, getterMethodName, target);
// set getter element
node.staticElement = methodResult.function;
// generate undefined method warning
@@ -509,8 +500,8 @@
node, target, getterMethodName, methodResult, staticType);
} else if (isInSetterContext) {
// lookup setter method
- ResolutionResult methodResult =
- _lookUpMethod(target, staticType, setterMethodName, target);
+ ResolutionResult methodResult = _newPropertyResolver()
+ .resolveOperator(target, staticType, setterMethodName, target);
// set setter element
node.staticElement = methodResult.function;
// generate undefined method warning
@@ -566,10 +557,8 @@
}
String methodName = _getPostfixOperator(node);
DartType staticType = _getStaticType(operand);
- // TODO(brianwilkerson) Change the [methodNameNode] from the operand to
- // the operator.
- ResolutionResult result =
- _lookUpMethod(operand, staticType, methodName, operand);
+ var result = _newPropertyResolver()
+ .resolveOperator(operand, staticType, methodName, operand);
node.staticElement = result.function;
if (_shouldReportInvalidMember(staticType, result)) {
if (operand is SuperExpression) {
@@ -674,10 +663,8 @@
Expression operand = node.operand;
String methodName = _getPrefixOperator(node);
DartType staticType = _getStaticType(operand, read: true);
- // TODO(brianwilkerson) Change the [methodNameNode] from the operand to
- // the operator.
- ResolutionResult result =
- _lookUpMethod(operand, staticType, methodName, operand);
+ var result = _newPropertyResolver()
+ .resolveOperator(operand, staticType, methodName, operand);
node.staticElement = result.function;
if (_shouldReportInvalidMember(staticType, result)) {
if (operand is SuperExpression) {
@@ -874,9 +861,12 @@
node.inGetterContext() &&
enclosingClass != null) {
InterfaceType enclosingType = enclosingClass.type;
- AuxiliaryElements auxiliaryElements = new AuxiliaryElements(
- _lookUpGetter(null, enclosingType, node.name, node).getter, null);
- node.auxiliaryElements = auxiliaryElements;
+ var propertyResolver = _newPropertyResolver();
+ propertyResolver.resolve(null, enclosingType, node.name, node);
+ node.auxiliaryElements = AuxiliaryElements(
+ propertyResolver.getterResult.getter,
+ null,
+ );
}
//
// Validate annotation element.
@@ -1090,8 +1080,10 @@
parameterizableType = invokeType;
parameters = invokeType.typeFormals;
} else if (invokeType is InterfaceType) {
- MethodElement callMethod =
- _lookUpCallMethod(invokeType, invocation.function);
+ var propertyResolver = _newPropertyResolver();
+ propertyResolver.resolve(null, invokeType,
+ FunctionElement.CALL_METHOD_NAME, invocation.function);
+ MethodElement callMethod = propertyResolver.getterResult.function;
invocation.staticElement = callMethod;
parameterizableType = callMethod?.type;
parameters = (parameterizableType as FunctionType)?.typeFormals;
@@ -1210,135 +1202,9 @@
}
}
- /**
- * Return the element representing the `call` method that is defined for the
- * given [type]. If there are multiple `call` methods defined by extensions,
- * use the given [node] to report the error.
- */
- MethodElement _lookUpCallMethod(InterfaceType type, Expression node) {
- var callMethod = type.lookUpMethod(
- FunctionElement.CALL_METHOD_NAME,
- _resolver.definingLibrary,
- );
- if (callMethod != null) {
- return callMethod;
- }
-
- var result = _extensionResolver.findExtension(
- type, FunctionElement.CALL_METHOD_NAME, node);
- var instantiatedMember = result.function;
- if (instantiatedMember is MethodElement) {
- return instantiatedMember;
- }
-
- return null;
- }
-
- /**
- * Look up the getter with the given [name] in the given [type]. Return a
- * result representing the result of that lookup. The [target] is the target
- * of the invocation, or `null` if there is no target.
- */
- ResolutionResult _lookUpGetter(
- Expression target, DartType type, String name, Expression nameNode) {
- type = _resolveTypeParameter(type);
- ResolutionResult result = ResolutionResult.none;
-
- void lookupIn(InterfaceType type) {
- var getter = type.lookUpInheritedGetter(name,
- library: _definingLibrary, thisType: target is! SuperExpression);
- if (getter != null) {
- result = ResolutionResult(property: getter.variable);
- }
- }
-
- if (type is InterfaceType) {
- lookupIn(type);
- } else if (type is FunctionType) {
- lookupIn(_resolver.typeProvider.functionType);
- } else {
- return ResolutionResult.none;
- }
- if (result.isNone) {
- result = _extensionResolver.findExtension(type, name, nameNode);
- }
- return result;
- }
-
- /**
- * Look up the method or getter with the given [name] in the given
- * [type]. Return the element representing the method or getter that was
- * found, or `null` if there is no method or getter with the given name.
- */
- ExecutableElement _lookupGetterOrMethod(DartType type, String name) {
- type = _resolveTypeParameter(type);
- if (type is InterfaceType) {
- return type.lookUpInheritedGetterOrMethod(name,
- library: _definingLibrary);
- }
- return null;
- }
-
- /**
- * Look up the method with the given [name] in the given [type]. Return a
- * result representing the result of that lookup. The [target] is the target
- * of the invocation, or `null` if there is no target.
- */
- ResolutionResult _lookUpMethod(
- Expression target, DartType type, String name, Expression nameNode) {
- type = _resolveTypeParameter(type);
- ResolutionResult result = ResolutionResult.none;
-
- void lookupIn(InterfaceType type) {
- var method = type.lookUpInheritedMethod(name,
- library: _definingLibrary, thisType: target is! SuperExpression);
- if (method != null) {
- result = ResolutionResult(function: method);
- }
- }
-
- if (type is InterfaceType) {
- lookupIn(type);
- } else if (type is FunctionType) {
- lookupIn(_resolver.typeProvider.functionType);
- } else {
- return ResolutionResult.none;
- }
- if (result.isNone) {
- result = _extensionResolver.findExtension(type, name, nameNode);
- }
- return result;
- }
-
- /**
- * Look up the setter with the given [name] in the given [type]. Return a
- * result representing the result of that lookup. The [target] is the target
- * of the invocation, or `null` if there is no target.
- */
- ResolutionResult _lookUpSetter(
- Expression target, DartType type, String name, Expression nameNode) {
- type = _resolveTypeParameter(type);
- ResolutionResult result = ResolutionResult.none;
-
- void lookupIn(InterfaceType type) {
- var setter = type.lookUpInheritedSetter(name,
- library: _definingLibrary, thisType: target is! SuperExpression);
- if (setter != null) {
- result = ResolutionResult(property: setter.variable);
- }
- }
-
- if (type is InterfaceType) {
- lookupIn(type);
- } else if (type is FunctionType) {
- lookupIn(_resolver.typeProvider.functionType);
- } else {
- return ResolutionResult.none;
- }
- if (result.isNone) {
- result = _extensionResolver.findExtension(type, name, nameNode);
- }
- return result;
+ _PropertyResolver _newPropertyResolver() {
+ return _PropertyResolver(_resolver.typeProvider, _inheritance,
+ _definingLibrary, _extensionResolver);
}
/**
@@ -1573,35 +1439,13 @@
return;
}
DartType leftType = _getStaticType(leftOperand);
- var isSuper = leftOperand is SuperExpression;
-
- ResolutionResult result = ResolutionResult.none;
-
- void lookupIn(InterfaceType type) {
- ExecutableElement invokeElement = _inheritance.getMember(
- type,
- new Name(_definingLibrary.source.uri, methodName),
- forSuper: isSuper,
- );
- if (invokeElement != null) {
- result = ResolutionResult(function: invokeElement);
- }
- }
-
- if (leftType is InterfaceType) {
- lookupIn(leftType);
- } else if (leftType is FunctionType) {
- lookupIn(_resolver.typeProvider.functionType);
- }
-
- if (result.isNone) {
- result = _extensionResolver.findExtension(leftType, methodName, node);
- }
+ ResolutionResult result = _newPropertyResolver()
+ .resolveOperator(leftOperand, leftType, methodName, node);
node.staticElement = result.function;
node.staticInvokeType = result.function?.type;
if (_shouldReportInvalidMember(leftType, result)) {
- if (isSuper) {
+ if (leftOperand is SuperExpression) {
_recordUndefinedToken(
leftType.element,
StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR,
@@ -1699,18 +1543,15 @@
*/
ResolutionResult _resolveProperty(
Expression target, DartType targetType, SimpleIdentifier propertyName) {
+ var propertyResolver = _newPropertyResolver();
+ propertyResolver.resolve(
+ target, targetType, propertyName.name, propertyName);
ResolutionResult result = ResolutionResult.none;
if (propertyName.inSetterContext()) {
- result =
- _lookUpSetter(target, targetType, propertyName.name, propertyName);
+ result = propertyResolver.setterResult;
}
if (result.isNone) {
- result =
- _lookUpGetter(target, targetType, propertyName.name, propertyName);
- }
- if (result.isNone) {
- result =
- _lookUpMethod(target, targetType, propertyName.name, propertyName);
+ result = propertyResolver.getterResult;
}
return result;
}
@@ -1907,9 +1748,10 @@
//
ClassElement enclosingClass = _resolver.enclosingClass;
if (enclosingClass != null) {
- setter = _lookUpSetter(
- null, enclosingClass.type, identifier.name, identifier)
- .setter;
+ var propertyResolver = _newPropertyResolver();
+ propertyResolver.resolve(
+ null, enclosingClass.type, identifier.name, identifier);
+ setter = propertyResolver.setterResult.setter;
}
}
if (setter != null) {
@@ -1943,24 +1785,15 @@
} else {
enclosingType = enclosingClass.type;
}
- if (enclosingType != null) {
- if (element == null &&
- (identifier.inSetterContext() ||
- identifier.parent is CommentReference)) {
- element =
- _lookUpSetter(null, enclosingType, identifier.name, identifier)
- .setter;
+ if (element == null && enclosingType != null) {
+ var propertyResolver = _newPropertyResolver();
+ propertyResolver.resolve(
+ null, enclosingType, identifier.name, identifier);
+ if (identifier.inSetterContext() ||
+ identifier.parent is CommentReference) {
+ element = propertyResolver.setterResult.setter;
}
- if (element == null && identifier.inGetterContext()) {
- element =
- _lookUpGetter(null, enclosingType, identifier.name, identifier)
- .getter;
- }
- if (element == null) {
- element =
- _lookUpMethod(null, enclosingType, identifier.name, identifier)
- .getter;
- }
+ element ??= propertyResolver.getterResult.getter;
}
}
return element;
@@ -2114,3 +1947,98 @@
@override
void visitChildren(AstVisitor visitor) {}
}
+
+/// Helper for resolving properties (getters, setters, or methods).
+class _PropertyResolver {
+ final TypeProvider _typeProvider;
+ final InheritanceManager3 _inheritance;
+ final LibraryElement _definingLibrary;
+ final ExtensionMemberResolver _extensionResolver;
+
+ ResolutionResult getterResult = ResolutionResult.none;
+ ResolutionResult setterResult = ResolutionResult.none;
+
+ _PropertyResolver(
+ this._typeProvider,
+ this._inheritance,
+ this._definingLibrary,
+ this._extensionResolver,
+ );
+
+ /// Look up the getter and the setter with the given [name] in the [type].
+ /// Set results into [getterResult] or [setterResult] correspondingly.
+ /// Methods are considered getters for this purpose.
+ ///
+ /// The [target] is optional, and used to identify `super`.
+ ///
+ /// The [errorNode] is used to report the ambiguous extension issue.
+ void resolve(
+ Expression target,
+ DartType type,
+ String name,
+ Expression errorNode,
+ ) {
+ type = _resolveTypeParameter(type);
+
+ PropertyAccessorElement typeGetter;
+ PropertyAccessorElement typeSetter;
+ ExecutableElement typeMethod;
+
+ void lookupIn(InterfaceType type) {
+ var isSuper = target is SuperExpression;
+
+ typeGetter = type.lookUpInheritedGetter(name,
+ library: _definingLibrary, thisType: !isSuper);
+
+ typeSetter = type.lookUpInheritedSetter(name,
+ library: _definingLibrary, thisType: !isSuper);
+
+ typeMethod = type.lookUpInheritedMethod(name,
+ library: _definingLibrary, thisType: !isSuper);
+ }
+
+ if (type is InterfaceType) {
+ lookupIn(type);
+ } else if (type is FunctionType) {
+ lookupIn(_typeProvider.functionType);
+ } else {
+ return;
+ }
+
+ if (typeGetter != null) {
+ getterResult = ResolutionResult(property: typeGetter.variable);
+ } else if (typeMethod != null) {
+ getterResult = ResolutionResult(function: typeMethod);
+ }
+ if (typeSetter != null) {
+ setterResult = ResolutionResult(property: typeSetter.variable);
+ }
+
+ if (getterResult.isNone && setterResult.isNone) {
+ var result = _extensionResolver.findExtension(type, name, errorNode);
+ if (result.isSingle) {
+ if (result.getter != null) {
+ getterResult = result;
+ } else {
+ assert(result.setter != null);
+ setterResult = result;
+ }
+ } else if (result.isAmbiguous) {
+ getterResult = ResolutionResult.ambiguous;
+ setterResult = ResolutionResult.ambiguous;
+ }
+ }
+ }
+
+ ResolutionResult resolveOperator(
+ Expression target, DartType type, String name, Expression nameNode) {
+ resolve(target, type, name, nameNode);
+ return getterResult;
+ }
+
+ /// If the given [type] is a type parameter, replace it with its bound.
+ /// Otherwise, return the original type.
+ DartType _resolveTypeParameter(DartType type) {
+ return type?.resolveToBound(_typeProvider.objectType);
+ }
+}
diff --git a/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart b/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart
index 9a559a5..cfb7917 100644
--- a/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart
+++ b/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart
@@ -34,6 +34,10 @@
/// field.
bool _checkConstantUpdate2018;
+ /// A cached flag indicating whether uses of extension method features need to
+ /// be checked. Use [checkExtensionMethods] to access this field.
+ bool _checkExtensionMethods;
+
/// A cached flag indicating whether references to Future and Stream need to
/// be checked. Use [checkFutureAndStream] to access this field.
bool _checkFutureAndStream;
@@ -76,6 +80,10 @@
VersionRange get before_2_5_0 =>
new VersionRange(max: Version.parse('2.5.0'), includeMax: false);
+ /// Return a range covering every version up to, but not including, 2.6.0.
+ VersionRange get before_2_6_0 =>
+ new VersionRange(max: Version.parse('2.6.0'), includeMax: false);
+
/// Return `true` if references to the constant-update-2018 features need to
/// be checked.
bool get checkConstantUpdate2018 => _checkConstantUpdate2018 ??=
@@ -83,9 +91,8 @@
/// Return `true` if references to the extension method features need to
/// be checked.
- // TODO(brianwilkerson) Implement this as a version check when a version has
- // been selected.
- bool get checkExtensionMethods => true;
+ bool get checkExtensionMethods => _checkExtensionMethods ??=
+ !before_2_6_0.intersect(_versionConstraint).isEmpty;
/// Return `true` if references to Future and Stream need to be checked.
bool get checkFutureAndStream => _checkFutureAndStream ??=
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 2ac377b..00c787a 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -23610,6 +23610,7 @@
kind == idl.LinkedNodeKind.compilationUnit ||
kind == idl.LinkedNodeKind.constructorDeclaration ||
kind == idl.LinkedNodeKind.defaultFormalParameter ||
+ kind == idl.LinkedNodeKind.enumConstantDeclaration ||
kind == idl.LinkedNodeKind.enumDeclaration ||
kind == idl.LinkedNodeKind.extensionDeclaration ||
kind == idl.LinkedNodeKind.fieldFormalParameter ||
@@ -23631,6 +23632,7 @@
kind == idl.LinkedNodeKind.compilationUnit ||
kind == idl.LinkedNodeKind.constructorDeclaration ||
kind == idl.LinkedNodeKind.defaultFormalParameter ||
+ kind == idl.LinkedNodeKind.enumConstantDeclaration ||
kind == idl.LinkedNodeKind.enumDeclaration ||
kind == idl.LinkedNodeKind.extensionDeclaration ||
kind == idl.LinkedNodeKind.fieldFormalParameter ||
@@ -23654,6 +23656,7 @@
kind == idl.LinkedNodeKind.compilationUnit ||
kind == idl.LinkedNodeKind.constructorDeclaration ||
kind == idl.LinkedNodeKind.defaultFormalParameter ||
+ kind == idl.LinkedNodeKind.enumConstantDeclaration ||
kind == idl.LinkedNodeKind.enumDeclaration ||
kind == idl.LinkedNodeKind.extensionDeclaration ||
kind == idl.LinkedNodeKind.fieldFormalParameter ||
@@ -23675,6 +23678,7 @@
kind == idl.LinkedNodeKind.compilationUnit ||
kind == idl.LinkedNodeKind.constructorDeclaration ||
kind == idl.LinkedNodeKind.defaultFormalParameter ||
+ kind == idl.LinkedNodeKind.enumConstantDeclaration ||
kind == idl.LinkedNodeKind.enumDeclaration ||
kind == idl.LinkedNodeKind.extensionDeclaration ||
kind == idl.LinkedNodeKind.fieldFormalParameter ||
@@ -23944,9 +23948,13 @@
_variantField_10 = defaultFormalParameter_defaultValueCode;
UnlinkedInformativeDataBuilder.enumConstantDeclaration({
+ int codeLength,
+ int codeOffset,
int nameOffset,
List<String> documentationComment_tokens,
}) : _kind = idl.LinkedNodeKind.enumConstantDeclaration,
+ _variantField_2 = codeLength,
+ _variantField_3 = codeOffset,
_variantField_1 = nameOffset,
_variantField_4 = documentationComment_tokens;
@@ -24219,6 +24227,8 @@
} else if (kind == idl.LinkedNodeKind.enumConstantDeclaration) {
signature.addInt(this.kind == null ? 0 : this.kind.index);
signature.addInt(this.nameOffset ?? 0);
+ signature.addInt(this.codeLength ?? 0);
+ signature.addInt(this.codeOffset ?? 0);
if (this.documentationComment_tokens == null) {
signature.addInt(0);
} else {
@@ -24486,6 +24496,7 @@
kind == idl.LinkedNodeKind.compilationUnit ||
kind == idl.LinkedNodeKind.constructorDeclaration ||
kind == idl.LinkedNodeKind.defaultFormalParameter ||
+ kind == idl.LinkedNodeKind.enumConstantDeclaration ||
kind == idl.LinkedNodeKind.enumDeclaration ||
kind == idl.LinkedNodeKind.extensionDeclaration ||
kind == idl.LinkedNodeKind.fieldFormalParameter ||
@@ -24509,6 +24520,7 @@
kind == idl.LinkedNodeKind.compilationUnit ||
kind == idl.LinkedNodeKind.constructorDeclaration ||
kind == idl.LinkedNodeKind.defaultFormalParameter ||
+ kind == idl.LinkedNodeKind.enumConstantDeclaration ||
kind == idl.LinkedNodeKind.enumDeclaration ||
kind == idl.LinkedNodeKind.extensionDeclaration ||
kind == idl.LinkedNodeKind.fieldFormalParameter ||
@@ -24688,6 +24700,8 @@
defaultFormalParameter_defaultValueCode;
}
if (kind == idl.LinkedNodeKind.enumConstantDeclaration) {
+ if (codeLength != 0) _result["codeLength"] = codeLength;
+ if (codeOffset != 0) _result["codeOffset"] = codeOffset;
if (nameOffset != 0) _result["nameOffset"] = nameOffset;
if (documentationComment_tokens.isNotEmpty)
_result["documentationComment_tokens"] = documentationComment_tokens;
@@ -24863,6 +24877,8 @@
}
if (kind == idl.LinkedNodeKind.enumConstantDeclaration) {
return {
+ "codeLength": codeLength,
+ "codeOffset": codeOffset,
"nameOffset": nameOffset,
"documentationComment_tokens": documentationComment_tokens,
"kind": kind,
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 5e71b0e..0ada341 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -3645,6 +3645,7 @@
LinkedNodeKind.compilationUnit,
LinkedNodeKind.constructorDeclaration,
LinkedNodeKind.defaultFormalParameter,
+ LinkedNodeKind.enumConstantDeclaration,
LinkedNodeKind.enumDeclaration,
LinkedNodeKind.extensionDeclaration,
LinkedNodeKind.fieldFormalParameter,
@@ -3666,6 +3667,7 @@
LinkedNodeKind.compilationUnit,
LinkedNodeKind.constructorDeclaration,
LinkedNodeKind.defaultFormalParameter,
+ LinkedNodeKind.enumConstantDeclaration,
LinkedNodeKind.enumDeclaration,
LinkedNodeKind.extensionDeclaration,
LinkedNodeKind.fieldFormalParameter,
diff --git a/pkg/analyzer/lib/src/summary2/informative_data.dart b/pkg/analyzer/lib/src/summary2/informative_data.dart
index 1bf085d..c26e114 100644
--- a/pkg/analyzer/lib/src/summary2/informative_data.dart
+++ b/pkg/analyzer/lib/src/summary2/informative_data.dart
@@ -116,6 +116,8 @@
setData(
node,
UnlinkedInformativeDataBuilder.enumConstantDeclaration(
+ codeOffset: node.offset,
+ codeLength: node.length,
documentationComment_tokens: _nodeCommentTokens(node),
nameOffset: node.name.offset,
),
diff --git a/pkg/analyzer/lib/src/summary2/lazy_ast.dart b/pkg/analyzer/lib/src/summary2/lazy_ast.dart
index 97fd87a..1ab9a95 100644
--- a/pkg/analyzer/lib/src/summary2/lazy_ast.dart
+++ b/pkg/analyzer/lib/src/summary2/lazy_ast.dart
@@ -574,6 +574,28 @@
return node.getProperty(_key);
}
+ static int getCodeLength(
+ LinkedUnitContext context,
+ EnumConstantDeclaration node,
+ ) {
+ var lazy = get(node);
+ if (lazy != null) {
+ return context.getInformativeData(lazy.data)?.codeLength ?? 0;
+ }
+ return node.length;
+ }
+
+ static int getCodeOffset(
+ LinkedUnitContext context,
+ EnumConstantDeclaration node,
+ ) {
+ var lazy = get(node);
+ if (lazy != null) {
+ return context.getInformativeData(lazy.data)?.codeOffset ?? 0;
+ }
+ return node.offset;
+ }
+
static void readDocumentationComment(
LinkedUnitContext context,
EnumConstantDeclaration node,
diff --git a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
index 801f3b0..823fef5 100644
--- a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
@@ -148,6 +148,8 @@
}
} else if (node is ConstructorDeclaration) {
return LazyConstructorDeclaration.getCodeLength(this, node);
+ } else if (node is EnumConstantDeclaration) {
+ return LazyEnumConstantDeclaration.getCodeLength(this, node);
} else if (node is EnumDeclaration) {
return LazyEnumDeclaration.getCodeLength(this, node);
} else if (node is ExtensionDeclaration) {
@@ -181,6 +183,8 @@
return 0;
} else if (node is ConstructorDeclaration) {
return LazyConstructorDeclaration.getCodeOffset(this, node);
+ } else if (node is EnumConstantDeclaration) {
+ return LazyEnumConstantDeclaration.getCodeOffset(this, node);
} else if (node is EnumDeclaration) {
return LazyEnumDeclaration.getCodeOffset(this, node);
} else if (node is ExtensionDeclaration) {
diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
index 3187ffa..6392ba2 100644
--- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
@@ -145,6 +145,9 @@
LinkingNodeContext(node, functionScope);
node.parameters?.accept(this);
+ node.initializers.accept(
+ _SetGenericFunctionTypeIdVisitor(this),
+ );
scope = outerScope;
reference = outerReference;
@@ -153,6 +156,9 @@
@override
void visitDefaultFormalParameter(DefaultFormalParameter node) {
node.parameter.accept(this);
+ node.defaultValue?.accept(
+ _SetGenericFunctionTypeIdVisitor(this),
+ );
}
@override
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 0bc30b6..42e45f2 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -2544,6 +2544,16 @@
parseCompilationUnit('D? foo(X? x) { X? x1; X? x2 = x + bar(7); }');
}
+ void test_assignment_complex2() {
+ parseCompilationUnit(r'''
+main() {
+ A? a;
+ String? s = '';
+ a?..foo().length..x27 = s!..toString().length;
+}
+''');
+ }
+
void test_assignment_simple() {
parseCompilationUnit('D? foo(X? x) { X? x1; X? x2 = x; }');
}
@@ -2561,6 +2571,39 @@
expect(rhs.name, 'x2');
}
+ void test_cascade_withNullCheck_indexExpression() {
+ var unit = parseCompilationUnit('main() { a?..[27]; }');
+ FunctionDeclaration funct = unit.declarations[0];
+ BlockFunctionBody body = funct.functionExpression.body;
+ ExpressionStatement statement = body.block.statements[0];
+ CascadeExpression cascade = statement.expression;
+ IndexExpression indexExpression = cascade.cascadeSections[0];
+ expect(indexExpression.period.lexeme, '?..');
+ expect(indexExpression.toSource(), '?..[27]');
+ }
+
+ void test_cascade_withNullCheck_methodInvocation() {
+ var unit = parseCompilationUnit('main() { a?..foo(); }');
+ FunctionDeclaration funct = unit.declarations[0];
+ BlockFunctionBody body = funct.functionExpression.body;
+ ExpressionStatement statement = body.block.statements[0];
+ CascadeExpression cascade = statement.expression;
+ MethodInvocation invocation = cascade.cascadeSections[0];
+ expect(invocation.operator.lexeme, '?..');
+ expect(invocation.toSource(), '?..foo()');
+ }
+
+ void test_cascade_withNullCheck_propertyAccess() {
+ var unit = parseCompilationUnit('main() { a?..x27; }');
+ FunctionDeclaration funct = unit.declarations[0];
+ BlockFunctionBody body = funct.functionExpression.body;
+ ExpressionStatement statement = body.block.statements[0];
+ CascadeExpression cascade = statement.expression;
+ PropertyAccess propertyAccess = cascade.cascadeSections[0];
+ expect(propertyAccess.operator.lexeme, '?..');
+ expect(propertyAccess.toSource(), '?..x27');
+ }
+
void test_conditional() {
parseCompilationUnit('D? foo(X? x) { X ? 7 : y; }');
}
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_final_no_setter_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_final_no_setter_test.dart
index a5f6427..238174f 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_final_no_setter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_final_no_setter_test.dart
@@ -2,7 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/driver_resolution.dart';
@@ -43,3 +45,25 @@
]);
}
}
+
+@reflectiveTest
+class AssignmentToMethodWithExtensionMethodsTest
+ extends AssignmentToFinalNoSetterTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+ test_instance_undefined_hasGetter() async {
+ await assertErrorsInCode('''
+extension E on int {
+ int get foo => 0;
+}
+f() {
+ 0.foo = 1;
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 53, 3),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart
index 0a24297..912eefe 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart
@@ -2,7 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/driver_resolution.dart';
@@ -10,6 +12,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(AssignmentToMethodTest);
+ defineReflectiveTests(AssignmentToMethodWithExtensionMethodsTest);
});
}
@@ -27,3 +30,50 @@
]);
}
}
+
+@reflectiveTest
+class AssignmentToMethodWithExtensionMethodsTest
+ extends AssignmentToMethodTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+ test_instance_extendedHasMethod_extensionHasSetter() async {
+ await assertErrorsInCode('''
+class C {
+ void foo() {}
+}
+
+extension E on C {
+ void set foo(int _) {}
+}
+
+f(C c) {
+ c.foo = 0;
+}
+''', [
+ error(StaticWarningCode.ASSIGNMENT_TO_METHOD, 87, 5),
+ error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 95, 1),
+ ]);
+ }
+
+ test_this_extendedHasMethod_extensionHasSetter() async {
+ await assertErrorsInCode('''
+class C {
+ void foo() {}
+}
+
+extension E on C {
+ void set foo(int _) {}
+
+ f() {
+ this.foo = 0;
+ }
+}
+''', [
+ error(StaticWarningCode.ASSIGNMENT_TO_METHOD, 86, 8),
+ error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 97, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/sdk_version_extension_methods_test.dart b/pkg/analyzer/test/src/diagnostics/sdk_version_extension_methods_test.dart
index 9afa451..e10751d 100644
--- a/pkg/analyzer/test/src/diagnostics/sdk_version_extension_methods_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/sdk_version_extension_methods_test.dart
@@ -21,7 +21,6 @@
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
..enabledExperiments = [EnableString.extension_methods];
- @failingTest
test_extension_equals() async {
await verifyVersion('2.6.0', '''
extension E on int {}
@@ -36,7 +35,6 @@
]);
}
- @failingTest
test_extensionOverride_equals() async {
await verifyVersion('2.6.0', '''
extension E on int {
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_extension_getter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_extension_getter_test.dart
index dc99786..1917d08 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_extension_getter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_extension_getter_test.dart
@@ -22,7 +22,7 @@
..contextFeatures = new FeatureSet.forTesting(
sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
- test_instance_defined() async {
+ test_override_defined() async {
await assertNoErrorsInCode('''
extension E on String {
int get g => 0;
@@ -33,7 +33,7 @@
''');
}
- test_instance_withoutSetter() async {
+ test_override_undefined() async {
await assertErrorsInCode('''
extension E on String {}
f() {
@@ -44,7 +44,7 @@
]);
}
- test_instance_withSetter() async {
+ test_override_undefined_hasSetter() async {
await assertErrorsInCode('''
extension E on String {
void set s(int x) {}
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_extension_setter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_extension_setter_test.dart
index 9c38d0c..f6c2f65 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_extension_setter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_extension_setter_test.dart
@@ -22,36 +22,49 @@
..contextFeatures = new FeatureSet.forTesting(
sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
- test_instance_defined() async {
+ test_override_defined() async {
await assertNoErrorsInCode('''
-extension E on String {
- void set s(int x) {}
+extension E on int {
+ void set foo(int _) {}
}
f() {
- E('a').s = 1;
+ E(0).foo = 1;
}
''');
}
- test_instance_undefined() async {
+ test_override_undefined() async {
await assertErrorsInCode('''
-extension E on String {}
+extension E on int {}
f() {
- E('a').s = 1;
+ E(0).foo = 1;
}
''', [
- error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 40, 1),
+ error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 35, 3),
+ ]);
+ }
+
+ test_override_undefined_hasGetter() async {
+ await assertErrorsInCode('''
+extension E on int {
+ int get foo => 0;
+}
+f() {
+ E(0).foo = 1;
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 56, 3),
]);
}
test_static_undefined() async {
await assertErrorsInCode('''
-extension E on Object {}
+extension E on int {}
void f() {
- E.s = 3;
+ E.foo = 3;
}
''', [
- error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 40, 1),
+ error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 37, 3),
]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
index d56ebb7..5f3050e 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
@@ -125,6 +125,37 @@
..contextFeatures = new FeatureSet.forTesting(
sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+ test_instance_extendedHasSetter_extensionHasGetter() async {
+ await assertErrorsInCode('''
+class C {
+ void set foo(int _) {}
+}
+
+extension E on C {
+ int get foo => 0;
+
+ f() {
+ this.foo;
+ }
+}
+''', [
+ error(StaticTypeWarningCode.UNDEFINED_GETTER, 95, 3),
+ ]);
+ }
+
+ test_instance_undefined_hasSetter() async {
+ await assertErrorsInCode('''
+extension E on int {
+ void set foo(int _) {}
+}
+f() {
+ 0.foo;
+}
+''', [
+ error(StaticTypeWarningCode.UNDEFINED_GETTER, 58, 3),
+ ]);
+ }
+
test_instance_withInference() async {
await assertErrorsInCode(r'''
extension E on int {}
@@ -147,4 +178,22 @@
error(StaticTypeWarningCode.UNDEFINED_GETTER, 46, 1),
]);
}
+
+ test_this_extendedHasSetter_extensionHasGetter() async {
+ await assertErrorsInCode('''
+class C {
+ void set foo(int _) {}
+}
+
+extension E on C {
+ int get foo => 0;
+}
+
+f(C c) {
+ c.foo;
+}
+''', [
+ error(StaticTypeWarningCode.UNDEFINED_GETTER, 93, 3),
+ ]);
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/unused_import_test.dart b/pkg/analyzer/test/src/diagnostics/unused_import_test.dart
index 0a78364..19a7be4 100644
--- a/pkg/analyzer/test/src/diagnostics/unused_import_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unused_import_test.dart
@@ -328,14 +328,14 @@
test_instance_setter() async {
newFile('/test/lib/lib1.dart', content: r'''
extension E on String {
- void set length(int i) {}
+ void set foo(int i) {}
}
''');
await assertNoErrorsInCode('''
import 'lib1.dart';
f() {
- 'abc'.length = 2;
+ 'abc'.foo = 2;
}
''');
}
diff --git a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
index befdee3..2d07417 100644
--- a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
+++ b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
@@ -184,6 +184,16 @@
assertCanBeConst("A(", false);
}
+ void test_false_typeParameter() async {
+ await resolve('''
+class A<T> {
+ const A();
+}
+f<U>() => A<U>();
+''');
+ assertCanBeConst("A<U>", false);
+ }
+
void test_true_constConstructorArg() async {
await resolve('''
class A {
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 38ce11b..e68375d 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -2075,6 +2075,28 @@
withConstElements: false);
}
+ test_codeRange_enum() async {
+ var library = await checkLibrary('''
+enum E {
+ aaa, bbb, ccc
+}
+''');
+ checkElementText(
+ library,
+ r'''
+enum E/*codeOffset=0, codeLength=26*/ {
+ synthetic final int index/*codeOffset=null, codeLength=null*/;
+ synthetic static const List<E> values/*codeOffset=null, codeLength=null*/;
+ static const E aaa/*codeOffset=11, codeLength=3*/;
+ static const E bbb/*codeOffset=16, codeLength=3*/;
+ static const E ccc/*codeOffset=21, codeLength=3*/;
+ String toString/*codeOffset=null, codeLength=null*/() {}
+}
+''',
+ withCodeRanges: true,
+ withConstElements: false);
+ }
+
test_codeRange_extensions() async {
featureSet = enableExtensionMethods;
var library = await checkLibrary('''
@@ -4617,6 +4639,31 @@
''');
}
+ test_constructor_initializers_genericFunctionType() async {
+ var library = await checkLibrary('''
+class A<T> {
+ const A();
+}
+class B {
+ const B(dynamic x);
+ const B.f()
+ : this(A<Function()>());
+}
+''');
+ if (isAstBasedSummary) {
+ checkElementText(library, r'''
+class A<T> {
+ const A();
+}
+class B {
+ const B(dynamic x);
+ const B.f() = B : this(
+ A/*location: test.dart;A*/<Function()>());
+}
+''');
+ }
+ }
+
test_constructor_initializers_superInvocation_named() async {
var library = await checkLibrary('''
class A {
@@ -5261,6 +5308,28 @@
''');
}
+ test_defaultValue_genericFunctionType() async {
+ var library = await checkLibrary('''
+class A<T> {
+ const A();
+}
+class B {
+ void foo({a: const A<Function()>()}) {}
+}
+''');
+ if (isAstBasedSummary) {
+ checkElementText(library, r'''
+class A<T> {
+ const A();
+}
+class B {
+ void foo({dynamic a: const
+ A/*location: test.dart;A*/<Function()>()}) {}
+}
+''');
+ }
+ }
+
test_defaultValue_refersToExtension_method_inside() async {
featureSet = enableExtensionMethods;
var library = await checkLibrary('''
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index bf7c912..e9bb860 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -1479,7 +1479,9 @@
@override
void endBinaryExpression(Token token) {
debugEvent("BinaryExpression");
- if (optional(".", token) || optional("..", token)) {
+ if (optional(".", token) ||
+ optional("..", token) ||
+ optional("?..", token)) {
return doDotOrCascadeExpression(token);
}
if (optional("&&", token) || optional("||", token)) {
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index a296c652..9ad4e92 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -4285,7 +4285,7 @@
Token parseCascadeExpression(Token token) {
Token cascadeOperator = token = token.next;
- assert(optional('..', cascadeOperator));
+ assert(optional('..', cascadeOperator) || optional('?..', cascadeOperator));
listener.beginCascade(cascadeOperator);
if (optional('[', token.next)) {
token = parseArgumentOrIndexStar(token, noTypeParamOrArg);
diff --git a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
index 50fedf3..e34362d 100644
--- a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
+++ b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
@@ -877,16 +877,22 @@
}
int tokenizeQuestion(int next) {
- // ? ?. ?? ??=
+ // ? ?. ?.. ?? ??=
next = advance();
if (identical(next, $QUESTION)) {
return select(
$EQ, TokenType.QUESTION_QUESTION_EQ, TokenType.QUESTION_QUESTION);
} else if (identical(next, $PERIOD)) {
next = advance();
- if (_enableNonNullable && identical($OPEN_SQUARE_BRACKET, next)) {
- appendBeginGroup(TokenType.QUESTION_PERIOD_OPEN_SQUARE_BRACKET);
- return advance();
+ if (_enableNonNullable) {
+ if (identical($PERIOD, next)) {
+ appendPrecedenceToken(TokenType.QUESTION_PERIOD_PERIOD);
+ return advance();
+ }
+ if (identical($OPEN_SQUARE_BRACKET, next)) {
+ appendBeginGroup(TokenType.QUESTION_PERIOD_OPEN_SQUARE_BRACKET);
+ return advance();
+ }
}
appendPrecedenceToken(TokenType.QUESTION_PERIOD);
return next;
diff --git a/pkg/front_end/lib/src/fasta/scanner/token_constants.dart b/pkg/front_end/lib/src/fasta/scanner/token_constants.dart
index e468145..f8cc645 100644
--- a/pkg/front_end/lib/src/fasta/scanner/token_constants.dart
+++ b/pkg/front_end/lib/src/fasta/scanner/token_constants.dart
@@ -90,3 +90,5 @@
const int PERIOD_PERIOD_PERIOD_QUESTION_TOKEN = GT_GT_GT_TOKEN + 1;
const int GT_GT_GT_EQ_TOKEN = PERIOD_PERIOD_PERIOD_QUESTION_TOKEN + 1;
const int QUESTION_PERIOD_OPEN_SQUARE_BRACKET_TOKEN = GT_GT_GT_EQ_TOKEN + 1;
+const int QUESTION_PERIOD_PERIOD_TOKEN =
+ QUESTION_PERIOD_OPEN_SQUARE_BRACKET_TOKEN + 1;
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
index dab1b69..3912f27 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
@@ -259,12 +259,6 @@
// identical(). If P and Q are equal but not identical, recursing through
// the types will give the proper result.
if (identical(subtype, supertype)) return true;
- // Any type `P` is a subtype match for `dynamic`, `Object`, or `void` under
- // no constraints.
- if (_isTop(supertype)) return true;
- // `Null` is a subtype match for any type `Q` under no constraints.
- // Note that nullable types will change this.
- if (_isNull(subtype)) return true;
// Handle FutureOr<T> union type.
if (subtype is InterfaceType &&
@@ -302,11 +296,34 @@
// - And `P` is a subtype match for `Q` with respect to `L` under
// constraints `C`
DartType supertypeArg = supertype.typeArguments[0];
- InterfaceType supertypeFuture = futureType(supertypeArg);
- return trySubtypeMatch(subtype, supertypeFuture) ||
- _isSubtypeMatch(subtype, supertypeArg);
+ DartType supertypeFuture = futureType(supertypeArg);
+
+ // The outcome of both trySubtypeMatch and _isSubtypeMatch is includes the
+ // returned boolean value and the added constraints to _protoConstraints.
+ // Here we need to match 'subtype' against both possibilities of the
+ // FutureOr<X> which is 'supertype,' that is, we need to match 'subtype'
+ // against Future<X> and X. However, if the first matching against
+ // Future<X> finds any new constraints and adds them to _protoConstraints,
+ // we should prefer them over the constraints possibly found while
+ // matching against X. Note that if matching against Future<X> returned
+ // true, but didn't find any new constraints, then matching against X
+ // should still be done and the new constraints should still be added to
+ // _protoConstraints.
+ int oldProtoConstraintsLength = _protoConstraints.length;
+ bool matchesFuture = trySubtypeMatch(subtype, supertypeFuture);
+ bool matchesArg = oldProtoConstraintsLength != _protoConstraints.length
+ ? false
+ : _isSubtypeMatch(subtype, supertypeArg);
+ return matchesFuture || matchesArg;
}
+ // Any type `P` is a subtype match for `dynamic`, `Object`, or `void` under
+ // no constraints.
+ if (_isTop(supertype)) return true;
+ // `Null` is a subtype match for any type `Q` under no constraints.
+ // Note that nullable types will change this.
+ if (_isNull(subtype)) return true;
+
// A type variable `T` not in `L` with bound `P` is a subtype match for the
// same type variable `T` with bound `Q` with respect to `L` under
// constraints `C`:
diff --git a/pkg/front_end/lib/src/scanner/token.dart b/pkg/front_end/lib/src/scanner/token.dart
index f7429c3..d16d2d4 100644
--- a/pkg/front_end/lib/src/scanner/token.dart
+++ b/pkg/front_end/lib/src/scanner/token.dart
@@ -1450,6 +1450,12 @@
SELECTOR_PRECEDENCE,
QUESTION_PERIOD_OPEN_SQUARE_BRACKET_TOKEN);
+ static const TokenType QUESTION_PERIOD_PERIOD = const TokenType(
+ '?..',
+ 'QUESTION_PERIOD_PERIOD',
+ CASCADE_PRECEDENCE,
+ QUESTION_PERIOD_PERIOD_TOKEN);
+
static const TokenType AS = Keyword.AS;
static const TokenType IS = Keyword.IS;
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 056b0f5..f27e950 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -97,6 +97,7 @@
also
alternating
alternative
+alternatives
alternatively
although
always
@@ -1984,6 +1985,7 @@
positions
positive
positives
+possibilities
possible
possibly
post
diff --git a/pkg/front_end/test/static_types/data/constraint_gatherer_for_future_or.dart b/pkg/front_end/test/static_types/data/constraint_gatherer_for_future_or.dart
new file mode 100644
index 0000000..8e74122
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/constraint_gatherer_for_future_or.dart
@@ -0,0 +1,74 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// The test checks the gathering of the constraints during type inference in
+// case the supertype of the match is a FutureOr<X> or one of its alternatives
+// (either Future<X> or X).
+
+import 'dart:async';
+
+// -----------------------------------------------------------------------------
+
+// Gathering constraints for S from comparison Null <: FutureOr<S>.
+void func1() {
+ void foo<S>(FutureOr<S> bar) {}
+
+ /*invoke: void*/ foo/*<Null>*/(/*Null*/ null);
+}
+
+// -----------------------------------------------------------------------------
+
+// Gathering constraints for S from comparison Null <: Future<S>.
+void func2() {
+ void foo<S>(Future<S> bar) {}
+
+ /*invoke: void*/ foo/*<dynamic>*/(/*Null*/ null);
+}
+
+// -----------------------------------------------------------------------------
+
+// Gathering constraints for S from comparison Null <: S.
+void func3() {
+ void foo<S>(S bar) {}
+
+ /*invoke: void*/ foo/*<Null>*/(/*Null*/ null);
+}
+
+// -----------------------------------------------------------------------------
+
+void func4() {
+ void foo<S>(FutureOr<FutureOr<S>> bar) {}
+
+ /*invoke: void*/ foo/*<Null>*/(/*Null*/ null);
+}
+
+// -----------------------------------------------------------------------------
+
+// Gathering constraints for S from comparison int <: FutureOr<S>.
+void func5() {
+ void foo<S>(FutureOr<S> bar) {}
+
+ /*invoke: void*/ foo/*<int>*/(/*int*/ 42);
+}
+
+// -----------------------------------------------------------------------------
+
+// Gathering constraints for S from comparison int <: S.
+void func6() {
+ void foo<S>(S bar) {}
+
+ /*invoke: void*/ foo/*<int>*/(/*int*/ 42);
+}
+
+// -----------------------------------------------------------------------------
+
+void func7() {
+ void foo<S>(FutureOr<FutureOr<S>> bar) {}
+
+ /*invoke: void*/ foo/*<int>*/(/*int*/ 42);
+}
+
+// -----------------------------------------------------------------------------
+
+main() {}
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 5a73336..f802599 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -274,15 +274,17 @@
@override
DecoratedType visitAssignmentExpression(AssignmentExpression node) {
_CompoundOperatorInfo compoundOperatorInfo;
+ bool isQuestionAssign = false;
if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
- _unimplemented(node, 'Assignment with operator ??=');
+ isQuestionAssign = true;
} else if (node.operator.type != TokenType.EQ) {
compoundOperatorInfo = _CompoundOperatorInfo(
node.staticElement, node.operator.offset, node.staticType);
}
var expressionType = _handleAssignment(node.rightHandSide,
destinationExpression: node.leftHandSide,
- compoundOperatorInfo: compoundOperatorInfo);
+ compoundOperatorInfo: compoundOperatorInfo,
+ questionAssignNode: isQuestionAssign ? node : null);
var conditionalNode = _conditionalNodes[node.leftHandSide];
if (conditionalNode != null) {
expressionType = expressionType.withNode(
@@ -369,13 +371,17 @@
(callee.enclosingElement as ClassElement)
.typeParameters
.isNotEmpty)); // TODO(paulberry)
- assert(callee != null); // TODO(paulberry)
- var calleeType = getOrComputeElementType(callee);
- // TODO(paulberry): substitute if necessary
- assert(calleeType.positionalParameters.length > 0); // TODO(paulberry)
- _handleAssignment(node.rightOperand,
- destinationType: calleeType.positionalParameters[0]);
- return _fixNumericTypes(calleeType.returnType, node.staticType);
+ if (callee == null) {
+ node.rightOperand.accept(this);
+ return _dynamicType;
+ } else {
+ var calleeType = getOrComputeElementType(callee);
+ // TODO(paulberry): substitute if necessary
+ assert(calleeType.positionalParameters.length > 0); // TODO(paulberry)
+ _handleAssignment(node.rightOperand,
+ destinationType: calleeType.positionalParameters[0]);
+ return _fixNumericTypes(calleeType.returnType, node.staticType);
+ }
} else {
// TODO(paulberry)
node.leftOperand.accept(this);
@@ -662,9 +668,8 @@
@override
DecoratedType visitFunctionExpressionInvocation(
FunctionExpressionInvocation node) {
- DecoratedType calleeType = node.function.accept(this);
- return _handleInvocationArguments(node, node.argumentList.arguments,
- node.typeArguments, node.typeArgumentTypes, calleeType, null);
+ return _handleFunctionExpressionInvocation(node, node.function,
+ node.argumentList, node.typeArguments, node.typeArgumentTypes);
}
@override
@@ -901,7 +906,13 @@
// Dynamic dispatch. The return type is `dynamic`.
// TODO(paulberry): would it be better to assume a return type of `Never`
// so that we don't unnecessarily propagate nullabilities everywhere?
+ node.typeArguments?.accept(this);
+ node.argumentList.accept(this);
return _dynamicType;
+ } else if (callee is VariableElement) {
+ // Function expression invocation that looks like a method invocation.
+ return _handleFunctionExpressionInvocation(node, node.methodName,
+ node.argumentList, node.typeArguments, node.typeArgumentTypes);
}
var calleeType = getOrComputeElementType(callee, targetType: targetType);
if (callee is PropertyAccessorElement) {
@@ -1184,7 +1195,7 @@
@override
DecoratedType visitSuperExpression(SuperExpression node) {
- return DecoratedType(node.staticType, _graph.never);
+ return _handleThisOrSuper(node);
}
@override
@@ -1214,7 +1225,7 @@
@override
DecoratedType visitThisExpression(ThisExpression node) {
- return DecoratedType(node.staticType, _graph.never);
+ return _handleThisOrSuper(node);
}
@override
@@ -1535,6 +1546,7 @@
{DecoratedType destinationType,
Expression destinationExpression,
_CompoundOperatorInfo compoundOperatorInfo,
+ Expression questionAssignNode,
bool canInsertChecks = true}) {
assert(
(destinationExpression == null) != (destinationType == null),
@@ -1554,47 +1566,64 @@
destinationType = destinationExpression.accept(this);
}
}
- var sourceType = expression.accept(this);
- if (sourceType == null) {
- throw StateError('No type computed for ${expression.runtimeType} '
- '(${expression.toSource()}) offset=${expression.offset}');
+ if (questionAssignNode != null) {
+ _guards.add(destinationType.node);
}
- ExpressionChecks expressionChecks;
- if (canInsertChecks && !sourceType.type.isDynamic) {
- expressionChecks = ExpressionChecks(expression.end);
- _variables.recordExpressionChecks(source, expression, expressionChecks);
- }
- if (compoundOperatorInfo != null) {
- var compoundOperatorMethod = compoundOperatorInfo.method;
- if (compoundOperatorMethod != null) {
- _checkAssignment(
- CompoundAssignmentOrigin(source, compoundOperatorInfo.offset),
- source: destinationType,
- destination: _notNullType,
- hard:
- _postDominatedLocals.isReferenceInScope(destinationExpression));
- DecoratedType compoundOperatorType =
- getOrComputeElementType(compoundOperatorMethod);
- assert(compoundOperatorType.positionalParameters.length > 0);
+ DecoratedType sourceType;
+ try {
+ sourceType = expression.accept(this);
+ if (sourceType == null) {
+ throw StateError('No type computed for ${expression.runtimeType} '
+ '(${expression.toSource()}) offset=${expression.offset}');
+ }
+ ExpressionChecks expressionChecks;
+ if (canInsertChecks && !sourceType.type.isDynamic) {
+ expressionChecks = ExpressionChecks(expression.end);
+ _variables.recordExpressionChecks(source, expression, expressionChecks);
+ }
+ if (compoundOperatorInfo != null) {
+ var compoundOperatorMethod = compoundOperatorInfo.method;
+ if (compoundOperatorMethod != null) {
+ _checkAssignment(
+ CompoundAssignmentOrigin(source, compoundOperatorInfo.offset),
+ source: destinationType,
+ destination: _notNullType,
+ hard: _postDominatedLocals
+ .isReferenceInScope(destinationExpression));
+ DecoratedType compoundOperatorType =
+ getOrComputeElementType(compoundOperatorMethod);
+ assert(compoundOperatorType.positionalParameters.length > 0);
+ _checkAssignment(expressionChecks,
+ source: sourceType,
+ destination: compoundOperatorType.positionalParameters[0],
+ hard: _postDominatedLocals.isReferenceInScope(expression));
+ sourceType = _fixNumericTypes(compoundOperatorType.returnType,
+ compoundOperatorInfo.undecoratedType);
+ _checkAssignment(
+ CompoundAssignmentOrigin(source, compoundOperatorInfo.offset),
+ source: sourceType,
+ destination: destinationType,
+ hard: false);
+ } else {
+ sourceType = _dynamicType;
+ }
+ } else {
_checkAssignment(expressionChecks,
source: sourceType,
- destination: compoundOperatorType.positionalParameters[0],
- hard: _postDominatedLocals.isReferenceInScope(expression));
- sourceType = _fixNumericTypes(compoundOperatorType.returnType,
- compoundOperatorInfo.undecoratedType);
- _checkAssignment(
- CompoundAssignmentOrigin(source, compoundOperatorInfo.offset),
- source: sourceType,
destination: destinationType,
- hard: false);
- } else {
- sourceType = _dynamicType;
+ hard: _postDominatedLocals.isReferenceInScope(expression));
}
- } else {
- _checkAssignment(expressionChecks,
- source: sourceType,
- destination: destinationType,
- hard: _postDominatedLocals.isReferenceInScope(expression));
+ if (questionAssignNode != null) {
+ // a ??= b is only nullable if both a and b are nullable.
+ sourceType = destinationType.withNode(_nullabilityNodeForGLB(
+ questionAssignNode, sourceType.node, destinationType.node));
+ _variables.recordDecoratedExpressionType(
+ questionAssignNode, sourceType);
+ }
+ } finally {
+ if (questionAssignNode != null) {
+ _guards.removeLast();
+ }
}
if (destinationExpression != null) {
_postDominatedLocals.removeReferenceFromAllScopes(destinationExpression);
@@ -1647,9 +1676,9 @@
assert(_currentFunctionType == null);
metadata.accept(this);
returnType?.accept(this);
+ _createFlowAnalysis(body);
parameters?.accept(this);
_currentFunctionType = _variables.decoratedElementType(declaredElement);
- _createFlowAnalysis(body);
_addParametersToFlowAnalysis(parameters);
// Push a scope of post-dominated declarations on the stack.
_postDominatedLocals.pushScope(elements: declaredElement.parameters);
@@ -1780,6 +1809,24 @@
});
}
+ DecoratedType _handleFunctionExpressionInvocation(
+ AstNode node,
+ Expression function,
+ ArgumentList argumentList,
+ TypeArgumentList typeArguments,
+ List<DartType> typeArgumentTypes) {
+ DecoratedType calleeType = _checkExpressionNotNull(function);
+ if (calleeType.type is FunctionType) {
+ return _handleInvocationArguments(node, argumentList.arguments,
+ typeArguments, typeArgumentTypes, calleeType, null);
+ } else {
+ // Invocation of type `dynamic` or `Function`.
+ typeArguments?.accept(this);
+ argumentList.accept(this);
+ return _dynamicType;
+ }
+ }
+
/// Creates the necessary constraint(s) for an [argumentList] when invoking an
/// executable element whose type is [calleeType].
///
@@ -1913,6 +1960,19 @@
}
}
+ DecoratedType _handleThisOrSuper(Expression node) {
+ var type = node.staticType as InterfaceType;
+ // Instantiate the type, and any type arguments, with `_graph.never`,
+ // because the type of `this` is always `ClassName<Param, Param, ...>` with
+ // no `?`s. (Even if some of the type parameters are allowed to be
+ // instantiated with nullable types at runtime, a reference to `this` can't
+ // be migrated in such a way that forces them to be nullable).
+ return DecoratedType(type, _graph.never,
+ typeArguments: type.typeArguments
+ .map((t) => DecoratedType(t, _graph.never))
+ .toList());
+ }
+
bool _isConditionalExpression(Expression expression) {
Token token;
if (expression is MethodInvocation) {
@@ -2037,6 +2097,35 @@
{@required DecoratedType source, @required DecoratedType destination}) {
var sourceType = source.type;
var destinationType = destination.type;
+ if (!_typeSystem.isSubtypeOf(sourceType, destinationType)) {
+ // Not a proper upcast assignment. It is either an implicit downcast or
+ // some illegal code. It's handled on a "best effort" basis.
+ if (destinationType is TypeParameterType &&
+ sourceType is! TypeParameterType) {
+ // Assume an assignment to the type parameter's bound.
+ _checkAssignment(origin,
+ source: source,
+ destination:
+ _getTypeParameterTypeBound(destination).withNode(_graph.always),
+ hard: false);
+ return;
+ }
+ if (sourceType is InterfaceType && destinationType is InterfaceType) {
+ if (_typeSystem.isSubtypeOf(destinationType, sourceType)) {
+ var rewrittenDestination = _decoratedClassHierarchy.asInstanceOf(
+ destination, sourceType.element);
+ assert(rewrittenDestination.typeArguments.length ==
+ source.typeArguments.length);
+ for (int i = 0; i < rewrittenDestination.typeArguments.length; i++) {
+ _checkAssignment(origin,
+ source: source.typeArguments[i],
+ destination: rewrittenDestination.typeArguments[i],
+ hard: false);
+ }
+ }
+ }
+ return;
+ }
if (destinationType.isDartAsyncFutureOr) {
// (From the subtyping spec):
// if T1 is FutureOr<S1> then T0 <: T1 iff any of the following hold:
@@ -2059,8 +2148,9 @@
else if (sourceType is TypeParameterType) {
throw UnimplementedError('TODO(paulberry)');
} else {
- // Not a subtype; this must be a downcast.
- throw UnimplementedError('TODO(paulberry)');
+ // Not a subtype. This should never happen, since we handle the
+ // implicit downcast case above.
+ assert(false, 'not a subtype');
}
}
if (sourceType.isBottom || sourceType.isDartCoreNull) {
@@ -2083,44 +2173,17 @@
hard: false);
return;
}
- } else if (destinationType is TypeParameterType) {
- // Effectively this is a downcast assignment from the source type to the
- // type parameter's bound.
- _checkAssignment(origin,
- source: source,
- destination:
- _getTypeParameterTypeBound(destination).withNode(_graph.always),
- hard: false);
} else if (sourceType is InterfaceType &&
destinationType is InterfaceType) {
- if (_typeSystem.isSubtypeOf(sourceType, destinationType)) {
- // Ordinary (upcast) assignment. No cast necessary.
- var rewrittenSource = _decoratedClassHierarchy.asInstanceOf(
- source, destinationType.element);
- assert(rewrittenSource.typeArguments.length ==
- destination.typeArguments.length);
- for (int i = 0; i < rewrittenSource.typeArguments.length; i++) {
- _checkAssignment(origin,
- source: rewrittenSource.typeArguments[i],
- destination: destination.typeArguments[i],
- hard: false);
- }
- } else if (_typeSystem.isSubtypeOf(destinationType, sourceType)) {
- // Implicit downcast assignment.
- // TODO(paulberry): the migration tool should insert a cast.
- var rewrittenDestination = _decoratedClassHierarchy.asInstanceOf(
- destination, sourceType.element);
- assert(rewrittenDestination.typeArguments.length ==
- source.typeArguments.length);
- for (int i = 0; i < rewrittenDestination.typeArguments.length; i++) {
- _checkAssignment(origin,
- source: source.typeArguments[i],
- destination: rewrittenDestination.typeArguments[i],
- hard: false);
- }
- } else {
- // This should never arise for correct code; if it does arise, recover
- // from the error by just not creating any additional edges.
+ var rewrittenSource = _decoratedClassHierarchy.asInstanceOf(
+ source, destinationType.element);
+ assert(rewrittenSource.typeArguments.length ==
+ destination.typeArguments.length);
+ for (int i = 0; i < rewrittenSource.typeArguments.length; i++) {
+ _checkAssignment(origin,
+ source: rewrittenSource.typeArguments[i],
+ destination: destination.typeArguments[i],
+ hard: false);
}
} else if (sourceType is FunctionType && destinationType is FunctionType) {
_checkAssignment(origin,
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index 079cf85..1db66dc 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -375,6 +375,16 @@
return variables.decoratedExpressionType(findNode.expression(text));
}
+ test_already_migrated_field() async {
+ await analyze('''
+double f() => double.NAN;
+''');
+ var nanElement = typeProvider.doubleType.element.getField('NAN');
+ assertEdge(variables.decoratedElementType(nanElement).node,
+ decoratedTypeAnnotation('double f').node,
+ hard: false);
+ }
+
test_as_dynamic() async {
await analyze('''
void f(Object o) {
@@ -401,16 +411,6 @@
assertEdge(decoratedTypeAnnotation('int').node, never, hard: false);
}
- test_already_migrated_field() async {
- await analyze('''
-double f() => double.NAN;
-''');
- var nanElement = typeProvider.doubleType.element.getField('NAN');
- assertEdge(variables.decoratedElementType(nanElement).node,
- decoratedTypeAnnotation('double f').node,
- hard: false);
- }
-
test_assert_demonstrates_non_null_intent() async {
await analyze('''
void f(int i) {
@@ -747,6 +747,48 @@
hard: true);
}
+ test_assignmentExpression_nullAware_complex_contravariant() async {
+ await analyze('''
+void Function(int) f(void Function(int) x, void Function(int) y) => x ??= y;
+''');
+ var xNullable =
+ decoratedGenericFunctionTypeAnnotation('void Function(int) x').node;
+ var xParamNullable = decoratedTypeAnnotation('int) x').node;
+ var yParamNullable = decoratedTypeAnnotation('int) y').node;
+ var returnParamNullable = decoratedTypeAnnotation('int) f').node;
+ assertEdge(xParamNullable, yParamNullable,
+ hard: false, guards: [xNullable]);
+ assertEdge(returnParamNullable, xParamNullable, hard: false);
+ }
+
+ test_assignmentExpression_nullAware_complex_covariant() async {
+ await analyze('''
+List<int> f(List<int> x, List<int> y) => x ??= y;
+''');
+ var xNullable = decoratedTypeAnnotation('List<int> x').node;
+ var xElementNullable = decoratedTypeAnnotation('int> x').node;
+ var yElementNullable = decoratedTypeAnnotation('int> y').node;
+ var returnElementNullable = decoratedTypeAnnotation('int> f').node;
+ assertEdge(yElementNullable, xElementNullable,
+ hard: false, guards: [xNullable]);
+ assertEdge(xElementNullable, returnElementNullable, hard: false);
+ }
+
+ test_assignmentExpression_nullAware_simple() async {
+ await analyze('''
+int f(int x, int y) => (x ??= y);
+''');
+ var yNullable = decoratedTypeAnnotation('int y').node;
+ var xNullable = decoratedTypeAnnotation('int x').node;
+ var returnNullable = decoratedTypeAnnotation('int f').node;
+ var glbNode = decoratedExpressionType('(x ??= y)').node;
+ assertEdge(yNullable, xNullable, hard: true, guards: [xNullable]);
+ assertEdge(yNullable, glbNode, hard: false, guards: [xNullable]);
+ assertEdge(glbNode, xNullable, hard: false);
+ assertEdge(glbNode, yNullable, hard: false);
+ assertEdge(glbNode, returnNullable, hard: false);
+ }
+
test_assignmentExpression_operands() async {
await analyze('''
void f(int i, int j) {
@@ -939,6 +981,18 @@
assertNoUpstreamNullability(decoratedTypeAnnotation('int f').node);
}
+ test_binaryExpression_left_dynamic() async {
+ await analyze('''
+Object f(dynamic x, int y) => x + g(y);
+int g(int z) => z;
+''');
+ assertEdge(decoratedTypeAnnotation('int y').node,
+ decoratedTypeAnnotation('int z').node,
+ hard: true);
+ assertNoEdge(decoratedTypeAnnotation('int g').node, anyNode);
+ assertEdge(always, decoratedTypeAnnotation('Object f').node, hard: false);
+ }
+
test_binaryExpression_lt_result_not_null() async {
await analyze('''
bool f(int i, int j) => i < j;
@@ -1088,6 +1142,20 @@
assertEdge(right, expression, guards: [left], hard: false);
}
+ test_binaryExpression_right_dynamic() async {
+ await analyze('''
+class C {
+ C operator+(C other) => other;
+}
+C f(C x, dynamic y) => x + y;
+''');
+ assertNullCheck(checkExpression('x +'),
+ assertEdge(decoratedTypeAnnotation('C x').node, never, hard: true));
+ assertEdge(decoratedTypeAnnotation('C operator').node,
+ decoratedTypeAnnotation('C f').node,
+ hard: false);
+ }
+
test_binaryExpression_slash_result_not_null() async {
await analyze('''
double f(int i, int j) => i / j;
@@ -1439,6 +1507,15 @@
assertLUB(nullable_conditional, nullable_i, always);
}
+ test_constructor_default_parameter_value_bool() async {
+ await analyze('''
+class C {
+ C([bool b = true]);
+}
+''');
+ assertNoUpstreamNullability(decoratedTypeAnnotation('bool b').node);
+ }
+
test_constructor_named() async {
await analyze('''
class C {
@@ -2486,6 +2563,92 @@
assertNoUpstreamNullability(decoratedTypeAnnotation('int').node);
}
+ test_invocation_arguments() async {
+ await analyze('''
+int f(Function g, int i, int j) => g(h(i), named: h(j));
+int h(int x) => 0;
+''');
+ // Make sure the appropriate edges get created for the calls to h().
+ assertEdge(decoratedTypeAnnotation('int i').node,
+ decoratedTypeAnnotation('int x').node,
+ hard: true);
+ assertEdge(decoratedTypeAnnotation('int j').node,
+ decoratedTypeAnnotation('int x').node,
+ hard: true);
+ }
+
+ test_invocation_arguments_parenthesized() async {
+ await analyze('''
+int f(Function g, int i, int j) => (g)(h(i), named: h(j));
+int h(int x) => 0;
+''');
+ // Make sure the appropriate edges get created for the calls to h().
+ assertEdge(decoratedTypeAnnotation('int i').node,
+ decoratedTypeAnnotation('int x').node,
+ hard: true);
+ assertEdge(decoratedTypeAnnotation('int j').node,
+ decoratedTypeAnnotation('int x').node,
+ hard: true);
+ }
+
+ test_invocation_dynamic() async {
+ await analyze('''
+int f(dynamic g) => g();
+''');
+ assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+ }
+
+ test_invocation_dynamic_parenthesized() async {
+ await analyze('''
+int f(dynamic g) => (g)();
+''');
+ assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+ }
+
+ test_invocation_function() async {
+ await analyze('''
+int f(Function g) => g();
+''');
+ assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+ assertNullCheck(
+ checkExpression('g('),
+ assertEdge(decoratedTypeAnnotation('Function g').node, never,
+ hard: true));
+ }
+
+ test_invocation_function_parenthesized() async {
+ await analyze('''
+int f(Function g) => (g)();
+''');
+ assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+ assertNullCheck(
+ checkExpression('g)('),
+ assertEdge(decoratedTypeAnnotation('Function g').node, never,
+ hard: true));
+ }
+
+ test_invocation_type_arguments() async {
+ await analyze('''
+int f(Function g) => g<C<int>>();
+class C<T extends num> {}
+''');
+ // Make sure the appropriate edge gets created for the instantiation of C.
+ assertEdge(decoratedTypeAnnotation('int>').node,
+ decoratedTypeAnnotation('num>').node,
+ hard: true);
+ }
+
+ test_invocation_type_arguments_parenthesized() async {
+ await analyze('''
+int f(Function g) => (g)<C<int>>();
+class C<T extends num> {}
+''');
+ // Make sure the appropriate edge gets created for the instantiation of C.
+ assertEdge(decoratedTypeAnnotation('int>').node,
+ decoratedTypeAnnotation('num>').node,
+ hard: true);
+ }
+
@failingTest
test_isExpression_genericFunctionType() async {
await analyze('''
@@ -2691,6 +2854,35 @@
assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
}
+ test_methodInvocation_dynamic_arguments() async {
+ await analyze('''
+int f(dynamic d, int i, int j) {
+ return d.g(h(i), named: h(j));
+}
+int h(int x) => 0;
+''');
+ // Make sure the appropriate edges get created for the calls to h().
+ assertEdge(decoratedTypeAnnotation('int i').node,
+ decoratedTypeAnnotation('int x').node,
+ hard: true);
+ assertEdge(decoratedTypeAnnotation('int j').node,
+ decoratedTypeAnnotation('int x').node,
+ hard: true);
+ }
+
+ test_methodInvocation_dynamic_type_arguments() async {
+ await analyze('''
+int f(dynamic d, int i, int j) {
+ return d.g<C<int>>();
+}
+class C<T extends num> {}
+''');
+ // Make sure the appropriate edge gets created for the instantiation of C.
+ assertEdge(decoratedTypeAnnotation('int>').node,
+ decoratedTypeAnnotation('num>').node,
+ hard: true);
+ }
+
test_methodInvocation_object_method() async {
await analyze('''
String f(int i) => i.toString();
@@ -4601,12 +4793,36 @@
test_superExpression() async {
await analyze('''
-class C {
- C f() => super;
+class B {
+ void f(int/*1*/ i, int/*2*/ j) {}
+}
+class C extends B {
+ void f(int/*3*/ i, int/*4*/ j) => super.f(j, i);
}
''');
+ assertEdge(decoratedTypeAnnotation('int/*3*/').node,
+ decoratedTypeAnnotation('int/*2*/').node,
+ hard: true);
+ assertEdge(decoratedTypeAnnotation('int/*4*/').node,
+ decoratedTypeAnnotation('int/*1*/').node,
+ hard: true);
+ }
- assertNoUpstreamNullability(decoratedTypeAnnotation('C f').node);
+ test_superExpression_generic() async {
+ await analyze('''
+class B<U> {
+ U g() => null;
+}
+class C<T> extends B<T> {
+ T f() => super.g();
+}
+''');
+ assertEdge(
+ substitutionNode(
+ substitutionNode(never, decoratedTypeAnnotation('T> {').node),
+ decoratedTypeAnnotation('U g').node),
+ decoratedTypeAnnotation('T f').node,
+ hard: false);
}
test_symbolLiteral() async {
@@ -4624,10 +4840,19 @@
C f() => this;
}
''');
-
assertNoUpstreamNullability(decoratedTypeAnnotation('C f').node);
}
+ test_thisExpression_generic() async {
+ await analyze('''
+class C<T> {
+ C<T> f() => this;
+}
+''');
+ assertNoUpstreamNullability(decoratedTypeAnnotation('C<T> f').node);
+ assertNoUpstreamNullability(decoratedTypeAnnotation('T> f').node);
+ }
+
test_throwExpression() async {
await analyze('''
int f() {
diff --git a/pkg/smith/lib/configuration.dart b/pkg/smith/lib/configuration.dart
index fc7883a..07653eb 100644
--- a/pkg/smith/lib/configuration.dart
+++ b/pkg/smith/lib/configuration.dart
@@ -908,7 +908,7 @@
/// Opted in to NNBD features, but only static checking and weak runtime
/// checks.
- static const optedIn = NnbdMode._('opted-in');
+ static const weak = NnbdMode._('weak');
/// Opted in to NNBD features and with full sound runtime checks.
static const strong = NnbdMode._('strong');
@@ -916,7 +916,7 @@
static final List<String> names = _all.keys.toList();
static final _all = {
- for (var mode in [legacy, optedIn, strong]) mode.name: mode
+ for (var mode in [legacy, weak, strong]) mode.name: mode
};
static NnbdMode find(String name) {
diff --git a/pkg/smith/test/configuration_test.dart b/pkg/smith/test/configuration_test.dart
index fcbbebf..4f5736e 100644
--- a/pkg/smith/test/configuration_test.dart
+++ b/pkg/smith/test/configuration_test.dart
@@ -198,7 +198,7 @@
test("other options from map", () {
expect(
Configuration.parse("dart2js", {
- "nnbd": "opted-in",
+ "nnbd": "weak",
"builder-tag": "the tag",
"vm-options": ["vm stuff", "more vm stuff"],
"dart2js-options": ["dart2js stuff", "more dart2js stuff"],
@@ -214,7 +214,7 @@
}),
equals(Configuration("dart2js", Architecture.x64, Compiler.dart2js,
Mode.release, Runtime.d8, System.host,
- nnbdMode: NnbdMode.optedIn,
+ nnbdMode: NnbdMode.weak,
builderTag: "the tag",
vmOptions: ["vm stuff", "more vm stuff"],
dart2jsOptions: ["dart2js stuff", "more dart2js stuff"],
diff --git a/pkg/test_runner/bin/test_runner.dart b/pkg/test_runner/bin/test_runner.dart
index 491e10b..3f5e048 100644
--- a/pkg/test_runner/bin/test_runner.dart
+++ b/pkg/test_runner/bin/test_runner.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:io';
/// This file is the entrypoint of the Dart repository's custom test system.
/// It is used to test:
@@ -28,11 +29,16 @@
void main(List<String> arguments) {
// Parse the command line arguments to a configuration.
var parser = OptionsParser();
- var configurations = parser.parse(arguments);
- if (configurations == null || configurations.isEmpty) return;
+ try {
+ var configurations = parser.parse(arguments);
+ if (configurations == null || configurations.isEmpty) return;
- // Run all of the configured tests.
- // TODO(26372): Ensure that all tasks complete and return a future from this
- // function.
- testConfigurations(configurations);
+ // Run all of the configured tests.
+ // TODO(26372): Ensure that all tasks complete and return a future from this
+ // function.
+ testConfigurations(configurations);
+ } on OptionParseException catch (exception) {
+ print(exception.message);
+ exit(1);
+ }
}
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index 9de4b81..ed972e7 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -37,11 +37,16 @@
// TODO(rnystrom): Some string options use "" to mean "no value" and others
// use null. Clean that up.
_Option(this.name, this.description,
- {String abbr, List<String> values, String defaultsTo, bool hide})
+ {String abbr,
+ List<String> values,
+ String defaultsTo,
+ bool allowMultiple,
+ bool hide})
: abbreviation = abbr,
values = values ?? [],
defaultValue = defaultsTo,
type = _OptionValueType.string,
+ allowMultiple = allowMultiple ?? true,
verboseOnly = hide ?? false;
_Option.bool(this.name, this.description, {String abbr, bool hide})
@@ -49,6 +54,7 @@
values = [],
defaultValue = false,
type = _OptionValueType.bool,
+ allowMultiple = false,
verboseOnly = hide ?? false;
_Option.int(this.name, this.description,
@@ -57,6 +63,7 @@
values = [],
defaultValue = defaultsTo,
type = _OptionValueType.int,
+ allowMultiple = false,
verboseOnly = hide ?? false;
final String name;
@@ -66,14 +73,16 @@
final Object defaultValue;
final _OptionValueType type;
+ /// Whether a comma-separated list of values is permitted.
+ final bool allowMultiple;
+
/// Only show this option in the verbose help.
final bool verboseOnly;
- /// Gets the shortest command line argument used to refer to this option.
+ /// The shortest command line argument used to refer to this option.
String get shortCommand => abbreviation != null ? "-$abbreviation" : command;
- /// Gets the canonical long command line argument used to refer to this
- /// option.
+ /// The canonical long command line argument used to refer to this option.
String get command => "--${name.replaceAll('_', '-')}";
}
@@ -151,7 +160,6 @@
test options, specifying how tests should be run.''',
abbr: 'n',
hide: true),
- _Option.bool('strong', 'Deprecated, no-op.', hide: true),
// TODO(sigmund): rename flag once we migrate all dart2js bots to the test
// matrix.
_Option.bool('host_checked', 'Run compiler with assertions enabled.',
@@ -189,7 +197,8 @@
compact, color, line, verbose, silent, status, buildbot, diff''',
abbr: 'p',
values: Progress.names,
- defaultsTo: Progress.compact.name),
+ defaultsTo: Progress.compact.name,
+ allowMultiple: false),
_Option('step_name', 'Step name for use by -pbuildbot.', hide: true),
_Option.bool('report',
'Print a summary report of the number of tests, by expectation.',
@@ -230,9 +239,14 @@
_Option('chrome', 'Path to chrome browser executable.', hide: true),
_Option('safari', 'Path to safari browser executable.', hide: true),
_Option.bool('use_sdk', '''Use compiler or runtime from the SDK.'''),
- _Option.bool('nnbd', '''Opt tests into non-nullable types.'''),
- _Option.bool('nnbd_strong_checking',
- '''Enable strong runtime checks of non-nullable types.'''),
+ _Option(
+ 'nnbd',
+ '''Which set of non-nullable type features to use.
+
+Allowed values are: legacy, weak, strong''',
+ values: NnbdMode.names,
+ defaultsTo: NnbdMode.legacy.name,
+ allowMultiple: false),
// TODO(rnystrom): This does not appear to be used. Remove?
_Option('build_directory',
'The name of the build directory, where products are placed.',
@@ -380,6 +394,7 @@
verbose: arguments.contains("--verbose") || arguments.contains("-v"));
return null;
}
+
if (arguments.contains("--list-configurations")) {
var testMatrixFile = "tools/bots/test_matrix.json";
var testMatrix = TestMatrix.fromPath(testMatrixFile);
@@ -476,11 +491,20 @@
case _OptionValueType.string:
// Validate against the allowed values.
if (!option.values.isEmpty) {
- for (var v in value.split(",")) {
- if (!option.values.contains(v)) {
- _fail('Unknown value "$v" for command line option "$command".');
+ validate(String value) {
+ if (!option.values.contains(value)) {
+ _fail('Unknown value "$value" for option "$command".');
}
}
+
+ if (option.allowMultiple) {
+ value.split(",").forEach(validate);
+ } else {
+ if (value.contains(",")) {
+ _fail('Only a single value is allowed for option "$command".');
+ }
+ validate(value);
+ }
}
// TODO(rnystrom): Store as a list instead of a comma-delimited
@@ -493,9 +517,9 @@
// If a named configuration was specified ensure no other options, which are
// implied by the named configuration, were specified.
if (configuration['named_configuration'] is String) {
- for (final optionName in _namedConfigurationOptions) {
+ for (var optionName in _namedConfigurationOptions) {
if (configuration.containsKey(optionName)) {
- final namedConfig = configuration['named_configuration'];
+ var namedConfig = configuration['named_configuration'];
_fail("The named configuration '$namedConfig' implies "
"'$optionName'. Try removing '$optionName'.");
}
@@ -654,6 +678,9 @@
compilers.addAll(runtimes.map((runtime) => runtime.defaultCompiler));
}
+ var progress = Progress.find(data["progress"] as String);
+ var nnbdMode = NnbdMode.find(data["nnbd"] as String);
+
// Expand runtimes.
for (var runtime in runtimes) {
// Start installing the runtime if needed.
@@ -676,10 +703,11 @@
var mode = Mode.find(modeName);
var system = System.find(data["system"] as String);
var namedConfiguration =
- getNamedConfiguration(data["named_configuration"] as String);
+ _namedConfiguration(data["named_configuration"] as String);
var innerConfiguration = namedConfiguration ??
Configuration("custom configuration", architecture, compiler,
mode, runtime, system,
+ nnbdMode: nnbdMode,
timeout: data["timeout"] as int,
enableAsserts: data["enable_asserts"] as bool,
useAnalyzerCfe: data["use_cfe"] as bool,
@@ -700,7 +728,7 @@
builderTag: data["builder_tag"] as String);
var configuration = TestConfiguration(
configuration: innerConfiguration,
- progress: Progress.find(data["progress"] as String),
+ progress: progress,
selectors: selectors,
testList: data["test_list_contents"] as List<String>,
repeat: data["repeat"] as int,
@@ -903,14 +931,22 @@
}
}
-Configuration getNamedConfiguration(String template) {
+/// Exception thrown when the arguments could not be parsed.
+class OptionParseException implements Exception {
+ final String message;
+
+ OptionParseException(this.message);
+}
+
+Configuration _namedConfiguration(String template) {
if (template == null) return null;
- final testMatrixFile = "tools/bots/test_matrix.json";
- TestMatrix testMatrix = TestMatrix.fromPath(testMatrixFile);
- final configuration = testMatrix.configurations
+
+ var testMatrixFile = "tools/bots/test_matrix.json";
+ var testMatrix = TestMatrix.fromPath(testMatrixFile);
+ var configuration = testMatrix.configurations
.singleWhere((c) => c.name == template, orElse: () => null);
if (configuration == null) {
- final names = testMatrix.configurations
+ var names = testMatrix.configurations
.map((configuration) => configuration.name)
.toList();
names.sort();
@@ -921,8 +957,7 @@
return configuration;
}
-/// Prints [message] and exits with a non-zero exit code.
+/// Throws an [OptionParseException] with [message].
void _fail(String message) {
- print(message);
- exit(1);
+ throw OptionParseException(message);
}
diff --git a/pkg/test_runner/lib/src/process_queue.dart b/pkg/test_runner/lib/src/process_queue.dart
index 72ab4c2..01a2fb1 100644
--- a/pkg/test_runner/lib/src/process_queue.dart
+++ b/pkg/test_runner/lib/src/process_queue.dart
@@ -1131,7 +1131,7 @@
}
var processFuture =
io.Process.start(executable, arguments, environment: environment);
- processFuture.then((io.Process p) {
+ processFuture.then<dynamic>((io.Process p) {
_process = p;
Stream<String> _stdoutStream = _process.stdout
diff --git a/pkg/test_runner/lib/src/static_error.dart b/pkg/test_runner/lib/src/static_error.dart
index 518d91b..e339a5e 100644
--- a/pkg/test_runner/lib/src/static_error.dart
+++ b/pkg/test_runner/lib/src/static_error.dart
@@ -2,6 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// Only needed so that [TestFile] can be referenced in doc comments.
+import 'test_file.dart';
+
/// Describes a static error.
///
/// These can be parsed from comments in [TestFile]s, in which case they
diff --git a/pkg/test_runner/lib/src/test_case.dart b/pkg/test_runner/lib/src/test_case.dart
index 4e7e080..2b153eaa 100644
--- a/pkg/test_runner/lib/src/test_case.dart
+++ b/pkg/test_runner/lib/src/test_case.dart
@@ -269,7 +269,7 @@
var processFuture = io.Process.start(command.executable, args,
environment: processEnvironment,
workingDirectory: command.workingDirectory);
- processFuture.then((io.Process process) {
+ processFuture.then<dynamic>((io.Process process) {
var stdoutFuture = process.stdout.pipe(stdout);
var stderrFuture = process.stderr.pipe(stderr);
pid = process.pid;
diff --git a/pkg/test_runner/test/options_test.dart b/pkg/test_runner/test/options_test.dart
new file mode 100644
index 0000000..cf1b98e
--- /dev/null
+++ b/pkg/test_runner/test/options_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'package:expect/expect.dart';
+
+import 'package:test_runner/src/configuration.dart';
+import 'package:test_runner/src/options.dart';
+
+void main() {
+ testDefaults();
+ testOptions();
+ testValidation();
+}
+
+void testDefaults() {
+ // TODO(rnystrom): Test other options.
+ var configuration = parseConfiguration([]);
+ Expect.equals(Progress.compact, configuration.progress);
+ Expect.equals(NnbdMode.legacy, configuration.nnbdMode);
+}
+
+void testOptions() {
+ // TODO(rnystrom): Test other options.
+ var configurations = parseConfigurations(['--mode=debug,release']);
+ Expect.equals(2, configurations.length);
+ Expect.equals(Mode.debug, configurations[0].mode);
+ Expect.equals(Mode.release, configurations[1].mode);
+
+ var configuration = parseConfiguration(['--nnbd=weak']);
+ Expect.equals(NnbdMode.weak, configuration.nnbdMode);
+}
+
+void testValidation() {
+ // TODO(rnystrom): Test other options.
+ expectValidationError(
+ ['--timeout=notint'], 'Integer value expected for option "--timeout".');
+ expectValidationError(
+ ['--timeout=1,2'], 'Integer value expected for option "--timeout".');
+
+ expectValidationError(['--progress=unknown'],
+ 'Unknown value "unknown" for option "--progress".');
+ // Don't allow multiple.
+ expectValidationError(['--progress=compact,silent'],
+ 'Only a single value is allowed for option "--progress".');
+
+ expectValidationError(
+ ['--nnbd=unknown'], 'Unknown value "unknown" for option "--nnbd".');
+ // Don't allow multiple.
+ expectValidationError(['--nnbd=weak,strong'],
+ 'Only a single value is allowed for option "--nnbd".');
+}
+
+TestConfiguration parseConfiguration(List<String> arguments) {
+ var configurations = parseConfigurations(arguments);
+ Expect.equals(1, configurations.length);
+ return configurations.first;
+}
+
+List<TestConfiguration> parseConfigurations(List<String> arguments) {
+ var parser = OptionsParser();
+ var configurations = parser.parse(arguments);
+
+ // By default, without an explicit selector, you get two configurations, one
+ // for observatory_ui, and one for all the other selectors. Discard the
+ // observatory one to keep things simpler.
+ configurations
+ .removeWhere((config) => config.selectors.containsKey('observatory_ui'));
+ return configurations;
+}
+
+void expectValidationError(List<String> arguments, String error) {
+ try {
+ OptionsParser().parse(arguments);
+ Expect.fail('Should have thrown an exception, but did not.');
+ } on OptionParseException catch (exception) {
+ Expect.equals(error, exception.message);
+ } catch (exception) {
+ Expect.fail('Wrong exception: $exception');
+ }
+}
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index f23de40..2ff8888 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -1154,7 +1154,7 @@
char* error = nullptr;
if (!dart::embedder::InitOnce(&error)) {
- Syslog::PrintErr("Stanalone embedder initialization failed: %s\n", error);
+ Syslog::PrintErr("Standalone embedder initialization failed: %s\n", error);
free(error);
Platform::Exit(kErrorExitCode);
}
diff --git a/runtime/observatory/tests/service/external_service_asynchronous_invocation_test.dart b/runtime/observatory/tests/service/external_service_asynchronous_invocation_test.dart
index 3157090..4feafac 100644
--- a/runtime/observatory/tests/service/external_service_asynchronous_invocation_test.dart
+++ b/runtime/observatory/tests/service/external_service_asynchronous_invocation_test.dart
@@ -145,7 +145,7 @@
completions.forEach((complete) => complete());
final errors = await Future.wait(results.map((future) {
- return future.then((_) {
+ return future.then<dynamic>((_) {
expect(false, isTrue, reason: 'shouldn\'t get here');
}).catchError((e) => e);
}));
diff --git a/runtime/observatory/tests/service/service_kernel.status b/runtime/observatory/tests/service/service_kernel.status
index 3c70570..4a4cf8f 100644
--- a/runtime/observatory/tests/service/service_kernel.status
+++ b/runtime/observatory/tests/service/service_kernel.status
@@ -35,7 +35,6 @@
rewind_optimized_out_test: SkipByDesign # No incremental compiler available.
rewind_test: SkipByDesign # No incremental compiler available.
simple_reload_test: RuntimeError, Timeout # Issue 35506
-unused_changes_in_last_reload_test: RuntimeError
[ $compiler == dartkp ]
*: SkipByDesign # Non-kernel also skips precompiled mode.
@@ -157,7 +156,6 @@
rewind_test: Pass, RuntimeError
set_name_rpc_test: RuntimeError # Please triage.
simple_reload_test: RuntimeError, Timeout
-unused_changes_in_last_reload_test: Skip # Times out on sim architectures.
valid_source_locations_test: Pass, Slow, Timeout # Issue 34736
# Kernel works slightly different. There are kernel specific versions.
@@ -171,4 +169,3 @@
evaluate_activation_test/scope: RuntimeError # http://dartbug.com/20047
get_source_report_test: RuntimeError # Should pass again when constant evaluation is relanded, see http://dartbug.com/36600
pause_on_unhandled_async_exceptions2_test: Pass, Slow
-unused_changes_in_last_reload_test: RuntimeError
diff --git a/runtime/observatory/tests/service/unused_changes_in_last_reload/v1/main.dart b/runtime/observatory/tests/service/unused_changes_in_last_reload/v1/main.dart
deleted file mode 100644
index 28f600c..0000000
--- a/runtime/observatory/tests/service/unused_changes_in_last_reload/v1/main.dart
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:isolate';
-
-unchangedFunction() => "unchanged";
-var unchangedField = "unchanged".toString();
-
-removedFunction() => "removed";
-var removedField = "removed".toString();
-
-function() => "original value";
-var uninitializedField = "original initializer".toString();
-var fieldLiteralInitializer = "original initializer";
-var initializedField = "original initializer".toString();
-var neverReferencedField = "original initializer".toString();
-
-// Not initially finalized.
-class C {
- function() => "original value";
-}
-
-class S {}
-class M {}
-class MA1 extends S with M {}
-class MA2 = S with M;
-
-main() {
- new RawReceivePort(); // Keep alive.
- print(function());
- print(initializedField);
- print(new MA1());
- print(new MA2());
-}
diff --git a/runtime/observatory/tests/service/unused_changes_in_last_reload/v2/main.dart b/runtime/observatory/tests/service/unused_changes_in_last_reload/v2/main.dart
deleted file mode 100644
index 910904f..0000000
--- a/runtime/observatory/tests/service/unused_changes_in_last_reload/v2/main.dart
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-unchangedFunction() => "unchanged";
-var unchangedField = "unchanged".toString();
-
-function() => "new value";
-var uninitializedField = "new initializer".toString();
-var fieldLiteralInitializer = "new initializer";
-var initializedField = "new initializer".toString();
-var neverReferencedField = "new initializer".toString();
-
-// Not initially finalized.
-class C {
- function() => "new value";
-}
-
-class S {}
-class M {
- newFunction() => "new value";
-}
-class MA1 extends S with M {
- newFunction2() => "new value";
-}
-class MA2 = S with M;
-
-class NewClass {
- function() => "new value";
-}
-
-typedef bool NewTypedef(Object obj);
-
-main2() {
- print(function());
- print(uninitializedField);
- print(initializedField);
- print(new C().function());
- print(new NewClass().function());
- print(new MA1().newFunction());
- print(new MA1().newFunction2());
-}
diff --git a/runtime/observatory/tests/service/unused_changes_in_last_reload_test.dart b/runtime/observatory/tests/service/unused_changes_in_last_reload_test.dart
deleted file mode 100644
index 223ac40..0000000
--- a/runtime/observatory/tests/service/unused_changes_in_last_reload_test.dart
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'test_helper.dart';
-import 'dart:developer';
-import 'dart:isolate' as I;
-import 'dart:io';
-import 'service_test_common.dart';
-import 'package:observatory/service.dart';
-import 'package:path/path.dart' as path;
-import 'package:unittest/unittest.dart';
-
-// Chop off the file name.
-String baseDirectory = path.dirname(Platform.script.path) + '/';
-
-Uri baseUri = Platform.script.replace(path: baseDirectory);
-Uri v1Uri = baseUri.resolveUri(Uri.parse('unused_changes_in_last_reload/v1/main.dart'));
-Uri v2Uri = baseUri.resolveUri(Uri.parse('unused_changes_in_last_reload/v2/main.dart'));
-
-testMain() async {
- print(baseUri);
- debugger(); // Stop here.
- // Spawn the child isolate.
- I.Isolate isolate = await I.Isolate.spawnUri(v1Uri, [], null);
- print(isolate);
- debugger();
-}
-
-var tests = <IsolateTest>[
- // Stopped at 'debugger' statement.
- hasStoppedAtBreakpoint,
- // Resume the isolate into the while loop.
- resumeIsolate,
- // Stop at 'debugger' statement.
- hasStoppedAtBreakpoint,
- (Isolate mainIsolate) async {
- // Grab the VM.
- VM vm = mainIsolate.vm;
- await vm.reloadIsolates();
- expect(vm.isolates.length, 2);
-
- // Find the child isolate.
- Isolate childIsolate =
- vm.isolates.firstWhere((Isolate i) => i != mainIsolate);
- expect(childIsolate, isNotNull);
-
- // Fetch unused.
- await childIsolate.invokeRpc("_getUnusedChangesInLastReload", {}).then((v) {
- print(v);
- throw "MissingError";
- }, onError: (e) {
- print(e);
- });
-
- // Reload to v1 (null change).
- var response = await childIsolate.reloadSources(
- rootLibUri: v1Uri.toString(),
- );
- print(response);
- expect(response['success'], isTrue);
-
- // Fetch unused.
- response = await childIsolate.invokeRpc("_getUnusedChangesInLastReload", {});
- print(response);
- var unused = response['unused'].map((ea) => ea.toString());
- expect(unused, unorderedEquals([]));
-
- // Reload to v2.
- response = await childIsolate.reloadSources(
- rootLibUri: v2Uri.toString(),
- );
- print(response);
- expect(response['success'], isTrue);
-
- // Fetch unused.
- response = await childIsolate.invokeRpc("_getUnusedChangesInLastReload", {});
- print(response);
- unused = response['unused'].map((ea) => ea.toString());
- expect(unused, unorderedEquals([
- 'Class(C)',
- 'Class(NewClass)',
- 'Field(main.dart.uninitializedField)',
- 'Field(main.dart.fieldLiteralInitializer)',
- 'Field(main.dart.initializedField)',
- 'Field(main.dart.neverReferencedField)',
- 'ServiceFunction(M.newFunction)',
- 'ServiceFunction(MA1.newFunction2)',
- 'ServiceFunction(function)',
- 'ServiceFunction(main2)',
- ]));
-
- // Invoke next main.
- Library lib = childIsolate.rootLibrary;
- await lib.load();
- Instance result = await lib.evaluate('main2()');
- expect(result.valueAsString, equals('null'));
-
- // Fetch unused.
- response = await childIsolate.invokeRpc("_getUnusedChangesInLastReload", {});
- print(response);
- unused = response['unused'].map((ea) => ea.toString());
- expect(unused, unorderedEquals([
- 'Field(main.dart.fieldLiteralInitializer)',
- 'Field(main.dart.initializedField)',
- 'Field(main.dart.neverReferencedField)',
- // TODO(31265): M.newFunction should be considered used.
- 'ServiceFunction(M.newFunction)',
- ]));
-
- // Reload to v2 again.
- response = await childIsolate.reloadSources(
- rootLibUri: v2Uri.toString(),
- );
- print(response);
- expect(response['success'], isTrue);
-
- // Fetch unused.
- response = await childIsolate.invokeRpc("_getUnusedChangesInLastReload", {});
- print(response);
- unused = response['unused'].map((ea) => ea.toString());
- expect(unused, unorderedEquals([]));
- }
-];
-
-main(args) => runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/runtime/tools/bin_to_coff.py b/runtime/tools/bin_to_coff.py
index c8a8ebc..1925bcd 100644
--- a/runtime/tools/bin_to_coff.py
+++ b/runtime/tools/bin_to_coff.py
@@ -4,8 +4,6 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
-# See also "PE Format" at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
-
import argparse
from ctypes import create_string_buffer
from struct import *
@@ -21,7 +19,6 @@
SECTION_HEADER_TEXT = 0x20 # Contains executable code
SECTION_HEADER_DATA = 0x40 # Contains only initialized data
SECTION_HEADER_BSS = 0x80 # Contains uninitialized data
-SECTION_HEADER_ALIGN_32BYTES = 0x600000
# FILE HEADER FORMAT
# typedef struct {
@@ -179,18 +176,17 @@
offset += FILE_HEADER_SIZE
section_name = SECTION_NAME_RODATA
- section_flags = SECTION_HEADER_DATA
+ section_type = SECTION_HEADER_DATA
if args.executable:
section_name = SECTION_NAME_TEXT
- section_flags = SECTION_HEADER_TEXT
- section_flags |= SECTION_HEADER_ALIGN_32BYTES
+ section_type = SECTION_HEADER_TEXT
# Populate the section header for a single section.
pack_into(SECTION_HEADER_FORMAT, buff, offset, section_name, SECTION_PADDR,
SECTION_VADDR, section_size + size_symbol_size,
SECTION_RAW_DATA_PTR, SECTION_RELOCATION_PTR,
SECTION_LINE_NUMS_PTR, SECTION_NUM_RELOCATION,
- SECTION_NUM_LINE_NUMS, section_flags)
+ SECTION_NUM_LINE_NUMS, section_type)
offset += SECTION_HEADER_SIZE
# Copy the binary data.
diff --git a/runtime/tools/dartfuzz/collect_data.py b/runtime/tools/dartfuzz/collect_data.py
index 25b5f5d..6ce118f 100755
--- a/runtime/tools/dartfuzz/collect_data.py
+++ b/runtime/tools/dartfuzz/collect_data.py
@@ -87,8 +87,8 @@
for i in range(len(s)):
s[i] += int(test[i])
print(
- "Tests: %d Success: %d (Rerun: %d) Skipped: %d Timeout: %d Divergences: %d"
- "(failing shards: %s) \r" %
+ "Tests: %d Success: %d (Rerun: %d) Skipped: %d Timeout: %d "
+ "Divergences: %d (failing shards: %s) \r" %
tuple(s + [", ".join(divs) if divs else "none"]),
end="")
diff --git a/runtime/tools/dartfuzz/dartfuzz.dart b/runtime/tools/dartfuzz/dartfuzz.dart
index cc97ad8..8a02ff3 100644
--- a/runtime/tools/dartfuzz/dartfuzz.dart
+++ b/runtime/tools/dartfuzz/dartfuzz.dart
@@ -14,7 +14,7 @@
// Version of DartFuzz. Increase this each time changes are made
// to preserve the property that a given version of DartFuzz yields
// the same fuzzed program for a deterministic random seed.
-const String version = '1.39';
+const String version = '1.42';
// Restriction on statements and expressions.
const int stmtLength = 2;
@@ -167,45 +167,74 @@
emitLn(').cast<ffi.NativeFunction<${typeName}>>().asFunction();');
}
+ void emitMethod(
+ String name, int index, List<DartType> method, bool isFfiMethod) {
+ if (isFfiMethod) {
+ emitFfiTypedef("${name}Ffi${index}Type", method);
+ emitLn('${method[0].name} ${name}Ffi$index(', newline: false);
+ } else {
+ emitLn('${method[0].name} $name$index(', newline: false);
+ }
+ emitParDecls(method);
+ if (!isFfiMethod && rand.nextInt(10) == 0) {
+ // Emit a method using "=>" syntax.
+ emit(') => ');
+ emitExpr(0, method[0]);
+ emit(';', newline: true);
+ return;
+ }
+ emit(') {', newline: true);
+ indent += 2;
+ assert(localVars.isEmpty);
+ if (emitStatements(0)) {
+ emitReturn();
+ }
+ assert(localVars.isEmpty);
+ indent -= 2;
+ emitLn('}');
+ if (isFfiMethod) {
+ emitFfiCast("${name}${index}", "${name}Ffi${index}",
+ "${name}Ffi${index}Type", method);
+ }
+ emit('', newline: true);
+ }
+
void emitMethods(String name, List<List<DartType>> methods,
[List<bool> ffiStatus]) {
for (int i = 0; i < methods.length; i++) {
List<DartType> method = methods[i];
currentMethod = i;
final bool isFfiMethod = ffiStatus != null && ffiStatus[i];
- if (isFfiMethod) {
- emitFfiTypedef("${name}Ffi${i}Type", method);
- emitLn('${method[0].name} ${name}Ffi$i(', newline: false);
- } else {
- emitLn('${method[0].name} $name$i(', newline: false);
- }
- emitParDecls(method);
- if (!isFfiMethod && rand.nextInt(10) == 0) {
- // Emit a method using "=>" syntax.
- emit(') => ');
- emitExpr(0, method[0]);
- emit(';', newline: true);
- currentMethod = null;
- continue;
- }
- emit(') {', newline: true);
- indent += 2;
- assert(localVars.isEmpty);
- if (emitStatements(0)) {
- emitReturn();
- }
- assert(localVars.isEmpty);
- indent -= 2;
- emitLn('}');
- if (isFfiMethod) {
- emitFfiCast(
- "${name}${i}", "${name}Ffi${i}", "${name}Ffi${i}Type", method);
- }
- emit('', newline: true);
+ emitMethod(name, i, method, isFfiMethod);
currentMethod = null;
}
}
+ // Randomly overwrite some methods from the parent classes.
+ void emitVirtualMethods() {
+ final currentClassTmp = currentClass;
+ int parentClass = classParents[currentClass];
+ // Chase randomly up in class hierarchy.
+ while (parentClass >= 0) {
+ for (int j = 0, n = classMethods[parentClass].length; j < n; j++) {
+ if (rand.nextInt(8) == 0) {
+ currentClass = parentClass;
+ currentMethod = j;
+ emitMethod('$methodName${parentClass}_', j,
+ classMethods[parentClass][j], false);
+ currentMethod = null;
+ currentClass = null;
+ }
+ }
+ if (rand.nextInt(2) == 0 || classParents.length > parentClass) {
+ break;
+ } else {
+ parentClass = classParents[parentClass];
+ }
+ }
+ currentClass = currentClassTmp;
+ }
+
void emitClasses() {
assert(classFields.length == classMethods.length);
for (int i = 0; i < classFields.length; i++) {
@@ -231,6 +260,7 @@
indent += 2;
emitVarDecls('$fieldName${i}_', classFields[i]);
currentClass = i;
+ emitVirtualMethods();
emitMethods('$methodName${i}_', classMethods[i]);
emitLn('void run() {');
indent += 2;
@@ -768,12 +798,16 @@
void emitCollectionElement(int depth, DartType tp) {
int r = depth <= exprDepth ? rand.nextInt(10) : 10;
- // TODO(ajcbik): renable, https://github.com/dart-lang/sdk/issues/38231
- switch (r + 3) {
+ switch (r) {
// Favors elements over control-flow collections.
case 0:
- emit('...'); // spread
- emitCollection(depth + 1, tp);
+ // TODO (ajcbik): Remove restriction once compiler is fixed.
+ if (depth < 2) {
+ emit('...'); // spread
+ emitCollection(depth + 1, tp);
+ } else {
+ emitElement(depth, tp);
+ }
break;
case 1:
emit('if (');
diff --git a/runtime/tools/dartfuzz/dartfuzz_test.dart b/runtime/tools/dartfuzz/dartfuzz_test.dart
index e5cce1d..3dc78e3 100644
--- a/runtime/tools/dartfuzz/dartfuzz_test.dart
+++ b/runtime/tools/dartfuzz/dartfuzz_test.dart
@@ -239,8 +239,10 @@
}
void printReproductionCommand() {
- print(
- [generate, '--gen-bytecode', platform, '-o', dill, fileName].join(" "));
+ if (generate != null) {
+ print([generate, '--gen-bytecode', platform, '-o', dill, fileName]
+ .join(" "));
+ }
print(cmd.join(" "));
}
@@ -485,7 +487,7 @@
void showReproduce() {
print("\n-- BEGIN REPRODUCE --\n");
- print("dartfuzz.dart --${ffi ? "" : "no-"}ffi --${fp ? "" : "no-"}fp"
+ print("dartfuzz.dart --${ffi ? "" : "no-"}ffi --${fp ? "" : "no-"}fp "
"--seed ${seed} $fileName");
print("\n-- RUN 1 --\n");
runner1.printReproductionCommand();
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index db49703..a95642a 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -511,13 +511,25 @@
return reinterpret_cast<uint8_t*>(realloc(ptr, new_size));
}
-// Start an Isolate, load a script and create a full snapshot.
-static void BenchmarkSnapshotSize(Benchmark* benchmark, const char* script) {
+BENCHMARK_SIZE(CoreSnapshotSize) {
+ const char* kScriptChars =
+ "import 'dart:async';\n"
+ "import 'dart:core';\n"
+ "import 'dart:collection';\n"
+ "import 'dart:_internal';\n"
+ "import 'dart:math';\n"
+ "import 'dart:isolate';\n"
+ "import 'dart:mirrors';\n"
+ "import 'dart:typed_data';\n"
+ "\n";
+
+ // Start an Isolate, load a script and create a full snapshot.
+ uint8_t* vm_snapshot_data_buffer;
+ uint8_t* isolate_snapshot_data_buffer;
// Need to load the script into the dart: core library due to
// the import of dart:_internal.
- TestCase::LoadCoreTestScript(script, nullptr);
+ TestCase::LoadCoreTestScript(kScriptChars, NULL);
- Thread* thread = Thread::Current();
TransitionNativeToVM transition(thread);
StackZone zone(thread);
HANDLESCOPE(thread);
@@ -525,63 +537,58 @@
Api::CheckAndFinalizePendingClasses(thread);
// Write snapshot with object content.
- uint8_t* vm_snapshot_data_buffer = nullptr;
- uint8_t* isolate_snapshot_data_buffer = nullptr;
- uint8_t* vm_snapshot_text_buffer = nullptr;
- uint8_t* isolate_snapshot_text_buffer = nullptr;
- BlobImageWriter vm_image_writer(thread, &vm_snapshot_text_buffer,
- &malloc_allocator, 2 * MB /* initial_size */,
- /*shared_objects=*/nullptr,
- /*shared_instructions=*/nullptr,
- /*reused_instructions=*/nullptr);
- BlobImageWriter isolate_image_writer(thread, &isolate_snapshot_text_buffer,
- &malloc_allocator,
- 2 * MB /* initial_size */,
- /*shared_objects=*/nullptr,
- /*shared_instructions=*/nullptr,
- /*reused_instructions=*/nullptr);
FullSnapshotWriter writer(Snapshot::kFull, &vm_snapshot_data_buffer,
&isolate_snapshot_data_buffer, &malloc_allocator,
- &vm_image_writer, &isolate_image_writer);
+ NULL, NULL /* image_writer */);
writer.WriteFullSnapshot();
const Snapshot* snapshot =
Snapshot::SetupFromBuffer(isolate_snapshot_data_buffer);
ASSERT(snapshot->kind() == Snapshot::kFull);
- benchmark->set_score(writer.IsolateSnapshotSize() +
- isolate_image_writer.data_size());
+ benchmark->set_score(snapshot->length());
free(vm_snapshot_data_buffer);
- free(vm_snapshot_text_buffer);
free(isolate_snapshot_data_buffer);
- free(isolate_snapshot_text_buffer);
-}
-
-BENCHMARK_SIZE(CoreSnapshotSize) {
- BenchmarkSnapshotSize(benchmark,
- "import 'dart:async';\n"
- "import 'dart:core';\n"
- "import 'dart:collection';\n"
- "import 'dart:_internal';\n"
- "import 'dart:math';\n"
- "import 'dart:isolate';\n"
- "import 'dart:mirrors';\n"
- "import 'dart:typed_data';\n"
- "\n");
}
BENCHMARK_SIZE(StandaloneSnapshotSize) {
- BenchmarkSnapshotSize(benchmark,
- "import 'dart:async';\n"
- "import 'dart:core';\n"
- "import 'dart:collection';\n"
- "import 'dart:convert';\n"
- "import 'dart:math';\n"
- "import 'dart:isolate';\n"
- "import 'dart:mirrors';\n"
- "import 'dart:typed_data';\n"
- "import 'dart:io';\n"
- "import 'dart:cli';\n"
- "\n");
+ const char* kScriptChars =
+ "import 'dart:async';\n"
+ "import 'dart:core';\n"
+ "import 'dart:collection';\n"
+ "import 'dart:convert';\n"
+ "import 'dart:math';\n"
+ "import 'dart:isolate';\n"
+ "import 'dart:mirrors';\n"
+ "import 'dart:typed_data';\n"
+ "import 'dart:io';\n"
+ "import 'dart:cli';\n"
+ "\n";
+
+ // Start an Isolate, load a script and create a full snapshot.
+ uint8_t* vm_snapshot_data_buffer;
+ uint8_t* isolate_snapshot_data_buffer;
+ // Need to load the script into the dart: core library due to
+ // the import of dart:_internal.
+ TestCase::LoadCoreTestScript(kScriptChars, NULL);
+
+ TransitionNativeToVM transition(thread);
+ StackZone zone(thread);
+ HANDLESCOPE(thread);
+
+ Api::CheckAndFinalizePendingClasses(thread);
+
+ // Write snapshot with object content.
+ FullSnapshotWriter writer(Snapshot::kFull, &vm_snapshot_data_buffer,
+ &isolate_snapshot_data_buffer, &malloc_allocator,
+ NULL, NULL /* image_writer */);
+ writer.WriteFullSnapshot();
+ const Snapshot* snapshot =
+ Snapshot::SetupFromBuffer(isolate_snapshot_data_buffer);
+ ASSERT(snapshot->kind() == Snapshot::kFull);
+ benchmark->set_score(snapshot->length());
+
+ free(vm_snapshot_data_buffer);
+ free(isolate_snapshot_data_buffer);
}
BENCHMARK(CreateMirrorSystem) {
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 7a7f898..a9d7943 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -16,58 +16,99 @@
DEFINE_FLAG(bool, print_class_table, false, "Print initial class table.");
-ClassTable::ClassTable()
+SharedClassTable::SharedClassTable()
: top_(kNumPredefinedCids),
capacity_(0),
table_(NULL),
- old_tables_(new MallocGrowableArray<ClassAndSize*>()) {
- NOT_IN_PRODUCT(class_heap_stats_table_ = NULL);
+ old_tables_(new MallocGrowableArray<intptr_t*>()) {
if (Dart::vm_isolate() == NULL) {
- capacity_ = initial_capacity_;
- table_ = reinterpret_cast<ClassAndSize*>(
- calloc(capacity_, sizeof(ClassAndSize))); // NOLINT
+ ASSERT(kInitialCapacity >= kNumPredefinedCids);
+ capacity_ = kInitialCapacity;
+ // Note that [calloc] will zero-initialize the memory.
+ table_ = static_cast<intptr_t*>(calloc(capacity_, sizeof(intptr_t)));
} else {
// Duplicate the class table from the VM isolate.
- ClassTable* vm_class_table = Dart::vm_isolate()->class_table();
- capacity_ = vm_class_table->capacity_;
- table_ = reinterpret_cast<ClassAndSize*>(
- calloc(capacity_, sizeof(ClassAndSize))); // NOLINT
+ auto vm_shared_class_table = Dart::vm_isolate()->shared_class_table();
+ capacity_ = vm_shared_class_table->capacity_;
+ // Note that [calloc] will zero-initialize the memory.
+ table_ = static_cast<intptr_t*>(calloc(capacity_, sizeof(RawClass*)));
+ // The following cids don't have a corresponding class object in Dart code.
+ // We therefore need to initialize them eagerly.
for (intptr_t i = kObjectCid; i < kInstanceCid; i++) {
- table_[i] = vm_class_table->PairAt(i);
+ table_[i] = vm_shared_class_table->SizeAt(i);
}
- table_[kTypeArgumentsCid] = vm_class_table->PairAt(kTypeArgumentsCid);
- table_[kFreeListElement] = vm_class_table->PairAt(kFreeListElement);
- table_[kForwardingCorpse] = vm_class_table->PairAt(kForwardingCorpse);
- table_[kDynamicCid] = vm_class_table->PairAt(kDynamicCid);
- table_[kVoidCid] = vm_class_table->PairAt(kVoidCid);
+ table_[kTypeArgumentsCid] =
+ vm_shared_class_table->SizeAt(kTypeArgumentsCid);
+ table_[kFreeListElement] = vm_shared_class_table->SizeAt(kFreeListElement);
+ table_[kForwardingCorpse] =
+ vm_shared_class_table->SizeAt(kForwardingCorpse);
+ table_[kDynamicCid] = vm_shared_class_table->SizeAt(kDynamicCid);
+ table_[kVoidCid] = vm_shared_class_table->SizeAt(kVoidCid);
}
#ifndef PRODUCT
- class_heap_stats_table_ = reinterpret_cast<ClassHeapStats*>(
- calloc(capacity_, sizeof(ClassHeapStats))); // NOLINT
+ class_heap_stats_table_ = static_cast<ClassHeapStats*>(
+ malloc(capacity_ * sizeof(ClassHeapStats))); // NOLINT
for (intptr_t i = 0; i < capacity_; i++) {
class_heap_stats_table_[i].Initialize();
}
#endif // !PRODUCT
}
-
-ClassTable::ClassTable(ClassTable* original)
- : top_(original->top_),
- capacity_(original->top_),
- table_(original->table_),
- old_tables_(NULL) {
- NOT_IN_PRODUCT(class_heap_stats_table_ = NULL);
-}
-
-ClassTable::~ClassTable() {
+SharedClassTable::~SharedClassTable() {
if (old_tables_ != NULL) {
FreeOldTables();
delete old_tables_;
free(table_);
- NOT_IN_PRODUCT(free(class_heap_stats_table_));
- } else {
- // This instance was a shallow copy. It doesn't own any memory.
- NOT_IN_PRODUCT(ASSERT(class_heap_stats_table_ == NULL));
}
+ NOT_IN_PRODUCT(free(class_heap_stats_table_));
+}
+
+ClassTable::ClassTable(SharedClassTable* shared_class_table)
+ : top_(kNumPredefinedCids),
+ capacity_(0),
+ table_(NULL),
+ old_tables_(new MallocGrowableArray<ClassAndSize*>()),
+ old_class_tables_(new MallocGrowableArray<RawClass**>()),
+ shared_class_table_(shared_class_table) {
+ if (Dart::vm_isolate() == NULL) {
+ ASSERT(kInitialCapacity >= kNumPredefinedCids);
+ capacity_ = kInitialCapacity;
+ // Note that [calloc] will zero-initialize the memory.
+ table_ = static_cast<RawClass**>(calloc(capacity_, sizeof(RawClass*)));
+ } else {
+ // Duplicate the class table from the VM isolate.
+ ClassTable* vm_class_table = Dart::vm_isolate()->class_table();
+ capacity_ = vm_class_table->capacity_;
+ // Note that [calloc] will zero-initialize the memory.
+ table_ = static_cast<RawClass**>(calloc(capacity_, sizeof(RawClass*)));
+ // The following cids don't have a corresponding class object in Dart code.
+ // We therefore need to initialize them eagerly.
+ for (intptr_t i = kObjectCid; i < kInstanceCid; i++) {
+ table_[i] = vm_class_table->At(i);
+ }
+ table_[kTypeArgumentsCid] = vm_class_table->At(kTypeArgumentsCid);
+ table_[kFreeListElement] = vm_class_table->At(kFreeListElement);
+ table_[kForwardingCorpse] = vm_class_table->At(kForwardingCorpse);
+ table_[kDynamicCid] = vm_class_table->At(kDynamicCid);
+ table_[kVoidCid] = vm_class_table->At(kVoidCid);
+ }
+}
+
+ClassTable::ClassTable(ClassTable* original,
+ SharedClassTable* shared_class_table)
+ : top_(original->top_),
+ capacity_(original->top_),
+ table_(original->table_),
+ old_tables_(nullptr),
+ old_class_tables_(nullptr),
+ shared_class_table_(shared_class_table) {}
+
+ClassTable::~ClassTable() {
+ if (old_tables_ != nullptr || old_class_tables_ != nullptr) {
+ FreeOldTables();
+ delete old_tables_;
+ delete old_class_tables_;
+ }
+ free(table_);
}
void ClassTable::AddOldTable(ClassAndSize* old_table) {
@@ -79,17 +120,32 @@
while (old_tables_->length() > 0) {
free(old_tables_->RemoveLast());
}
+ while (old_class_tables_->length() > 0) {
+ free(old_class_tables_->RemoveLast());
+ }
+}
+
+void SharedClassTable::FreeOldTables() {
+ while (old_tables_->length() > 0) {
+ free(old_tables_->RemoveLast());
+ }
}
void ClassTable::Register(const Class& cls) {
ASSERT(Thread::Current()->IsMutatorThread());
- intptr_t index = cls.id();
+
+ const intptr_t index = cls.id();
+
+ // During the transition period we would like [SharedClassTable] to operate in
+ // parallel to [ClassTable].
+ const intptr_t expected_cid =
+ shared_class_table_->Register(index, Class::instance_size(cls.raw()));
+
if (index != kIllegalCid) {
- ASSERT(index > 0);
- ASSERT(index < kNumPredefinedCids);
- ASSERT(table_[index].class_ == NULL);
- ASSERT(index < capacity_);
- table_[index] = ClassAndSize(cls.raw(), Class::instance_size(cls.raw()));
+ ASSERT(index > 0 && index < kNumPredefinedCids && index < top_);
+ ASSERT(table_[index] == nullptr);
+ table_[index] = cls.raw();
+
// Add the vtable for this predefined class into the static vtable registry
// if it has not been setup yet.
cpp_vtable cls_vtable = cls.handle_vtable();
@@ -100,95 +156,141 @@
}
} else {
if (top_ == capacity_) {
- // Grow the capacity of the class table.
- // TODO(koda): Add ClassTable::Grow to share code.
-
-#ifndef PRODUCT
- // Wait for any marking tasks to complete. Allocation stats in the
- // marker rely on the class table size not changing.
- Thread* thread = Thread::Current();
- thread->heap()->WaitForMarkerTasks(thread);
-#endif
-
- intptr_t new_capacity = capacity_ + capacity_increment_;
- ClassAndSize* new_table = reinterpret_cast<ClassAndSize*>(
- malloc(new_capacity * sizeof(ClassAndSize))); // NOLINT
- memmove(new_table, table_, capacity_ * sizeof(ClassAndSize));
-#ifndef PRODUCT
- ClassHeapStats* new_stats_table = reinterpret_cast<ClassHeapStats*>(
- realloc(class_heap_stats_table_,
- new_capacity * sizeof(ClassHeapStats))); // NOLINT
-#endif
- for (intptr_t i = capacity_; i < new_capacity; i++) {
- new_table[i] = ClassAndSize(NULL, 0);
- NOT_IN_PRODUCT(new_stats_table[i].Initialize());
- }
- capacity_ = new_capacity;
- old_tables_->Add(table_);
- table_ = new_table; // TODO(koda): This should use atomics.
- NOT_IN_PRODUCT(class_heap_stats_table_ = new_stats_table);
+ const intptr_t new_capacity = capacity_ + kCapacityIncrement;
+ Grow(new_capacity);
}
ASSERT(top_ < capacity_);
- if (!Class::is_valid_id(top_)) {
- FATAL1("Fatal error in ClassTable::Register: invalid index %" Pd "\n",
- top_);
- }
cls.set_id(top_);
- table_[top_] = ClassAndSize(cls.raw());
+ table_[top_] = cls.raw();
top_++; // Increment next index.
}
+ ASSERT(expected_cid == cls.id());
+}
+
+intptr_t SharedClassTable::Register(intptr_t index, intptr_t size) {
+ if (!Class::is_valid_id(top_)) {
+ FATAL1("Fatal error in SharedClassTable::Register: invalid index %" Pd "\n",
+ top_);
+ }
+
+ ASSERT(Thread::Current()->IsMutatorThread());
+ if (index != kIllegalCid) {
+ // We are registring the size of a predefined class.
+ ASSERT(index > 0 && index < kNumPredefinedCids);
+ SetSizeAt(index, size);
+ return index;
+ } else {
+ if (top_ == capacity_) {
+ const intptr_t new_capacity = capacity_ + kCapacityIncrement;
+ Grow(new_capacity);
+ }
+ ASSERT(top_ < capacity_);
+ table_[top_] = size;
+ return top_++; // Increment next index.
+ }
}
void ClassTable::AllocateIndex(intptr_t index) {
+ // This is called by a snapshot reader.
+ shared_class_table_->AllocateIndex(index);
+ ASSERT(Class::is_valid_id(index));
+
if (index >= capacity_) {
- // Grow the capacity of the class table.
- // TODO(koda): Add ClassTable::Grow to share code.
-
-#ifndef PRODUCT
- // Wait for any marking tasks to complete. Allocation stats in the
- // marker rely on the class table size not changing.
- Thread* thread = Thread::Current();
- thread->heap()->WaitForMarkerTasks(thread);
-#endif
-
- intptr_t new_capacity = index + capacity_increment_;
- if (!Class::is_valid_id(index) || new_capacity < capacity_) {
- FATAL1("Fatal error in ClassTable::Register: invalid index %" Pd "\n",
- index);
- }
- ClassAndSize* new_table = reinterpret_cast<ClassAndSize*>(
- malloc(new_capacity * sizeof(ClassAndSize))); // NOLINT
- memmove(new_table, table_, capacity_ * sizeof(ClassAndSize));
-#ifndef PRODUCT
- ClassHeapStats* new_stats_table = reinterpret_cast<ClassHeapStats*>(
- realloc(class_heap_stats_table_,
- new_capacity * sizeof(ClassHeapStats))); // NOLINT
-#endif
- for (intptr_t i = capacity_; i < new_capacity; i++) {
- new_table[i] = ClassAndSize(NULL);
- NOT_IN_PRODUCT(new_stats_table[i].Initialize());
- }
- capacity_ = new_capacity;
- old_tables_->Add(table_);
- table_ = new_table; // TODO(koda): This should use atomics.
- NOT_IN_PRODUCT(class_heap_stats_table_ = new_stats_table);
- ASSERT(capacity_increment_ >= 1);
+ const intptr_t new_capacity = index + kCapacityIncrement;
+ Grow(new_capacity);
}
- ASSERT(table_[index].class_ == NULL);
+ ASSERT(table_[index] == nullptr);
+ if (index >= top_) {
+ top_ = index + 1;
+ }
+
+ ASSERT(top_ == shared_class_table_->top_);
+ ASSERT(capacity_ == shared_class_table_->capacity_);
+}
+
+void ClassTable::Grow(intptr_t new_capacity) {
+ ASSERT(new_capacity > capacity_);
+
+ auto new_table = static_cast<RawClass**>(
+ malloc(new_capacity * sizeof(RawClass*))); // NOLINT
+ memmove(new_table, table_, top_ * sizeof(RawClass*));
+ memset(new_table + top_, 0, (new_capacity - top_) * sizeof(RawClass*));
+ capacity_ = new_capacity;
+ old_class_tables_->Add(table_);
+ table_ = new_table; // TODO(koda): This should use atomics.
+}
+
+void SharedClassTable::AllocateIndex(intptr_t index) {
+ // This is called by a snapshot reader.
+ ASSERT(Class::is_valid_id(index));
+
+ if (index >= capacity_) {
+ const intptr_t new_capacity = index + kCapacityIncrement;
+ Grow(new_capacity);
+ }
+
+ ASSERT(table_[index] == 0);
if (index >= top_) {
top_ = index + 1;
}
}
+void SharedClassTable::Grow(intptr_t new_capacity) {
+ ASSERT(new_capacity >= capacity_);
+
+#ifndef PRODUCT
+ // Wait for any marking tasks to complete. Allocation stats in the
+ // marker rely on the class table size not changing.
+ Thread* thread = Thread::Current();
+ thread->heap()->WaitForMarkerTasks(thread);
+#endif
+
+ intptr_t* new_table = static_cast<intptr_t*>(
+ malloc(new_capacity * sizeof(intptr_t))); // NOLINT
+ memmove(new_table, table_, top_ * sizeof(intptr_t));
+ memset(new_table + top_, 0, (new_capacity - top_) * sizeof(intptr_t));
+#ifndef PRODUCT
+ auto new_stats_table = static_cast<ClassHeapStats*>(
+ realloc(class_heap_stats_table_,
+ new_capacity * sizeof(ClassHeapStats))); // NOLINT
+#endif
+ for (intptr_t i = capacity_; i < new_capacity; i++) {
+ new_table[i] = 0;
+ NOT_IN_PRODUCT(new_stats_table[i].Initialize());
+ }
+ capacity_ = new_capacity;
+ old_tables_->Add(table_);
+ table_ = new_table; // TODO(koda): This should use atomics.
+ NOT_IN_PRODUCT(class_heap_stats_table_ = new_stats_table);
+}
+
void ClassTable::Unregister(intptr_t index) {
- table_[index] = ClassAndSize(NULL);
+ shared_class_table_->Unregister(index);
+ table_[index] = nullptr;
+}
+
+void SharedClassTable::Unregister(intptr_t index) {
+ table_[index] = 0;
}
void ClassTable::Remap(intptr_t* old_to_new_cid) {
ASSERT(Thread::Current()->IsAtSafepoint());
- intptr_t num_cids = NumCids();
- ClassAndSize* cls_by_old_cid = new ClassAndSize[num_cids];
+ shared_class_table_->Remap(old_to_new_cid);
+
+ const intptr_t num_cids = NumCids();
+ auto cls_by_old_cid = new RawClass*[num_cids];
+ memmove(cls_by_old_cid, table_, sizeof(RawClass*) * num_cids);
+ for (intptr_t i = 0; i < num_cids; i++) {
+ table_[old_to_new_cid[i]] = cls_by_old_cid[i];
+ }
+ delete[] cls_by_old_cid;
+}
+
+void SharedClassTable::Remap(intptr_t* old_to_new_cid) {
+ ASSERT(Thread::Current()->IsAtSafepoint());
+ const intptr_t num_cids = NumCids();
+ intptr_t* cls_by_old_cid = new intptr_t[num_cids];
for (intptr_t i = 0; i < num_cids; i++) {
cls_by_old_cid[i] = table_[i];
}
@@ -202,7 +304,7 @@
ASSERT(visitor != NULL);
visitor->set_gc_root_type("class table");
for (intptr_t i = 0; i < top_; i++) {
- visitor->VisitPointer(reinterpret_cast<RawObject**>(&(table_[i].class_)));
+ visitor->VisitPointer(reinterpret_cast<RawObject**>(&(table_[i])));
}
visitor->clear_gc_root_type();
}
@@ -249,17 +351,11 @@
}
void ClassTable::SetAt(intptr_t index, RawClass* raw_cls) {
+ // This is called by snapshot reader and class finalizer.
ASSERT(index < capacity_);
- if (raw_cls == NULL) {
- table_[index] = ClassAndSize(raw_cls, 0);
- } else {
- // Ensure we never change size for a given cid from one non-zero size to
- // another non-zero size.
- const intptr_t old_size = table_[index].size_;
- const intptr_t new_size = Class::instance_size(raw_cls);
- ASSERT(old_size == 0 || old_size == new_size);
- table_[index] = ClassAndSize(raw_cls, new_size);
- }
+ const intptr_t size = raw_cls == nullptr ? 0 : Class::instance_size(raw_cls);
+ shared_class_table_->SetSizeAt(index, size);
+ table_[index] = raw_cls;
}
ClassAndSize::ClassAndSize(RawClass* clazz) : class_(clazz) {
@@ -437,32 +533,32 @@
obj->AddProperty64("bytesCurrent", bytes_current);
}
-void ClassTable::UpdateAllocatedOldGC(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateAllocatedOldGC(intptr_t cid, intptr_t size) {
ClassHeapStats* stats = PreliminaryStatsAt(cid);
ASSERT(stats != NULL);
ASSERT(size != 0);
stats->recent.AddOldGC(size);
}
-void ClassTable::UpdateAllocatedExternalNew(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateAllocatedExternalNew(intptr_t cid, intptr_t size) {
ClassHeapStats* stats = PreliminaryStatsAt(cid);
ASSERT(stats != NULL);
stats->recent.AddNewExternal(size);
}
-void ClassTable::UpdateAllocatedExternalOld(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateAllocatedExternalOld(intptr_t cid, intptr_t size) {
ClassHeapStats* stats = PreliminaryStatsAt(cid);
ASSERT(stats != NULL);
stats->recent.AddOldExternal(size);
}
-bool ClassTable::ShouldUpdateSizeForClassId(intptr_t cid) {
+bool SharedClassTable::ShouldUpdateSizeForClassId(intptr_t cid) {
return !RawObject::IsVariableSizeClassId(cid);
}
ClassHeapStats* ClassTable::StatsWithUpdatedSize(intptr_t cid) {
- if (!HasValidClassAt(cid) || (cid == kFreeListElement) ||
- (cid == kForwardingCorpse) || (cid == kSmiCid)) {
+ if (!HasValidClassAt(cid) || cid == kFreeListElement ||
+ cid == kForwardingCorpse || cid == kSmiCid) {
return NULL;
}
Class& cls = Class::Handle(At(cid));
@@ -470,48 +566,53 @@
// Not finalized.
return NULL;
}
+ return shared_class_table_->StatsWithUpdatedSize(cid, cls.instance_size());
+}
+
+ClassHeapStats* SharedClassTable::StatsWithUpdatedSize(intptr_t cid,
+ intptr_t size) {
ClassHeapStats* stats = PreliminaryStatsAt(cid);
if (ShouldUpdateSizeForClassId(cid)) {
- stats->UpdateSize(cls.instance_size());
+ stats->UpdateSize(size);
}
stats->Verify();
return stats;
}
-void ClassTable::ResetCountersOld() {
+void SharedClassTable::ResetCountersOld() {
for (intptr_t i = 0; i < top_; i++) {
class_heap_stats_table_[i].ResetAtOldGC();
}
}
-void ClassTable::ResetCountersNew() {
+void SharedClassTable::ResetCountersNew() {
for (intptr_t i = 0; i < top_; i++) {
class_heap_stats_table_[i].ResetAtNewGC();
}
}
-void ClassTable::UpdatePromoted() {
+void SharedClassTable::UpdatePromoted() {
for (intptr_t i = 0; i < top_; i++) {
class_heap_stats_table_[i].UpdatePromotedAfterNewGC();
}
}
-intptr_t ClassTable::ClassOffsetFor(intptr_t cid) {
+intptr_t SharedClassTable::ClassOffsetFor(intptr_t cid) {
return cid * sizeof(ClassHeapStats); // NOLINT
}
-intptr_t ClassTable::NewSpaceCounterOffsetFor(intptr_t cid) {
+intptr_t SharedClassTable::NewSpaceCounterOffsetFor(intptr_t cid) {
const intptr_t class_offset = ClassOffsetFor(cid);
const intptr_t count_field_offset =
ClassHeapStats::allocated_since_gc_new_space_offset();
return class_offset + count_field_offset;
}
-intptr_t ClassTable::StateOffsetFor(intptr_t cid) {
+intptr_t SharedClassTable::StateOffsetFor(intptr_t cid) {
return ClassOffsetFor(cid) + ClassHeapStats::state_offset();
}
-intptr_t ClassTable::NewSpaceSizeOffsetFor(intptr_t cid) {
+intptr_t SharedClassTable::NewSpaceSizeOffsetFor(intptr_t cid) {
const uword class_offset = ClassOffsetFor(cid);
const uword size_field_offset =
ClassHeapStats::allocated_size_since_gc_new_space_offset();
@@ -563,16 +664,21 @@
}
}
-void ClassTable::ResetAllocationAccumulators() {
+void SharedClassTable::ResetAllocationAccumulators() {
for (intptr_t i = 1; i < top_; i++) {
- ClassHeapStats* stats = StatsWithUpdatedSize(i);
- if (stats != NULL) {
- stats->ResetAccumulator();
+ if (HasValidClassAt(i)) {
+ const intptr_t size = table_[i];
+ ClassHeapStats* stats = StatsWithUpdatedSize(i, size);
+ if (stats != NULL) {
+ stats->ResetAccumulator();
+ }
}
}
}
-void ClassTable::UpdateLiveOld(intptr_t cid, intptr_t size, intptr_t count) {
+void SharedClassTable::UpdateLiveOld(intptr_t cid,
+ intptr_t size,
+ intptr_t count) {
ClassHeapStats* stats = PreliminaryStatsAt(cid);
ASSERT(stats != NULL);
ASSERT(size >= 0);
@@ -580,28 +686,28 @@
stats->post_gc.AddOld(size, count);
}
-void ClassTable::UpdateLiveNew(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateLiveNew(intptr_t cid, intptr_t size) {
ClassHeapStats* stats = PreliminaryStatsAt(cid);
ASSERT(stats != NULL);
ASSERT(size >= 0);
stats->post_gc.AddNew(size);
}
-void ClassTable::UpdateLiveNewGC(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateLiveNewGC(intptr_t cid, intptr_t size) {
ClassHeapStats* stats = PreliminaryStatsAt(cid);
ASSERT(stats != NULL);
ASSERT(size >= 0);
stats->post_gc.AddNewGC(size);
}
-void ClassTable::UpdateLiveOldExternal(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateLiveOldExternal(intptr_t cid, intptr_t size) {
ClassHeapStats* stats = PreliminaryStatsAt(cid);
ASSERT(stats != NULL);
ASSERT(size >= 0);
stats->post_gc.AddOldExternal(size);
}
-void ClassTable::UpdateLiveNewExternal(intptr_t cid, intptr_t size) {
+void SharedClassTable::UpdateLiveNewExternal(intptr_t cid, intptr_t size) {
ClassHeapStats* stats = PreliminaryStatsAt(cid);
ASSERT(stats != NULL);
ASSERT(size >= 0);
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index 3de2d46..19b13ce 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -7,7 +7,9 @@
#include "platform/assert.h"
#include "platform/atomic.h"
+
#include "vm/bitfield.h"
+#include "vm/class_id.h"
#include "vm/globals.h"
namespace dart {
@@ -15,6 +17,8 @@
class Class;
class ClassStats;
class ClassTable;
+class Isolate;
+class IsolateGroup;
class JSONArray;
class JSONObject;
class JSONStream;
@@ -185,21 +189,180 @@
};
#endif // !PRODUCT
+// Registry of all known classes and their sizes.
+//
+// The GC will only need the information in this shared class table to scan
+// object pointers.
+class SharedClassTable {
+ public:
+ SharedClassTable();
+ ~SharedClassTable();
+
+ // Thread-safe.
+ intptr_t SizeAt(intptr_t index) const {
+ ASSERT(IsValidIndex(index));
+ return table_[index];
+ }
+
+ bool HasValidClassAt(intptr_t index) const {
+ ASSERT(IsValidIndex(index));
+ ASSERT(table_[index] >= 0);
+ return table_[index] != 0;
+ }
+
+ void SetSizeAt(intptr_t index, intptr_t size) {
+ ASSERT(IsValidIndex(index));
+ // Ensure we never change size for a given cid from one non-zero size to
+ // another non-zero size.
+ RELEASE_ASSERT(table_[index] == 0 || table_[index] == size);
+ table_[index] = size;
+ }
+
+ bool IsValidIndex(intptr_t index) const { return index > 0 && index < top_; }
+
+ intptr_t NumCids() const { return top_; }
+ intptr_t Capacity() const { return capacity_; }
+
+ // Used to drop recently added classes.
+ void SetNumCids(intptr_t num_cids) {
+ ASSERT(num_cids <= top_);
+ top_ = num_cids;
+ }
+
+ // Called whenever a old GC occurs.
+ void ResetCountersOld();
+ // Called whenever a new GC occurs.
+ void ResetCountersNew();
+ // Called immediately after a new GC.
+ void UpdatePromoted();
+
+#if !defined(PRODUCT)
+ // Called whenever a class is allocated in the runtime.
+ void UpdateAllocatedNew(intptr_t cid, intptr_t size) {
+ ClassHeapStats* stats = PreliminaryStatsAt(cid);
+ ASSERT(stats != NULL);
+ ASSERT(size != 0);
+ stats->recent.AddNew(size);
+ }
+ void UpdateAllocatedOld(intptr_t cid, intptr_t size) {
+ ClassHeapStats* stats = PreliminaryStatsAt(cid);
+ ASSERT(stats != NULL);
+ ASSERT(size != 0);
+ stats->recent.AddOld(size);
+ }
+ void UpdateAllocatedOldGC(intptr_t cid, intptr_t size);
+ void UpdateAllocatedExternalNew(intptr_t cid, intptr_t size);
+ void UpdateAllocatedExternalOld(intptr_t cid, intptr_t size);
+
+ void ResetAllocationAccumulators();
+
+ void SetTraceAllocationFor(intptr_t cid, bool trace) {
+ ClassHeapStats* stats = PreliminaryStatsAt(cid);
+ stats->set_trace_allocation(trace);
+ }
+ bool TraceAllocationFor(intptr_t cid) {
+ ClassHeapStats* stats = PreliminaryStatsAt(cid);
+ return stats->trace_allocation();
+ }
+
+ ClassHeapStats* StatsWithUpdatedSize(intptr_t cid, intptr_t size);
+#endif // !defined(PRODUCT)
+
+ // Returns the newly allocated cid.
+ //
+ // [index] is kIllegalCid or a predefined cid.
+ intptr_t Register(intptr_t index, intptr_t size);
+ void AllocateIndex(intptr_t index);
+ void Unregister(intptr_t index);
+
+ void Remap(intptr_t* old_to_new_cids);
+
+ void FreeOldTables();
+
+ // Used by the generated code.
+#ifndef PRODUCT
+ static intptr_t class_heap_stats_table_offset() {
+ return OFFSET_OF(SharedClassTable, class_heap_stats_table_);
+ }
+#endif
+
+ // Used by the generated code.
+ static intptr_t ClassOffsetFor(intptr_t cid);
+
+ // Used by the generated code.
+ static intptr_t NewSpaceCounterOffsetFor(intptr_t cid);
+
+ // Used by the generated code.
+ static intptr_t StateOffsetFor(intptr_t cid);
+
+ // Used by the generated code.
+ static intptr_t NewSpaceSizeOffsetFor(intptr_t cid);
+
+ static const int kInitialCapacity = 512;
+ static const int kCapacityIncrement = 256;
+
+ private:
+ friend class ClassTable;
+ friend class GCMarker;
+ friend class MarkingWeakVisitor;
+ friend class Scavenger;
+ friend class ScavengerWeakVisitor;
+ friend class ClassHeapStatsTestHelper;
+ friend class HeapTestsHelper;
+
+ static bool ShouldUpdateSizeForClassId(intptr_t cid);
+
+#ifndef PRODUCT
+ // May not have updated size for variable size classes.
+ ClassHeapStats* PreliminaryStatsAt(intptr_t cid) {
+ ASSERT(cid > 0);
+ ASSERT(cid < top_);
+ return &class_heap_stats_table_[cid];
+ }
+ void UpdateLiveOld(intptr_t cid, intptr_t size, intptr_t count = 1);
+ void UpdateLiveNew(intptr_t cid, intptr_t size);
+ void UpdateLiveNewGC(intptr_t cid, intptr_t size);
+ void UpdateLiveOldExternal(intptr_t cid, intptr_t size);
+ void UpdateLiveNewExternal(intptr_t cid, intptr_t size);
+
+ ClassHeapStats* class_heap_stats_table_ = nullptr;
+#endif // !PRODUCT
+
+ void Grow(intptr_t new_capacity);
+
+ intptr_t top_;
+ intptr_t capacity_;
+
+ // Copy-on-write is used for table_, with old copies stored in old_tables_.
+ intptr_t* table_; // Maps the cid to the instance size.
+ MallocGrowableArray<intptr_t*>* old_tables_;
+
+ DISALLOW_COPY_AND_ASSIGN(SharedClassTable);
+};
+
class ClassTable {
public:
- ClassTable();
+ explicit ClassTable(SharedClassTable* shared_class_table_);
+
// Creates a shallow copy of the original class table for some read-only
// access, without support for stats data.
- explicit ClassTable(ClassTable* original);
+ ClassTable(ClassTable* original, SharedClassTable* shared_class_table);
~ClassTable();
+ SharedClassTable* shared_class_table() const { return shared_class_table_; }
+
void CopyBeforeHotReload(ClassAndSize** copy, intptr_t* copy_num_cids) {
// The [IsolateReloadContext] will need to maintain a copy of the old class
// table until instances have been morphed.
- const intptr_t bytes = sizeof(ClassAndSize) * NumCids();
- *copy_num_cids = NumCids();
- *copy = static_cast<ClassAndSize*>(malloc(bytes));
- memmove(*copy, table_, bytes);
+ const intptr_t num_cids = NumCids();
+ const intptr_t bytes = sizeof(ClassAndSize) * num_cids;
+ auto class_and_size = static_cast<ClassAndSize*>(malloc(bytes));
+ for (intptr_t i = 0; i < num_cids; ++i) {
+ class_and_size[i] =
+ ClassAndSize(table_[i], shared_class_table_->table_[i]);
+ }
+ *copy_num_cids = num_cids;
+ *copy = class_and_size;
}
void ResetBeforeHotReload() {
@@ -211,7 +374,7 @@
// to find the super class (e.g. `cls.SuperClass` will cause us to come
// here).
for (intptr_t i = 0; i < top_; ++i) {
- table_[i].size_ = 0;
+ shared_class_table_->table_[i] = 0;
}
}
@@ -222,7 +385,10 @@
// return, so we restore size information for all classes.
if (is_rollback) {
SetNumCids(num_old_cids);
- memmove(table_, old_table, num_old_cids * sizeof(ClassAndSize));
+ for (intptr_t i = 0; i < num_old_cids; ++i) {
+ shared_class_table_->table_[i] = old_table[i].size_;
+ table_[i] = old_table[i].class_;
+ }
} else {
CopySizesFromClassObjects();
}
@@ -237,43 +403,37 @@
// Thread-safe.
RawClass* At(intptr_t index) const {
ASSERT(IsValidIndex(index));
- return table_[index].class_;
+ return table_[index];
}
intptr_t SizeAt(intptr_t index) const {
- ASSERT(IsValidIndex(index));
- return table_[index].size_;
- }
-
- ClassAndSize PairAt(intptr_t index) const {
- ASSERT(IsValidIndex(index));
- return table_[index];
+ return shared_class_table_->SizeAt(index);
}
void SetAt(intptr_t index, RawClass* raw_cls);
bool IsValidIndex(intptr_t index) const {
- return (index > 0) && (index < top_);
+ return shared_class_table_->IsValidIndex(index);
}
bool HasValidClassAt(intptr_t index) const {
ASSERT(IsValidIndex(index));
- return table_[index].class_ != NULL;
+ return table_[index] != nullptr;
}
- intptr_t NumCids() const { return top_; }
- intptr_t Capacity() const { return capacity_; }
+ intptr_t NumCids() const { return shared_class_table_->NumCids(); }
+ intptr_t Capacity() const { return shared_class_table_->Capacity(); }
// Used to drop recently added classes.
void SetNumCids(intptr_t num_cids) {
+ shared_class_table_->SetNumCids(num_cids);
+
ASSERT(num_cids <= top_);
top_ = num_cids;
}
void Register(const Class& cls);
-
void AllocateIndex(intptr_t index);
-
void Unregister(intptr_t index);
void Remap(intptr_t* old_to_new_cids);
@@ -293,7 +453,9 @@
static intptr_t table_offset() { return OFFSET_OF(ClassTable, table_); }
// Used by the generated code.
- static intptr_t ClassOffsetFor(intptr_t cid);
+ static intptr_t shared_class_table_offset() {
+ return OFFSET_OF(ClassTable, shared_class_table_);
+ }
#ifndef PRODUCT
// Describes layout of heap stats for code generation. See offset_extractor.cc
@@ -304,76 +466,19 @@
};
#endif
-#if defined(ARCH_IS_32_BIT)
- static constexpr int kSizeOfClassPairLog2 = 3;
-#else
- static constexpr int kSizeOfClassPairLog2 = 4;
-#endif
- static_assert(
- (1 << kSizeOfClassPairLog2) == sizeof(ClassAndSize),
- "Mismatch between sizeof(ClassAndSize) and kSizeOfClassPairLog2");
-
#ifndef PRODUCT
- // Called whenever a class is allocated in the runtime.
- void UpdateAllocatedNew(intptr_t cid, intptr_t size) {
- ClassHeapStats* stats = PreliminaryStatsAt(cid);
- ASSERT(stats != NULL);
- ASSERT(size != 0);
- stats->recent.AddNew(size);
- }
- void UpdateAllocatedOld(intptr_t cid, intptr_t size) {
- ClassHeapStats* stats = PreliminaryStatsAt(cid);
- ASSERT(stats != NULL);
- ASSERT(size != 0);
- stats->recent.AddOld(size);
- }
- void UpdateAllocatedOldGC(intptr_t cid, intptr_t size);
- void UpdateAllocatedExternalNew(intptr_t cid, intptr_t size);
- void UpdateAllocatedExternalOld(intptr_t cid, intptr_t size);
-
- // Called whenever a old GC occurs.
- void ResetCountersOld();
- // Called whenever a new GC occurs.
- void ResetCountersNew();
- // Called immediately after a new GC.
- void UpdatePromoted();
-
- // Used by the generated code.
- static intptr_t class_heap_stats_table_offset() {
- return OFFSET_OF(ClassTable, class_heap_stats_table_);
- }
-
- // Used by the generated code.
- static intptr_t NewSpaceCounterOffsetFor(intptr_t cid);
-
- // Used by the generated code.
- static intptr_t StateOffsetFor(intptr_t cid);
-
- // Used by the generated code.
- static intptr_t NewSpaceSizeOffsetFor(intptr_t cid);
ClassHeapStats* StatsWithUpdatedSize(intptr_t cid);
void AllocationProfilePrintJSON(JSONStream* stream, bool internal);
- void ResetAllocationAccumulators();
void PrintToJSONObject(JSONObject* object);
-
- void SetTraceAllocationFor(intptr_t cid, bool trace) {
- ClassHeapStats* stats = PreliminaryStatsAt(cid);
- stats->set_trace_allocation(trace);
- }
- bool TraceAllocationFor(intptr_t cid) {
- ClassHeapStats* stats = PreliminaryStatsAt(cid);
- return stats->trace_allocation();
- }
#endif // !PRODUCT
void AddOldTable(ClassAndSize* old_table);
// Deallocates table copies. Do not call during concurrent access to table.
void FreeOldTables();
-
private:
friend class GCMarker;
friend class MarkingWeakVisitor;
@@ -381,33 +486,19 @@
friend class ScavengerWeakVisitor;
friend class ClassHeapStatsTestHelper;
friend class HeapTestsHelper;
- static const int initial_capacity_ = 512;
- static const int capacity_increment_ = 256;
+ static const int kInitialCapacity = SharedClassTable::kInitialCapacity;
+ static const int kCapacityIncrement = SharedClassTable::kCapacityIncrement;
- static bool ShouldUpdateSizeForClassId(intptr_t cid);
+ void Grow(intptr_t index);
intptr_t top_;
intptr_t capacity_;
// Copy-on-write is used for table_, with old copies stored in old_tables_.
- ClassAndSize* table_;
+ RawClass** table_;
MallocGrowableArray<ClassAndSize*>* old_tables_;
-
-#ifndef PRODUCT
- ClassHeapStats* class_heap_stats_table_;
-
- // May not have updated size for variable size classes.
- ClassHeapStats* PreliminaryStatsAt(intptr_t cid) {
- ASSERT(cid > 0);
- ASSERT(cid < top_);
- return &class_heap_stats_table_[cid];
- }
- void UpdateLiveOld(intptr_t cid, intptr_t size, intptr_t count = 1);
- void UpdateLiveNew(intptr_t cid, intptr_t size);
- void UpdateLiveNewGC(intptr_t cid, intptr_t size);
- void UpdateLiveOldExternal(intptr_t cid, intptr_t size);
- void UpdateLiveNewExternal(intptr_t cid, intptr_t size);
-#endif // !PRODUCT
+ MallocGrowableArray<RawClass**>* old_class_tables_;
+ SharedClassTable* shared_class_table_;
DISALLOW_COPY_AND_ASSIGN(ClassTable);
};
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 1939554..a5958d6 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -3305,6 +3305,19 @@
}
void ReadFill(Deserializer* d) {}
+
+ void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
+ const Class& mint_cls =
+ Class::Handle(zone, Isolate::Current()->object_store()->mint_class());
+ mint_cls.set_constants(Object::empty_array());
+ Object& number = Object::Handle(zone);
+ for (intptr_t i = start_index_; i < stop_index_; i++) {
+ number = refs.At(i);
+ if (number.IsMint() && number.IsCanonical()) {
+ mint_cls.InsertCanonicalMint(zone, Mint::Cast(number));
+ }
+ }
+ }
};
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -4086,6 +4099,159 @@
};
#if !defined(DART_PRECOMPILED_RUNTIME)
+class OneByteStringSerializationCluster : public SerializationCluster {
+ public:
+ OneByteStringSerializationCluster() : SerializationCluster("OneByteString") {}
+ ~OneByteStringSerializationCluster() {}
+
+ void Trace(Serializer* s, RawObject* object) {
+ RawOneByteString* str = reinterpret_cast<RawOneByteString*>(object);
+ objects_.Add(str);
+ }
+
+ void WriteAlloc(Serializer* s) {
+ s->WriteCid(kOneByteStringCid);
+ intptr_t count = objects_.length();
+ s->WriteUnsigned(count);
+ for (intptr_t i = 0; i < count; i++) {
+ RawOneByteString* str = objects_[i];
+ s->AssignRef(str);
+ AutoTraceObject(str);
+ intptr_t length = Smi::Value(str->ptr()->length_);
+ s->WriteUnsigned(length);
+ }
+ }
+
+ void WriteFill(Serializer* s) {
+ intptr_t count = objects_.length();
+ for (intptr_t i = 0; i < count; i++) {
+ RawOneByteString* str = objects_[i];
+ AutoTraceObject(str);
+ intptr_t length = Smi::Value(str->ptr()->length_);
+ s->WriteUnsigned(length);
+ s->Write<bool>(str->IsCanonical());
+ intptr_t hash = String::GetCachedHash(str);
+ s->Write<int32_t>(hash);
+ s->WriteBytes(str->ptr()->data(), length);
+ }
+ }
+
+ private:
+ GrowableArray<RawOneByteString*> objects_;
+};
+#endif // !DART_PRECOMPILED_RUNTIME
+
+class OneByteStringDeserializationCluster : public DeserializationCluster {
+ public:
+ OneByteStringDeserializationCluster() {}
+ ~OneByteStringDeserializationCluster() {}
+
+ void ReadAlloc(Deserializer* d) {
+ start_index_ = d->next_index();
+ PageSpace* old_space = d->heap()->old_space();
+ intptr_t count = d->ReadUnsigned();
+ for (intptr_t i = 0; i < count; i++) {
+ intptr_t length = d->ReadUnsigned();
+ d->AssignRef(AllocateUninitialized(old_space,
+ OneByteString::InstanceSize(length)));
+ }
+ stop_index_ = d->next_index();
+ }
+
+ void ReadFill(Deserializer* d) {
+ for (intptr_t id = start_index_; id < stop_index_; id++) {
+ RawOneByteString* str = reinterpret_cast<RawOneByteString*>(d->Ref(id));
+ intptr_t length = d->ReadUnsigned();
+ bool is_canonical = d->Read<bool>();
+ Deserializer::InitializeHeader(str, kOneByteStringCid,
+ OneByteString::InstanceSize(length),
+ is_canonical);
+ str->ptr()->length_ = Smi::New(length);
+ String::SetCachedHash(str, d->Read<int32_t>());
+ for (intptr_t j = 0; j < length; j++) {
+ str->ptr()->data()[j] = d->Read<uint8_t>();
+ }
+ }
+ }
+};
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+class TwoByteStringSerializationCluster : public SerializationCluster {
+ public:
+ TwoByteStringSerializationCluster() : SerializationCluster("TwoByteString") {}
+ ~TwoByteStringSerializationCluster() {}
+
+ void Trace(Serializer* s, RawObject* object) {
+ RawTwoByteString* str = reinterpret_cast<RawTwoByteString*>(object);
+ objects_.Add(str);
+ }
+
+ void WriteAlloc(Serializer* s) {
+ s->WriteCid(kTwoByteStringCid);
+ intptr_t count = objects_.length();
+ s->WriteUnsigned(count);
+ for (intptr_t i = 0; i < count; i++) {
+ RawTwoByteString* str = objects_[i];
+ s->AssignRef(str);
+ AutoTraceObject(str);
+ intptr_t length = Smi::Value(str->ptr()->length_);
+ s->WriteUnsigned(length);
+ }
+ }
+
+ void WriteFill(Serializer* s) {
+ intptr_t count = objects_.length();
+ for (intptr_t i = 0; i < count; i++) {
+ RawTwoByteString* str = objects_[i];
+ AutoTraceObject(str);
+ intptr_t length = Smi::Value(str->ptr()->length_);
+ s->WriteUnsigned(length);
+ s->Write<bool>(str->IsCanonical());
+ intptr_t hash = String::GetCachedHash(str);
+ s->Write<int32_t>(hash);
+ s->WriteBytes(reinterpret_cast<uint8_t*>(str->ptr()->data()), length * 2);
+ }
+ }
+
+ private:
+ GrowableArray<RawTwoByteString*> objects_;
+};
+#endif // !DART_PRECOMPILED_RUNTIME
+
+class TwoByteStringDeserializationCluster : public DeserializationCluster {
+ public:
+ TwoByteStringDeserializationCluster() {}
+ ~TwoByteStringDeserializationCluster() {}
+
+ void ReadAlloc(Deserializer* d) {
+ start_index_ = d->next_index();
+ PageSpace* old_space = d->heap()->old_space();
+ intptr_t count = d->ReadUnsigned();
+ for (intptr_t i = 0; i < count; i++) {
+ intptr_t length = d->ReadUnsigned();
+ d->AssignRef(AllocateUninitialized(old_space,
+ TwoByteString::InstanceSize(length)));
+ }
+ stop_index_ = d->next_index();
+ }
+
+ void ReadFill(Deserializer* d) {
+ for (intptr_t id = start_index_; id < stop_index_; id++) {
+ RawTwoByteString* str = reinterpret_cast<RawTwoByteString*>(d->Ref(id));
+ intptr_t length = d->ReadUnsigned();
+ bool is_canonical = d->Read<bool>();
+ Deserializer::InitializeHeader(str, kTwoByteStringCid,
+ TwoByteString::InstanceSize(length),
+ is_canonical);
+ str->ptr()->length_ = Smi::New(length);
+ String::SetCachedHash(str, d->Read<int32_t>());
+ uint8_t* cdata = reinterpret_cast<uint8_t*>(str->ptr()->data());
+ d->ReadBytes(cdata, length * 2);
+ }
+ }
+};
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
class FakeSerializationCluster : public SerializationCluster {
public:
FakeSerializationCluster(const char* name, intptr_t size)
@@ -4205,10 +4371,16 @@
if (Snapshot::IncludesCode(kind_)) {
switch (cid) {
+ case kPcDescriptorsCid:
+ return new (Z) RODataSerializationCluster("(RO)PcDescriptors", cid);
case kCodeSourceMapCid:
return new (Z) RODataSerializationCluster("(RO)CodeSourceMap", cid);
case kStackMapCid:
return new (Z) RODataSerializationCluster("(RO)StackMap", cid);
+ case kOneByteStringCid:
+ return new (Z) RODataSerializationCluster("(RO)OneByteString", cid);
+ case kTwoByteStringCid:
+ return new (Z) RODataSerializationCluster("(RO)TwoByteString", cid);
}
}
@@ -4247,8 +4419,6 @@
#endif // !DART_PRECOMPILED_RUNTIME
case kObjectPoolCid:
return new (Z) ObjectPoolSerializationCluster();
- case kPcDescriptorsCid:
- return new (Z) RODataSerializationCluster("(RO)PcDescriptors", cid);
case kExceptionHandlersCid:
return new (Z) ExceptionHandlersSerializationCluster();
case kContextCid:
@@ -4298,9 +4468,9 @@
case kImmutableArrayCid:
return new (Z) ArraySerializationCluster(kImmutableArrayCid);
case kOneByteStringCid:
- return new (Z) RODataSerializationCluster("(RO)OneByteString", cid);
+ return new (Z) OneByteStringSerializationCluster();
case kTwoByteStringCid:
- return new (Z) RODataSerializationCluster("(RO)TwoByteString", cid);
+ return new (Z) TwoByteStringSerializationCluster();
default:
break;
}
@@ -4794,15 +4964,17 @@
zone_(thread->zone()),
kind_(kind),
stream_(buffer, size),
- image_reader_(nullptr),
- refs_(nullptr),
+ image_reader_(NULL),
+ refs_(NULL),
next_ref_index_(1),
- clusters_(nullptr) {
- ASSERT((instructions_buffer != nullptr) || !Snapshot::IncludesCode(kind));
- ASSERT(data_buffer != nullptr);
- image_reader_ =
- new (zone_) ImageReader(data_buffer, instructions_buffer,
- shared_data_buffer, shared_instructions_buffer);
+ clusters_(NULL) {
+ if (Snapshot::IncludesCode(kind)) {
+ ASSERT(instructions_buffer != NULL);
+ ASSERT(data_buffer != NULL);
+ image_reader_ =
+ new (zone_) ImageReader(data_buffer, instructions_buffer,
+ shared_data_buffer, shared_instructions_buffer);
+ }
stream_.SetPosition(offset);
}
@@ -4915,14 +5087,25 @@
return new (Z) ArrayDeserializationCluster(kArrayCid);
case kImmutableArrayCid:
return new (Z) ArrayDeserializationCluster(kImmutableArrayCid);
- case kOneByteStringCid:
- case kTwoByteStringCid:
- return new (Z) RODataDeserializationCluster();
+ case kOneByteStringCid: {
+ if (Snapshot::IncludesCode(kind_)) {
+ return new (Z) RODataDeserializationCluster();
+ } else {
+ return new (Z) OneByteStringDeserializationCluster();
+ }
+ }
+ case kTwoByteStringCid: {
+ if (Snapshot::IncludesCode(kind_)) {
+ return new (Z) RODataDeserializationCluster();
+ } else {
+ return new (Z) TwoByteStringDeserializationCluster();
+ }
+ }
default:
break;
}
FATAL1("No cluster defined for cid %" Pd, cid);
- return nullptr;
+ return NULL;
}
RawApiError* Deserializer::VerifyImageAlignment() {
@@ -5309,8 +5492,7 @@
intptr_t FullSnapshotWriter::WriteVMSnapshot() {
TIMELINE_DURATION(thread(), Isolate, "WriteVMSnapshot");
- ASSERT(vm_snapshot_data_buffer_ != nullptr);
- ASSERT(vm_image_writer_ != nullptr);
+ ASSERT(vm_snapshot_data_buffer_ != NULL);
Serializer serializer(thread(), kind_, vm_snapshot_data_buffer_, alloc_,
kInitialSize, vm_image_writer_, /*vm=*/true,
profile_writer_);
@@ -5327,12 +5509,14 @@
serializer.FillHeader(serializer.kind());
clustered_vm_size_ = serializer.bytes_written();
- vm_image_writer_->SetProfileWriter(profile_writer_);
- vm_image_writer_->Write(serializer.stream(), true);
- mapped_data_size_ += vm_image_writer_->data_size();
- mapped_text_size_ += vm_image_writer_->text_size();
- vm_image_writer_->ResetOffsets();
- vm_image_writer_->ClearProfileWriter();
+ if (Snapshot::IncludesCode(kind_)) {
+ vm_image_writer_->SetProfileWriter(profile_writer_);
+ vm_image_writer_->Write(serializer.stream(), true);
+ mapped_data_size_ += vm_image_writer_->data_size();
+ mapped_text_size_ += vm_image_writer_->text_size();
+ vm_image_writer_->ResetOffsets();
+ vm_image_writer_->ClearProfileWriter();
+ }
// The clustered part + the direct mapped data part.
vm_isolate_snapshot_size_ = serializer.bytes_written();
@@ -5342,13 +5526,11 @@
void FullSnapshotWriter::WriteIsolateSnapshot(intptr_t num_base_objects) {
TIMELINE_DURATION(thread(), Isolate, "WriteIsolateSnapshot");
- ASSERT(isolate_snapshot_data_buffer_ != nullptr);
- ASSERT(isolate_image_writer_ != nullptr);
Serializer serializer(thread(), kind_, isolate_snapshot_data_buffer_, alloc_,
kInitialSize, isolate_image_writer_, /*vm=*/false,
profile_writer_);
ObjectStore* object_store = isolate()->object_store();
- ASSERT(object_store != nullptr);
+ ASSERT(object_store != NULL);
serializer.ReserveHeader();
serializer.WriteVersionAndFeatures(false);
@@ -5358,16 +5540,18 @@
serializer.FillHeader(serializer.kind());
clustered_isolate_size_ = serializer.bytes_written();
- isolate_image_writer_->SetProfileWriter(profile_writer_);
- isolate_image_writer_->Write(serializer.stream(), false);
+ if (Snapshot::IncludesCode(kind_)) {
+ isolate_image_writer_->SetProfileWriter(profile_writer_);
+ isolate_image_writer_->Write(serializer.stream(), false);
#if defined(DART_PRECOMPILER)
- isolate_image_writer_->DumpStatistics();
+ isolate_image_writer_->DumpStatistics();
#endif
- mapped_data_size_ += isolate_image_writer_->data_size();
- mapped_text_size_ += isolate_image_writer_->text_size();
- isolate_image_writer_->ResetOffsets();
- isolate_image_writer_->ClearProfileWriter();
+ mapped_data_size_ += isolate_image_writer_->data_size();
+ mapped_text_size_ += isolate_image_writer_->text_size();
+ isolate_image_writer_->ResetOffsets();
+ isolate_image_writer_->ClearProfileWriter();
+ }
// The clustered part + the direct mapped data part.
isolate_snapshot_size_ = serializer.bytes_written();
@@ -5488,11 +5672,11 @@
return api_error;
}
- ASSERT(data_image_ != nullptr);
- thread_->isolate()->SetupImagePage(data_image_,
- /* is_executable */ false);
if (Snapshot::IncludesCode(kind_)) {
- ASSERT(instructions_image_ != nullptr);
+ ASSERT(data_image_ != NULL);
+ thread_->isolate()->SetupImagePage(data_image_,
+ /* is_executable */ false);
+ ASSERT(instructions_image_ != NULL);
thread_->isolate()->SetupImagePage(instructions_image_,
/* is_executable */ true);
}
@@ -5519,18 +5703,18 @@
return api_error;
}
- ASSERT(data_image_ != nullptr);
- thread_->isolate()->SetupImagePage(data_image_,
- /* is_executable */ false);
if (Snapshot::IncludesCode(kind_)) {
- ASSERT(instructions_image_ != nullptr);
+ ASSERT(data_image_ != NULL);
+ thread_->isolate()->SetupImagePage(data_image_,
+ /* is_executable */ false);
+ ASSERT(instructions_image_ != NULL);
thread_->isolate()->SetupImagePage(instructions_image_,
/* is_executable */ true);
- if (shared_data_image_ != nullptr) {
+ if (shared_data_image_ != NULL) {
thread_->isolate()->SetupImagePage(shared_data_image_,
/* is_executable */ false);
}
- if (shared_instructions_image_ != nullptr) {
+ if (shared_instructions_image_ != NULL) {
thread_->isolate()->SetupImagePage(shared_instructions_image_,
/* is_executable */ true);
}
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index f62744a..ad04810 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -635,7 +635,6 @@
ReAlloc alloc_;
intptr_t vm_isolate_snapshot_size_;
intptr_t isolate_snapshot_size_;
- ForwardList* forward_list_;
ImageWriter* vm_image_writer_;
ImageWriter* isolate_image_writer_;
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm.cc b/runtime/vm/compiler/asm_intrinsifier_arm.cc
index bb2cb37..ae216fa 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm.cc
@@ -1607,7 +1607,7 @@
__ Ret();
__ Bind(&use_declaration_type);
- __ LoadClassById(R2, R1); // Overwrites R1.
+ __ LoadClassById(R2, R1);
__ ldrh(R3, FieldAddress(R2, target::Class::num_type_arguments_offset()));
__ CompareImmediate(R3, 0);
__ b(normal_ir_body, NE);
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
index 1551dfc..d96d9fc 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
@@ -1668,7 +1668,7 @@
__ ret();
__ Bind(&use_declaration_type);
- __ LoadClassById(R2, R1); // Overwrites R1.
+ __ LoadClassById(R2, R1);
__ ldr(R3, FieldAddress(R2, target::Class::num_type_arguments_offset()),
kHalfword);
__ CompareImmediate(R3, 0);
@@ -1704,7 +1704,7 @@
// Objects have the same class and neither is a closure.
// Check if there are no type arguments. In this case we can return true.
// Otherwise fall through into the runtime to handle comparison.
- __ LoadClassById(R3, R1); // Overwrites R1.
+ __ LoadClassById(R3, R1);
__ ldr(R3, FieldAddress(R3, target::Class::num_type_arguments_offset()),
kHalfword);
__ CompareImmediate(R3, 0);
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index 0e6e40c..6958b22 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -1984,12 +1984,13 @@
void Assembler::LoadClassById(Register result, Register class_id) {
ASSERT(result != class_id);
+
+ const intptr_t table_offset = target::Isolate::class_table_offset() +
+ target::ClassTable::table_offset();
+
LoadIsolate(result);
- const intptr_t offset = target::Isolate::class_table_offset() +
- target::ClassTable::table_offset();
- LoadFromOffset(kWord, result, result, offset);
- ldr(result,
- Address(result, class_id, LSL, target::ClassTable::kSizeOfClassPairLog2));
+ LoadFromOffset(kWord, result, result, table_offset);
+ ldr(result, Address(result, class_id, LSL, target::kWordSizeLog2));
}
void Assembler::CompareClassId(Register object,
@@ -3511,10 +3512,16 @@
ASSERT(dest != kNoRegister);
ASSERT(dest != TMP);
ASSERT(cid > 0);
+
+ const intptr_t shared_table_offset =
+ target::Isolate::class_table_offset() +
+ target::ClassTable::shared_class_table_offset();
+ const intptr_t table_offset =
+ target::SharedClassTable::class_heap_stats_table_offset();
const intptr_t class_offset = target::ClassTable::ClassOffsetFor(cid);
+
LoadIsolate(dest);
- intptr_t table_offset = target::Isolate::class_table_offset() +
- target::ClassTable::class_heap_stats_table_offset();
+ ldr(dest, Address(dest, shared_table_offset));
ldr(dest, Address(dest, table_offset));
AddImmediate(dest, class_offset);
}
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index 6321133..e75fcc9 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -1116,12 +1116,12 @@
void Assembler::LoadClassById(Register result, Register class_id) {
ASSERT(result != class_id);
+
+ const intptr_t table_offset = target::Isolate::class_table_offset() +
+ target::ClassTable::table_offset();
+
LoadIsolate(result);
- const intptr_t offset = target::Isolate::class_table_offset() +
- target::ClassTable::table_offset();
- LoadFromOffset(result, result, offset);
- ASSERT(target::ClassTable::kSizeOfClassPairLog2 == 4);
- add(class_id, class_id, Operand(class_id));
+ LoadFromOffset(result, result, table_offset);
ldr(result, Address(result, class_id, UXTX, Address::Scaled));
}
@@ -1553,10 +1553,16 @@
Register temp_reg,
Label* trace) {
ASSERT(cid > 0);
- intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+
+ const intptr_t shared_table_offset =
+ target::Isolate::class_table_offset() +
+ target::ClassTable::shared_class_table_offset();
+ const intptr_t table_offset =
+ target::SharedClassTable::class_heap_stats_table_offset();
+ const intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+
LoadIsolate(temp_reg);
- intptr_t table_offset = target::Isolate::class_table_offset() +
- target::ClassTable::class_heap_stats_table_offset();
+ ldr(temp_reg, Address(temp_reg, shared_table_offset));
ldr(temp_reg, Address(temp_reg, table_offset));
AddImmediate(temp_reg, state_offset);
ldr(temp_reg, Address(temp_reg, 0));
@@ -1566,10 +1572,17 @@
void Assembler::UpdateAllocationStats(intptr_t cid) {
ASSERT(cid > 0);
- intptr_t counter_offset = target::ClassTable::NewSpaceCounterOffsetFor(cid);
+
+ const intptr_t shared_table_offset =
+ target::Isolate::class_table_offset() +
+ target::ClassTable::shared_class_table_offset();
+ const intptr_t table_offset =
+ target::SharedClassTable::class_heap_stats_table_offset();
+ const intptr_t counter_offset =
+ target::ClassTable::NewSpaceCounterOffsetFor(cid);
+
LoadIsolate(TMP2);
- intptr_t table_offset = target::Isolate::class_table_offset() +
- target::ClassTable::class_heap_stats_table_offset();
+ ldr(TMP2, Address(TMP2, shared_table_offset));
ldr(TMP, Address(TMP2, table_offset));
AddImmediate(TMP2, TMP, counter_offset);
ldr(TMP, Address(TMP2, 0));
@@ -1579,14 +1592,21 @@
void Assembler::UpdateAllocationStatsWithSize(intptr_t cid, Register size_reg) {
ASSERT(cid > 0);
+
+ const intptr_t shared_table_offset =
+ target::Isolate::class_table_offset() +
+ target::ClassTable::shared_class_table_offset();
+ const intptr_t table_offset =
+ target::SharedClassTable::class_heap_stats_table_offset();
+
const uword class_offset = target::ClassTable::ClassOffsetFor(cid);
const uword count_field_offset =
target::ClassHeapStats::allocated_since_gc_new_space_offset();
const uword size_field_offset =
target::ClassHeapStats::allocated_size_since_gc_new_space_offset();
+
LoadIsolate(TMP2);
- intptr_t table_offset = target::Isolate::class_table_offset() +
- target::ClassTable::class_heap_stats_table_offset();
+ ldr(TMP2, Address(TMP2, shared_table_offset));
ldr(TMP, Address(TMP2, table_offset));
AddImmediate(TMP2, TMP, class_offset);
ldr(TMP, Address(TMP2, count_field_offset));
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index d945c0e..315e72f 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1526,7 +1526,6 @@
void CompareObject(Register reg, const Object& object);
void LoadClassId(Register result, Register object);
- // Overwrites class_id register (it will be tagged afterwards).
void LoadClassById(Register result, Register class_id);
void CompareClassId(Register object,
intptr_t class_id,
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc
index 5834616..4943f780 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32.cc
@@ -2362,11 +2362,17 @@
bool near_jump) {
ASSERT(cid > 0);
Address state_address(kNoRegister, 0);
- intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+
+ const intptr_t shared_table_offset =
+ target::Isolate::class_table_offset() +
+ target::ClassTable::shared_class_table_offset();
+ const intptr_t table_offset =
+ target::SharedClassTable::class_heap_stats_table_offset();
+ const intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+
ASSERT(temp_reg != kNoRegister);
LoadIsolate(temp_reg);
- intptr_t table_offset = target::Isolate::class_table_offset() +
- target::ClassTable::class_heap_stats_table_offset();
+ movl(temp_reg, Address(temp_reg, shared_table_offset));
movl(temp_reg, Address(temp_reg, table_offset));
state_address = Address(temp_reg, state_offset);
testb(state_address,
@@ -2378,11 +2384,17 @@
void Assembler::UpdateAllocationStats(intptr_t cid, Register temp_reg) {
ASSERT(cid > 0);
- intptr_t counter_offset = target::ClassTable::NewSpaceCounterOffsetFor(cid);
+ const intptr_t shared_table_offset =
+ target::Isolate::class_table_offset() +
+ target::ClassTable::shared_class_table_offset();
+ const intptr_t table_offset =
+ target::SharedClassTable::class_heap_stats_table_offset();
+ const intptr_t counter_offset =
+ target::ClassTable::NewSpaceCounterOffsetFor(cid);
+
ASSERT(temp_reg != kNoRegister);
LoadIsolate(temp_reg);
- intptr_t table_offset = target::Isolate::class_table_offset() +
- target::ClassTable::class_heap_stats_table_offset();
+ movl(temp_reg, Address(temp_reg, shared_table_offset));
movl(temp_reg, Address(temp_reg, table_offset));
incl(Address(temp_reg, counter_offset));
}
@@ -2617,12 +2629,12 @@
void Assembler::LoadClassById(Register result, Register class_id) {
ASSERT(result != class_id);
+
+ const intptr_t table_offset = target::Isolate::class_table_offset() +
+ target::ClassTable::table_offset();
LoadIsolate(result);
- const intptr_t offset = target::Isolate::class_table_offset() +
- target::ClassTable::table_offset();
- movl(result, Address(result, offset));
- ASSERT(target::ClassTable::kSizeOfClassPairLog2 == 3);
- movl(result, Address(result, class_id, TIMES_8, 0));
+ movl(result, Address(result, table_offset));
+ movl(result, Address(result, class_id, TIMES_4, 0));
}
void Assembler::CompareClassId(Register object,
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index 8bc626a..9c1cb4f 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -1851,11 +1851,16 @@
Label* trace,
bool near_jump) {
ASSERT(cid > 0);
- intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+ const intptr_t shared_table_offset =
+ target::Isolate::class_table_offset() +
+ target::ClassTable::shared_class_table_offset();
+ const intptr_t table_offset =
+ target::SharedClassTable::class_heap_stats_table_offset();
+ const intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+
Register temp_reg = TMP;
LoadIsolate(temp_reg);
- intptr_t table_offset = target::Isolate::class_table_offset() +
- target::ClassTable::class_heap_stats_table_offset();
+ movq(temp_reg, Address(temp_reg, shared_table_offset));
movq(temp_reg, Address(temp_reg, table_offset));
testb(Address(temp_reg, state_offset),
Immediate(target::ClassHeapStats::TraceAllocationMask()));
@@ -1866,11 +1871,17 @@
void Assembler::UpdateAllocationStats(intptr_t cid) {
ASSERT(cid > 0);
- intptr_t counter_offset = target::ClassTable::NewSpaceCounterOffsetFor(cid);
+ const intptr_t shared_table_offset =
+ target::Isolate::class_table_offset() +
+ target::ClassTable::shared_class_table_offset();
+ const intptr_t table_offset =
+ target::SharedClassTable::class_heap_stats_table_offset();
+ const intptr_t counter_offset =
+ target::ClassTable::NewSpaceCounterOffsetFor(cid);
+
Register temp_reg = TMP;
LoadIsolate(temp_reg);
- intptr_t table_offset = target::Isolate::class_table_offset() +
- target::ClassTable::class_heap_stats_table_offset();
+ movq(temp_reg, Address(temp_reg, shared_table_offset));
movq(temp_reg, Address(temp_reg, table_offset));
incq(Address(temp_reg, counter_offset));
}
@@ -2125,14 +2136,11 @@
void Assembler::LoadClassById(Register result, Register class_id) {
ASSERT(result != class_id);
+ const intptr_t table_offset = target::Isolate::class_table_offset() +
+ target::ClassTable::table_offset();
+
LoadIsolate(result);
- const intptr_t offset = target::Isolate::class_table_offset() +
- target::ClassTable::table_offset();
- movq(result, Address(result, offset));
- ASSERT(target::ClassTable::kSizeOfClassPairLog2 == 4);
- // TIMES_16 is not a real scale factor on x64, so we double the class id
- // and use TIMES_8.
- addq(class_id, class_id);
+ movq(result, Address(result, table_offset));
movq(result, Address(result, class_id, TIMES_8, 0));
}
diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h
index 9e69dc8..4065bdd 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.h
+++ b/runtime/vm/compiler/assembler/assembler_x64.h
@@ -803,8 +803,6 @@
// Loading and comparing classes of objects.
void LoadClassId(Register result, Register object);
-
- // Overwrites class_id register (it will be tagged afterwards).
void LoadClassById(Register result, Register class_id);
void CompareClassId(Register object,
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index b49dc6e..3359f05 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -5419,6 +5419,55 @@
Register out) {
ASSERT(op_kind == Token::kMOD || op_kind == Token::kTRUNCDIV);
+ // Special case 64-bit div/mod by compile-time constant. Note that various
+ // special constants (such as powers of two) should have been optimized
+ // earlier in the pipeline. Div or mod by zero falls into general code
+ // to implement the exception.
+ if (FLAG_optimization_level <= 2) {
+ // We only consider magic operations under O3.
+ } else if (auto c = instruction->right()->definition()->AsConstant()) {
+ if (c->value().IsInteger()) {
+ const int64_t divisor = Integer::Cast(c->value()).AsInt64Value();
+ if (divisor <= -2 || divisor >= 2) {
+ // For x DIV c or x MOD c: use magic operations.
+ compiler::Label pos;
+ int64_t magic = 0;
+ int64_t shift = 0;
+ Utils::CalculateMagicAndShiftForDivRem(divisor, &magic, &shift);
+ // Compute tmp = high(magic * numerator).
+ __ LoadImmediate(TMP2, magic);
+ __ smulh(TMP2, TMP2, left);
+ // Compute tmp +/-= numerator.
+ if (divisor > 0 && magic < 0) {
+ __ add(TMP2, TMP2, compiler::Operand(left));
+ } else if (divisor < 0 && magic > 0) {
+ __ sub(TMP2, TMP2, compiler::Operand(left));
+ }
+ // Shift if needed.
+ if (shift != 0) {
+ __ add(TMP2, ZR, compiler::Operand(TMP2, ASR, shift));
+ }
+ // Finalize DIV or MOD.
+ if (op_kind == Token::kTRUNCDIV) {
+ __ sub(out, TMP2, compiler::Operand(TMP2, ASR, 63));
+ } else {
+ __ sub(TMP2, TMP2, compiler::Operand(TMP2, ASR, 63));
+ __ LoadImmediate(TMP, divisor);
+ __ msub(out, TMP2, TMP, left);
+ // Compensate for Dart's Euclidean view of MOD.
+ __ CompareRegisters(out, ZR);
+ if (divisor > 0) {
+ __ add(TMP2, out, compiler::Operand(TMP));
+ } else {
+ __ sub(TMP2, out, compiler::Operand(TMP));
+ }
+ __ csel(out, TMP2, out, LT);
+ }
+ return;
+ }
+ }
+ }
+
// Prepare a slow path.
Range* right_range = instruction->right()->definition()->range();
Int64DivideSlowPath* slow_path = new (Z) Int64DivideSlowPath(
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 7068b74..1cfab97 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -44,8 +44,7 @@
UNREACHABLE();
}
- B->graph_entry_ =
- new (Z) GraphEntryInstr(*parsed_function(), Compiler::kNoOSRDeoptId);
+ B->graph_entry_ = new (Z) GraphEntryInstr(*parsed_function(), B->osr_id_);
auto normal_entry = B->BuildFunctionEntry(B->graph_entry_);
B->graph_entry_->set_normal_entry(normal_entry);
@@ -63,6 +62,9 @@
body += Return(TokenPosition::kNoSource);
PrologueInfo prologue_info(-1, -1);
+ if (B->IsCompiledForOsr()) {
+ B->graph_entry_->RelinkToOsrEntry(Z, B->last_used_block_id_ + 1);
+ }
return new (Z) FlowGraph(*parsed_function(), B->graph_entry_,
B->last_used_block_id_, prologue_info);
}
diff --git a/runtime/vm/compiler/method_recognizer.cc b/runtime/vm/compiler/method_recognizer.cc
index 9dda8a1..07f910f 100644
--- a/runtime/vm/compiler/method_recognizer.cc
+++ b/runtime/vm/compiler/method_recognizer.cc
@@ -317,10 +317,10 @@
static struct {
intptr_t symbol_id;
intptr_t cid;
- intptr_t finger_print;
+ uint32_t finger_print;
const char* name;
} factory_recognizer_list[] = {RECOGNIZED_LIST_FACTORY_LIST(RECOGNIZE_FACTORY){
- Symbols::kIllegal, -1, -1, NULL}};
+ Symbols::kIllegal, -1, 0, NULL}};
#undef RECOGNIZE_FACTORY
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 27e1bb1..3af03f5 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -9,337 +9,335 @@
// clang-format off
// (class-name, function-name, recognized enum, fingerprint).
-// When adding a new function add a 0 as fingerprint, build and run with
-// `tools/test.py vm/dart/reused_instructions_test` to get the correct
-// fingerprint from the mismatch error (or use Library::GetFunction() and print
-// func.SourceFingerprint()).
-// TODO(36376): Restore checking fingerprints of recognized methods.
+// When adding a new function, add a 0 as the fingerprint and run the build in
+// debug mode to get the correct fingerprint from the mismatch error.
#define OTHER_RECOGNIZED_LIST(V) \
- V(::, identical, ObjectIdentical, 0x49c6e96a) \
- V(ClassID, getID, ClassIDgetID, 0x7b18b257) \
- V(Object, Object., ObjectConstructor, 0x681617fe) \
- V(List, ., ListFactory, 0x629f8324) \
- V(_List, ., ObjectArrayAllocate, 0x2121902f) \
- V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0x7041895a) \
- V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0x336fa3ea) \
- V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0x231bbe2e) \
- V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0x0371785f) \
- V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0x65ab3a20) \
- V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x0cb0fcf6) \
- V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0x7db75d78) \
- V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0x1487cfc6) \
- V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0x6674ea6f) \
- V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0x236c6e7a) \
- V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0x5c367ffb) \
- V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0x772d1c0f) \
- V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0x12bae36a) \
- V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 0x15821cc9) \
- V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0x1f8237fa) \
- V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 0x181e5d16) \
- V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0x7ddb9f87) \
- V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0x74094f8d) \
- V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0x4741396e) \
- V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0x3b398ae4) \
- V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0x03db087b) \
- V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0x38a80b0d) \
- V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x40052c4e) \
- V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0x07b89f54) \
- V(ByteData, ., ByteDataFactory, 0x0) \
- V(_ByteDataView, get:offsetInBytes, ByteDataViewOffsetInBytes, 0x0) \
- V(_ByteDataView, get:_typedData, ByteDataViewTypedData, 0x0) \
- V(_TypedListView, get:offsetInBytes, TypedDataViewOffsetInBytes, 0x0) \
- V(_TypedListView, get:_typedData, TypedDataViewTypedData, 0x0) \
- V(_ByteDataView, ._, TypedData_ByteDataView_factory, 0x0) \
- V(_Int8ArrayView, ._, TypedData_Int8ArrayView_factory, 0x0) \
- V(_Uint8ArrayView, ._, TypedData_Uint8ArrayView_factory, 0x0) \
- V(_Uint8ClampedArrayView, ._, TypedData_Uint8ClampedArrayView_factory, 0x0) \
- V(_Int16ArrayView, ._, TypedData_Int16ArrayView_factory, 0x0) \
- V(_Uint16ArrayView, ._, TypedData_Uint16ArrayView_factory, 0x0) \
- V(_Int32ArrayView, ._, TypedData_Int32ArrayView_factory, 0x0) \
- V(_Uint32ArrayView, ._, TypedData_Uint32ArrayView_factory, 0x0) \
- V(_Int64ArrayView, ._, TypedData_Int64ArrayView_factory, 0x0) \
- V(_Uint64ArrayView, ._, TypedData_Uint64ArrayView_factory, 0x0) \
- V(_Float32ArrayView, ._, TypedData_Float32ArrayView_factory, 0x0) \
- V(_Float64ArrayView, ._, TypedData_Float64ArrayView_factory, 0x0) \
- V(_Float32x4ArrayView, ._, TypedData_Float32x4ArrayView_factory, 0x0) \
- V(_Int32x4ArrayView, ._, TypedData_Int32x4ArrayView_factory, 0x0) \
- V(_Float64x2ArrayView, ._, TypedData_Float64x2ArrayView_factory, 0x0) \
- V(::, _toClampedUint8, ConvertIntToClampedUint8, 0x564b0435) \
- V(_StringBase, _interpolate, StringBaseInterpolate, 0x01ecb15a) \
- V(_IntegerImplementation, toDouble, IntegerToDouble, 0x05da96ed) \
- V(_Double, _add, DoubleAdd, 0x2a38277b) \
- V(_Double, _sub, DoubleSub, 0x4f466391) \
- V(_Double, _mul, DoubleMul, 0x175e4f66) \
- V(_Double, _div, DoubleDiv, 0x0854181b) \
- V(::, min, MathMin, 0x32ebc57d) \
- V(::, max, MathMax, 0x377e8889) \
- V(::, _doublePow, MathDoublePow, 0x5add0ec1) \
- V(::, _intPow, MathIntPow, 0x11b45569) \
- V(Float32x4, Float32x4., Float32x4Constructor, 0x26ea459b) \
- V(Float32x4, Float32x4.zero, Float32x4Zero, 0x16eca604) \
- V(Float32x4, Float32x4.splat, Float32x4Splat, 0x694e83e3) \
- V(Float32x4, Float32x4.fromInt32x4Bits, Int32x4ToFloat32x4, 0x2f62ebd3) \
- V(Float32x4, Float32x4.fromFloat64x2, Float64x2ToFloat32x4, 0x50ed6910) \
- V(_Float32x4, shuffle, Float32x4Shuffle, 0x7829101f) \
- V(_Float32x4, shuffleMix, Float32x4ShuffleMix, 0x4182c06b) \
- V(_Float32x4, get:signMask, Float32x4GetSignMask, 0x1d08b351) \
- V(_Float32x4, equal, Float32x4Equal, 0x11adb239) \
- V(_Float32x4, greaterThan, Float32x4GreaterThan, 0x48adaf58) \
- V(_Float32x4, greaterThanOrEqual, Float32x4GreaterThanOrEqual, 0x32db94ca) \
- V(_Float32x4, lessThan, Float32x4LessThan, 0x425b000c) \
- V(_Float32x4, lessThanOrEqual, Float32x4LessThanOrEqual, 0x0278c2f8) \
- V(_Float32x4, notEqual, Float32x4NotEqual, 0x2987cd26) \
- V(_Float32x4, min, Float32x4Min, 0x5ed74b6f) \
- V(_Float32x4, max, Float32x4Max, 0x68696442) \
- V(_Float32x4, scale, Float32x4Scale, 0x704e4122) \
- V(_Float32x4, sqrt, Float32x4Sqrt, 0x2c967a6f) \
- V(_Float32x4, reciprocalSqrt, Float32x4ReciprocalSqrt, 0x6264bfe8) \
- V(_Float32x4, reciprocal, Float32x4Reciprocal, 0x3cd7e819) \
- V(_Float32x4, unary-, Float32x4Negate, 0x37accb52) \
- V(_Float32x4, abs, Float32x4Abs, 0x471cdd87) \
- V(_Float32x4, clamp, Float32x4Clamp, 0x2cb30492) \
- V(_Float32x4, withX, Float32x4WithX, 0x4e336aff) \
- V(_Float32x4, withY, Float32x4WithY, 0x0a72b910) \
- V(_Float32x4, withZ, Float32x4WithZ, 0x31e93658) \
- V(_Float32x4, withW, Float32x4WithW, 0x60ddc105) \
- V(Float64x2, Float64x2., Float64x2Constructor, 0x43054b9f) \
- V(Float64x2, Float64x2.zero, Float64x2Zero, 0x4af12f9d) \
- V(Float64x2, Float64x2.splat, Float64x2Splat, 0x134edef0) \
- V(Float64x2, Float64x2.fromFloat32x4, Float32x4ToFloat64x2, 0x17d6b5e4) \
- V(_Float64x2, get:x, Float64x2GetX, 0x58c09c58) \
- V(_Float64x2, get:y, Float64x2GetY, 0x3cf5e5b8) \
- V(_Float64x2, unary-, Float64x2Negate, 0x415ca009) \
- V(_Float64x2, abs, Float64x2Abs, 0x031f9e47) \
- V(_Float64x2, sqrt, Float64x2Sqrt, 0x77f711dd) \
- V(_Float64x2, get:signMask, Float64x2GetSignMask, 0x27deda4b) \
- V(_Float64x2, scale, Float64x2Scale, 0x26830a61) \
- V(_Float64x2, withX, Float64x2WithX, 0x1d2bcaf5) \
- V(_Float64x2, withY, Float64x2WithY, 0x383ed6ac) \
- V(_Float64x2, min, Float64x2Min, 0x28d7ddf6) \
- V(_Float64x2, max, Float64x2Max, 0x0bd74e5b) \
- V(Int32x4, Int32x4., Int32x4Constructor, 0x480555a9) \
- V(Int32x4, Int32x4.bool, Int32x4BoolConstructor, 0x36aa6963) \
- V(Int32x4, Int32x4.fromFloat32x4Bits, Float32x4ToInt32x4, 0x6715388a) \
- V(_Int32x4, get:flagX, Int32x4GetFlagX, 0x56396c82) \
- V(_Int32x4, get:flagY, Int32x4GetFlagY, 0x44704738) \
- V(_Int32x4, get:flagZ, Int32x4GetFlagZ, 0x20d6ff37) \
- V(_Int32x4, get:flagW, Int32x4GetFlagW, 0x5045616a) \
- V(_Int32x4, get:signMask, Int32x4GetSignMask, 0x2c1fb2a3) \
- V(_Int32x4, shuffle, Int32x4Shuffle, 0x20bc0b16) \
- V(_Int32x4, shuffleMix, Int32x4ShuffleMix, 0x5c7056e1) \
- V(_Int32x4, select, Int32x4Select, 0x6b49654f) \
- V(_Int32x4, withFlagX, Int32x4WithFlagX, 0x0ef58fcf) \
- V(_Int32x4, withFlagY, Int32x4WithFlagY, 0x6485a9c4) \
- V(_Int32x4, withFlagZ, Int32x4WithFlagZ, 0x267acdfa) \
- V(_Int32x4, withFlagW, Int32x4WithFlagW, 0x345ac675) \
- V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 0x02477157) \
- V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 0x4fc8d5e0) \
- V(_HashVMBase, get:_data, LinkedHashMap_getData, 0x2d7a70ac) \
- V(_HashVMBase, set:_data, LinkedHashMap_setData, 0x0ec032e8) \
- V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 0x088599ed) \
- V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 0x5f42ca86) \
- V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 0x32f3b13b) \
- V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 0x7219c45b) \
- V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 0x558481c2) \
- V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 0x5aa9888d) \
- V(::, _classRangeCheck, ClassRangeCheck, 0x2ae76b84) \
- V(::, _asyncStackTraceHelper, AsyncStackTraceHelper, 0) \
- V(::, _abi, FfiAbi, 0x0) \
- V(::, _asFunctionInternal, FfiAsFunctionInternal, 0x0) \
- V(::, _nativeCallbackFunction, FfiNativeCallbackFunction, 0x0) \
+ V(::, identical, ObjectIdentical, 0xc6e9467a) \
+ V(ClassID, getID, ClassIDgetID, 0xf0376ced) \
+ V(Object, Object., ObjectConstructor, 0x8f3ae7ea) \
+ V(List, ., ListFactory, 0xd834242d) \
+ V(_List, ., ObjectArrayAllocate, 0xe9c6d2be) \
+ V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0xa24c2704) \
+ V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0xa491df3e) \
+ V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0xb65ae1fc) \
+ V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0xb4b776e5) \
+ V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0xb460abe4) \
+ V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x8c066c71) \
+ V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0xacf2f222) \
+ V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0xa74b200b) \
+ V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0xa33a9f77) \
+ V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0x87d86b60) \
+ V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0x3e76086e) \
+ V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0xfea5f17f) \
+ V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0xd2c4e74b) \
+ V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 0xec62b082) \
+ V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0xc3566903) \
+ V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 0xdb50780f) \
+ V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0xbeeeea8a) \
+ V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0xca02f10a) \
+ V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0xcf587ccf) \
+ V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0xe01a1df0) \
+ V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0xb6a6294f) \
+ V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0xce7dad17) \
+ V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x4b773b59) \
+ V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0xfa2a6f88) \
+ V(ByteData, ., ByteDataFactory, 0x0d31f187) \
+ V(_ByteDataView, get:offsetInBytes, ByteDataViewOffsetInBytes, 0x0d956c6d) \
+ V(_ByteDataView, get:_typedData, ByteDataViewTypedData, 0x28cc4efc) \
+ V(_TypedListView, get:offsetInBytes, TypedDataViewOffsetInBytes, 0x0d956c6d) \
+ V(_TypedListView, get:_typedData, TypedDataViewTypedData, 0x28cc4efc) \
+ V(_ByteDataView, ._, TypedData_ByteDataView_factory, 0xb839ff59) \
+ V(_Int8ArrayView, ._, TypedData_Int8ArrayView_factory, 0x3d000a8d) \
+ V(_Uint8ArrayView, ._, TypedData_Uint8ArrayView_factory, 0xff69de0f) \
+ V(_Uint8ClampedArrayView, ._, TypedData_Uint8ClampedArrayView_factory, \
+ 0xdff11b9a) \
+ V(_Int16ArrayView, ._, TypedData_Int16ArrayView_factory, 0x1635c91e) \
+ V(_Uint16ArrayView, ._, TypedData_Uint16ArrayView_factory, 0x287cbc66) \
+ V(_Int32ArrayView, ._, TypedData_Int32ArrayView_factory, 0xf5270227) \
+ V(_Uint32ArrayView, ._, TypedData_Uint32ArrayView_factory, 0xbb74a021) \
+ V(_Int64ArrayView, ._, TypedData_Int64ArrayView_factory, 0xf348a583) \
+ V(_Uint64ArrayView, ._, TypedData_Uint64ArrayView_factory, 0x10589491) \
+ V(_Float32ArrayView, ._, TypedData_Float32ArrayView_factory, 0xbb4124b3) \
+ V(_Float64ArrayView, ._, TypedData_Float64ArrayView_factory, 0x5f0b81e9) \
+ V(_Float32x4ArrayView, ._, TypedData_Float32x4ArrayView_factory, 0xd8c71a39) \
+ V(_Int32x4ArrayView, ._, TypedData_Int32x4ArrayView_factory, 0x9bfbd6d5) \
+ V(_Float64x2ArrayView, ._, TypedData_Float64x2ArrayView_factory, 0x1a383408) \
+ V(::, _toClampedUint8, ConvertIntToClampedUint8, 0x59765a4a) \
+ V(_StringBase, _interpolate, StringBaseInterpolate, 0xe5a934d2) \
+ V(_IntegerImplementation, toDouble, IntegerToDouble, 0x22a26db3) \
+ V(_Double, _add, DoubleAdd, 0x2f5c036a) \
+ V(_Double, _sub, DoubleSub, 0x6d3cec71) \
+ V(_Double, _mul, DoubleMul, 0x648e67af) \
+ V(_Double, _div, DoubleDiv, 0x6d72d7d4) \
+ V(::, min, MathMin, 0x07168bf9) \
+ V(::, max, MathMax, 0xc7dbc9a0) \
+ V(::, _doublePow, MathDoublePow, 0x5ae04e61) \
+ V(::, _intPow, MathIntPow, 0x569ffd3f) \
+ V(Float32x4, Float32x4., Float32x4Constructor, 0xdf9f0693) \
+ V(Float32x4, Float32x4.zero, Float32x4Zero, 0x9b875c7f) \
+ V(Float32x4, Float32x4.splat, Float32x4Splat, 0xf584a639) \
+ V(Float32x4, Float32x4.fromInt32x4Bits, Int32x4ToFloat32x4, 0x7339b2bd) \
+ V(Float32x4, Float32x4.fromFloat64x2, Float64x2ToFloat32x4, 0x5de0e788) \
+ V(_Float32x4, shuffle, Float32x4Shuffle, 0x5bc2446e) \
+ V(_Float32x4, shuffleMix, Float32x4ShuffleMix, 0x61887391) \
+ V(_Float32x4, get:signMask, Float32x4GetSignMask, 0x2931936f) \
+ V(_Float32x4, equal, Float32x4Equal, 0x63e87fb9) \
+ V(_Float32x4, greaterThan, Float32x4GreaterThan, 0x71db0fc2) \
+ V(_Float32x4, greaterThanOrEqual, Float32x4GreaterThanOrEqual, 0x6dfbf3fa) \
+ V(_Float32x4, lessThan, Float32x4LessThan, 0x69a60360) \
+ V(_Float32x4, lessThanOrEqual, Float32x4LessThanOrEqual, 0x6604e583) \
+ V(_Float32x4, notEqual, Float32x4NotEqual, 0x83dcc786) \
+ V(_Float32x4, min, Float32x4Min, 0xf70ed6d5) \
+ V(_Float32x4, max, Float32x4Max, 0xd93e58a6) \
+ V(_Float32x4, scale, Float32x4Scale, 0xea28b605) \
+ V(_Float32x4, sqrt, Float32x4Sqrt, 0xacff17f7) \
+ V(_Float32x4, reciprocalSqrt, Float32x4ReciprocalSqrt, 0xa5e00f7d) \
+ V(_Float32x4, reciprocal, Float32x4Reciprocal, 0x9c5a3fb7) \
+ V(_Float32x4, unary-, Float32x4Negate, 0xae8af7f1) \
+ V(_Float32x4, abs, Float32x4Abs, 0xb34e9b8d) \
+ V(_Float32x4, clamp, Float32x4Clamp, 0xbed4ce62) \
+ V(_Float32x4, withX, Float32x4WithX, 0xe204ec19) \
+ V(_Float32x4, withY, Float32x4WithY, 0xff17a63f) \
+ V(_Float32x4, withZ, Float32x4WithZ, 0x0e7144f2) \
+ V(_Float32x4, withW, Float32x4WithW, 0x0802b80f) \
+ V(Float64x2, Float64x2., Float64x2Constructor, 0xb0bb0109) \
+ V(Float64x2, Float64x2.zero, Float64x2Zero, 0x5e70f315) \
+ V(Float64x2, Float64x2.splat, Float64x2Splat, 0xb86e3ccf) \
+ V(Float64x2, Float64x2.fromFloat32x4, Float32x4ToFloat64x2, 0x956c2161) \
+ V(_Float64x2, get:x, Float64x2GetX, 0x00b83193) \
+ V(_Float64x2, get:y, Float64x2GetY, 0xee498cb6) \
+ V(_Float64x2, unary-, Float64x2Negate, 0x71748e87) \
+ V(_Float64x2, abs, Float64x2Abs, 0x76383223) \
+ V(_Float64x2, sqrt, Float64x2Sqrt, 0x6fe8ae8d) \
+ V(_Float64x2, get:signMask, Float64x2GetSignMask, 0x2931936f) \
+ V(_Float64x2, scale, Float64x2Scale, 0xad124c9b) \
+ V(_Float64x2, withX, Float64x2WithX, 0xa4ee82af) \
+ V(_Float64x2, withY, Float64x2WithY, 0xc2013cd5) \
+ V(_Float64x2, min, Float64x2Min, 0x57938495) \
+ V(_Float64x2, max, Float64x2Max, 0x39c30666) \
+ V(Int32x4, Int32x4., Int32x4Constructor, 0xa77aeafb) \
+ V(Int32x4, Int32x4.bool, Int32x4BoolConstructor, 0x51ae2c0c) \
+ V(Int32x4, Int32x4.fromFloat32x4Bits, Float32x4ToInt32x4, 0x64c906dc) \
+ V(_Int32x4, get:flagX, Int32x4GetFlagX, 0x9f8da5bb) \
+ V(_Int32x4, get:flagY, Int32x4GetFlagY, 0xbafddc9b) \
+ V(_Int32x4, get:flagZ, Int32x4GetFlagZ, 0xc8a777ee) \
+ V(_Int32x4, get:flagW, Int32x4GetFlagW, 0xd1c78a2f) \
+ V(_Int32x4, get:signMask, Int32x4GetSignMask, 0x2931936f) \
+ V(_Int32x4, shuffle, Int32x4Shuffle, 0x00cff856) \
+ V(_Int32x4, shuffleMix, Int32x4ShuffleMix, 0x57a21961) \
+ V(_Int32x4, select, Int32x4Select, 0xafd1fc25) \
+ V(_Int32x4, withFlagX, Int32x4WithFlagX, 0x7a1fe4b5) \
+ V(_Int32x4, withFlagY, Int32x4WithFlagY, 0x8c658940) \
+ V(_Int32x4, withFlagZ, Int32x4WithFlagZ, 0x97d3a01c) \
+ V(_Int32x4, withFlagW, Int32x4WithFlagW, 0x80e3723b) \
+ V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 0x09db1d9d) \
+ V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 0xb643fb19) \
+ V(_HashVMBase, get:_data, LinkedHashMap_getData, 0x9a54182a) \
+ V(_HashVMBase, set:_data, LinkedHashMap_setData, 0x8bc58326) \
+ V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 0xf3cf0e2e) \
+ V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 0x75261d2a) \
+ V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 0xfbd541dd) \
+ V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 0x7d2c50d9) \
+ V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 0xfdd43ee1) \
+ V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 0x7f2b4ddd) \
+ V(::, _classRangeCheck, ClassRangeCheck, 0xca52e30a) \
+ V(::, _asyncStackTraceHelper, AsyncStackTraceHelper, 0xaeaed5cb) \
+ V(::, _abi, FfiAbi, 0xf2e89620) \
+ V(::, _asFunctionInternal, FfiAsFunctionInternal, 0x82525e9e) \
+ V(::, _nativeCallbackFunction, FfiNativeCallbackFunction, 0x591fb33c) \
// List of intrinsics:
// (class-name, function-name, intrinsification method, fingerprint).
#define CORE_LIB_INTRINSIC_LIST(V) \
- V(_Smi, ~, Smi_bitNegate, 0x67299f4f) \
- V(_Smi, get:bitLength, Smi_bitLength, 0x25b3cb0a) \
- V(_Smi, _bitAndFromSmi, Smi_bitAndFromSmi, 0x562d5047) \
- V(_BigIntImpl, _lsh, Bigint_lsh, 0x5b6cfc8b) \
- V(_BigIntImpl, _rsh, Bigint_rsh, 0x6ff14a49) \
- V(_BigIntImpl, _absAdd, Bigint_absAdd, 0x5bf14238) \
- V(_BigIntImpl, _absSub, Bigint_absSub, 0x1de5bd32) \
- V(_BigIntImpl, _mulAdd, Bigint_mulAdd, 0x6f277966) \
- V(_BigIntImpl, _sqrAdd, Bigint_sqrAdd, 0x68e4c8ea) \
+ V(_Smi, ~, Smi_bitNegate, 0x2f002cba) \
+ V(_Smi, get:bitLength, Smi_bitLength, 0x277b8ace) \
+ V(_Smi, _bitAndFromSmi, Smi_bitAndFromSmi, 0x90b94dd3) \
+ V(_BigIntImpl, _lsh, Bigint_lsh, 0x776e33c7) \
+ V(_BigIntImpl, _rsh, Bigint_rsh, 0x2bf277fc) \
+ V(_BigIntImpl, _absAdd, Bigint_absAdd, 0x147eb8ec) \
+ V(_BigIntImpl, _absSub, Bigint_absSub, 0xed4c4e74) \
+ V(_BigIntImpl, _mulAdd, Bigint_mulAdd, 0xc8dcc37e) \
+ V(_BigIntImpl, _sqrAdd, Bigint_sqrAdd, 0x45be1228) \
V(_BigIntImpl, _estimateQuotientDigit, Bigint_estimateQuotientDigit, \
- 0x35456d91) \
- V(_BigIntMontgomeryReduction, _mulMod, Montgomery_mulMod, 0x0f7b0375) \
- V(_Double, >, Double_greaterThan, 0x4f1375a3) \
- V(_Double, >=, Double_greaterEqualThan, 0x4260c184) \
- V(_Double, <, Double_lessThan, 0x365d1eba) \
- V(_Double, <=, Double_lessEqualThan, 0x74b5eb64) \
- V(_Double, ==, Double_equal, 0x613492fc) \
- V(_Double, +, Double_add, 0x53994370) \
- V(_Double, -, Double_sub, 0x3b69d466) \
- V(_Double, *, Double_mul, 0x2bb9bd5d) \
- V(_Double, /, Double_div, 0x483eee28) \
- V(_Double, get:hashCode, Double_hashCode, 0x702b77b7) \
- V(_Double, get:_identityHashCode, Double_identityHash, 0x7bda5549) \
- V(_Double, get:isNaN, Double_getIsNaN, 0x0af9d4a9) \
- V(_Double, get:isInfinite, Double_getIsInfinite, 0x0f7acb47) \
- V(_Double, get:isNegative, Double_getIsNegative, 0x3a59e7f4) \
- V(_Double, _mulFromInteger, Double_mulFromInteger, 0x2017fcf6) \
- V(_Double, .fromInteger, DoubleFromInteger, 0x6d234f4b) \
- V(_GrowableList, ._withData, GrowableArray_Allocate, 0x28b2138e) \
- V(_RegExp, _ExecuteMatch, RegExp_ExecuteMatch, 0x380184b1) \
- V(_RegExp, _ExecuteMatchSticky, RegExp_ExecuteMatchSticky, 0x79b8f955) \
- V(Object, ==, ObjectEquals, 0x7b32a55a) \
- V(Object, get:runtimeType, ObjectRuntimeType, 0x00e8ab29) \
- V(Object, _haveSameRuntimeType, ObjectHaveSameRuntimeType, 0x4dc50799) \
- V(_StringBase, get:hashCode, String_getHashCode, 0x78c3d446) \
- V(_StringBase, get:_identityHashCode, String_identityHash, 0x0472b1d8) \
- V(_StringBase, get:isEmpty, StringBaseIsEmpty, 0x4a8b29c8) \
- V(_StringBase, _substringMatches, StringBaseSubstringMatches, 0x46de4f10) \
- V(_StringBase, [], StringBaseCharAt, 0x7cbb8603) \
- V(_OneByteString, get:hashCode, OneByteString_getHashCode, 0x78c3d446) \
+ 0xd7c44af1) \
+ V(_BigIntMontgomeryReduction, _mulMod, Montgomery_mulMod, 0xa1a5caf3) \
+ V(_Double, >, Double_greaterThan, 0x682a02bc) \
+ V(_Double, >=, Double_greaterEqualThan, 0x2961f8ee) \
+ V(_Double, <, Double_lessThan, 0xcbff42e5) \
+ V(_Double, <=, Double_lessEqualThan, 0xd2253d90) \
+ V(_Double, ==, Double_equal, 0xa7dfa02b) \
+ V(_Double, +, Double_add, 0xf7d8da94) \
+ V(_Double, -, Double_sub, 0xc8dda725) \
+ V(_Double, *, Double_mul, 0x2dac85a2) \
+ V(_Double, /, Double_div, 0x6cf1f09e) \
+ V(_Double, get:hashCode, Double_hashCode, 0x22a75218) \
+ V(_Double, get:_identityHashCode, Double_identityHash, 0xf46be6d6) \
+ V(_Double, get:isNaN, Double_getIsNaN, 0xb177a8f6) \
+ V(_Double, get:isInfinite, Double_getIsInfinite, 0xa1e96db5) \
+ V(_Double, get:isNegative, Double_getIsNegative, 0xb15ff274) \
+ V(_Double, _mulFromInteger, Double_mulFromInteger, 0xe2853768) \
+ V(_Double, .fromInteger, DoubleFromInteger, 0x89504536) \
+ V(_GrowableList, ._withData, GrowableArray_Allocate, 0x55981e03) \
+ V(_RegExp, _ExecuteMatch, RegExp_ExecuteMatch, 0xb961fc8d) \
+ V(_RegExp, _ExecuteMatchSticky, RegExp_ExecuteMatchSticky, 0xb22daf53) \
+ V(Object, ==, ObjectEquals, 0x91ead0d6) \
+ V(Object, get:runtimeType, ObjectRuntimeType, 0x8cdba093) \
+ V(Object, _haveSameRuntimeType, ObjectHaveSameRuntimeType, 0xcee5d65a) \
+ V(_StringBase, get:hashCode, String_getHashCode, 0x22a75237) \
+ V(_StringBase, get:_identityHashCode, String_identityHash, 0xf46be6f5) \
+ V(_StringBase, get:isEmpty, StringBaseIsEmpty, 0xd7218394) \
+ V(_StringBase, _substringMatches, StringBaseSubstringMatches, 0x46fc3731) \
+ V(_StringBase, [], StringBaseCharAt, 0xe67164fe) \
+ V(_OneByteString, get:hashCode, OneByteString_getHashCode, 0x22a75237) \
V(_OneByteString, _substringUncheckedNative, \
- OneByteString_substringUnchecked, 0x3538ad86) \
- V(_OneByteString, _setAt, OneByteStringSetAt, 0x11ffddd1) \
- V(_OneByteString, _allocate, OneByteString_allocate, 0x74933376) \
- V(_OneByteString, ==, OneByteString_equality, 0x4eda197e) \
- V(_TwoByteString, ==, TwoByteString_equality, 0x4eda197e) \
- V(_Type, get:hashCode, Type_getHashCode, 0x18d1523f) \
- V(::, _getHash, Object_getHash, 0x2827856d) \
- V(::, _setHash, Object_setHash, 0x690faebd) \
+ OneByteString_substringUnchecked, 0x94c41563) \
+ V(_OneByteString, _setAt, OneByteStringSetAt, 0xc6c7e75d) \
+ V(_OneByteString, _allocate, OneByteString_allocate, 0xbe472ce0) \
+ V(_OneByteString, ==, OneByteString_equality, 0xe1ea0c11) \
+ V(_TwoByteString, ==, TwoByteString_equality, 0xe1ea0c11) \
+ V(_Type, get:hashCode, Type_getHashCode, 0x22a75237) \
+ V(::, _getHash, Object_getHash, 0xb05aa13f) \
+ V(::, _setHash, Object_setHash, 0xcb404dd2) \
#define CORE_INTEGER_LIB_INTRINSIC_LIST(V) \
V(_IntegerImplementation, _addFromInteger, Integer_addFromInteger, \
- 0x6a10c54a) \
- V(_IntegerImplementation, +, Integer_add, 0x43d53af7) \
+ 0xc7bd74ae) \
+ V(_IntegerImplementation, +, Integer_add, 0x49774600) \
V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger, \
- 0x3fa4b1ed) \
- V(_IntegerImplementation, -, Integer_sub, 0x2dc22e03) \
+ 0x8e0de2a2) \
+ V(_IntegerImplementation, -, Integer_sub, 0x1a853bf1) \
V(_IntegerImplementation, _mulFromInteger, Integer_mulFromInteger, \
- 0x3216e299) \
- V(_IntegerImplementation, *, Integer_mul, 0x4e7a1c24) \
+ 0x95751a41) \
+ V(_IntegerImplementation, *, Integer_mul, 0xefe7fbce) \
V(_IntegerImplementation, _moduloFromInteger, Integer_moduloFromInteger, \
- 0x6348b974) \
- V(_IntegerImplementation, ~/, Integer_truncDivide, 0x4efb2d39) \
- V(_IntegerImplementation, unary-, Integer_negate, 0x428bf6fa) \
+ 0xbc75fece) \
+ V(_IntegerImplementation, ~/, Integer_truncDivide, 0xfb066107) \
+ V(_IntegerImplementation, unary-, Integer_negate, 0xdb5f0d70) \
V(_IntegerImplementation, _bitAndFromInteger, Integer_bitAndFromInteger, \
- 0x395b1678) \
- V(_IntegerImplementation, &, Integer_bitAnd, 0x5ab35f30) \
+ 0xb7e724d2) \
+ V(_IntegerImplementation, &, Integer_bitAnd, 0xd9888ca4) \
V(_IntegerImplementation, _bitOrFromInteger, Integer_bitOrFromInteger, \
- 0x6a36b395) \
- V(_IntegerImplementation, |, Integer_bitOr, 0x267fa107) \
+ 0xa97501aa) \
+ V(_IntegerImplementation, |, Integer_bitOr, 0xc82cc85c) \
V(_IntegerImplementation, _bitXorFromInteger, Integer_bitXorFromInteger, \
- 0x72da93f0) \
- V(_IntegerImplementation, ^, Integer_bitXor, 0x0c7b0230) \
+ 0x9ab4d16e) \
+ V(_IntegerImplementation, ^, Integer_bitXor, 0xc1ed9463) \
V(_IntegerImplementation, _greaterThanFromInteger, \
- Integer_greaterThanFromInt, 0x4a50ed58) \
- V(_IntegerImplementation, >, Integer_greaterThan, 0x6599a6e1) \
- V(_IntegerImplementation, ==, Integer_equal, 0x58abc487) \
+ Integer_greaterThanFromInt, 0x3366ff66) \
+ V(_IntegerImplementation, >, Integer_greaterThan, 0xe74b678c) \
+ V(_IntegerImplementation, ==, Integer_equal, 0xb6faea0e) \
V(_IntegerImplementation, _equalToInteger, Integer_equalToInteger, \
- 0x063be842) \
- V(_IntegerImplementation, <, Integer_lessThan, 0x365d1eba) \
- V(_IntegerImplementation, <=, Integer_lessEqualThan, 0x74b5eb64) \
- V(_IntegerImplementation, >=, Integer_greaterEqualThan, 0x4260c184) \
- V(_IntegerImplementation, <<, Integer_shl, 0x371c45fa) \
- V(_IntegerImplementation, >>, Integer_sar, 0x2b630578) \
- V(_Double, toInt, DoubleToInteger, 0x26ef344b) \
+ 0x39d3cd05) \
+ V(_IntegerImplementation, <, Integer_lessThan, 0xcbff42e5) \
+ V(_IntegerImplementation, <=, Integer_lessEqualThan, 0xd2253d90) \
+ V(_IntegerImplementation, >=, Integer_greaterEqualThan, 0x2961f8ee) \
+ V(_IntegerImplementation, <<, Integer_shl, 0x972a7fd6) \
+ V(_IntegerImplementation, >>, Integer_sar, 0xfe022e7b) \
+ V(_Double, toInt, DoubleToInteger, 0x14433ded) \
#define MATH_LIB_INTRINSIC_LIST(V) \
- V(::, sqrt, MathSqrt, 0x70482cf3) \
- V(_Random, _nextState, Random_nextState, 0x2842c4d5) \
+ V(::, sqrt, MathSqrt, 0x2c20a879) \
+ V(_Random, _nextState, Random_nextState, 0x30682e3d) \
#define GRAPH_MATH_LIB_INTRINSIC_LIST(V) \
- V(::, sin, MathSin, 0x6b7bd98c) \
- V(::, cos, MathCos, 0x459bf5fe) \
- V(::, tan, MathTan, 0x3bcd772a) \
- V(::, asin, MathAsin, 0x2ecc2fcd) \
- V(::, acos, MathAcos, 0x08cf2212) \
- V(::, atan, MathAtan, 0x1e2731d5) \
- V(::, atan2, MathAtan2, 0x39f1fa41) \
+ V(::, sin, MathSin, 0x18e743c0) \
+ V(::, cos, MathCos, 0x6623c0ce) \
+ V(::, tan, MathTan, 0x3584ee62) \
+ V(::, asin, MathAsin, 0xb023f0df) \
+ V(::, acos, MathAcos, 0x165661fa) \
+ V(::, atan, MathAtan, 0xc91eca17) \
+ V(::, atan2, MathAtan2, 0x79b3a5e6) \
#define TYPED_DATA_LIB_INTRINSIC_LIST(V) \
- V(Int8List, ., TypedData_Int8Array_factory, 0x7e39a3a1) \
- V(Uint8List, ., TypedData_Uint8Array_factory, 0x3a79adf7) \
- V(Uint8ClampedList, ., TypedData_Uint8ClampedArray_factory, 0x67f38395) \
- V(Int16List, ., TypedData_Int16Array_factory, 0x6477bda8) \
- V(Uint16List, ., TypedData_Uint16Array_factory, 0x5707c5a2) \
- V(Int32List, ., TypedData_Int32Array_factory, 0x2b96ec0e) \
- V(Uint32List, ., TypedData_Uint32Array_factory, 0x0c1c0d62) \
- V(Int64List, ., TypedData_Int64Array_factory, 0x279ab485) \
- V(Uint64List, ., TypedData_Uint64Array_factory, 0x7bcb89c2) \
- V(Float32List, ., TypedData_Float32Array_factory, 0x43506c09) \
- V(Float64List, ., TypedData_Float64Array_factory, 0x1fde3eaf) \
- V(Float32x4List, ., TypedData_Float32x4Array_factory, 0x4a4030d6) \
- V(Int32x4List, ., TypedData_Int32x4Array_factory, 0x6dd02406) \
- V(Float64x2List, ., TypedData_Float64x2Array_factory, 0x688e4e97) \
+ V(Int8List, ., TypedData_Int8Array_factory, 0x6ce2f102) \
+ V(Uint8List, ., TypedData_Uint8Array_factory, 0x1163d489) \
+ V(Uint8ClampedList, ., TypedData_Uint8ClampedArray_factory, 0x0b0e9f0f) \
+ V(Int16List, ., TypedData_Int16Array_factory, 0x6addd02d) \
+ V(Uint16List, ., TypedData_Uint16Array_factory, 0x139a6464) \
+ V(Int32List, ., TypedData_Int32Array_factory, 0x40dad19a) \
+ V(Uint32List, ., TypedData_Uint32Array_factory, 0x988357c5) \
+ V(Int64List, ., TypedData_Int64Array_factory, 0xef0a3469) \
+ V(Uint64List, ., TypedData_Uint64Array_factory, 0xf49c0472) \
+ V(Float32List, ., TypedData_Float32Array_factory, 0x779b26f8) \
+ V(Float64List, ., TypedData_Float64Array_factory, 0xf623554b) \
+ V(Float32x4List, ., TypedData_Float32x4Array_factory, 0x9edf5402) \
+ V(Int32x4List, ., TypedData_Int32x4Array_factory, 0x915e8e68) \
+ V(Float64x2List, ., TypedData_Float64x2Array_factory, 0x0d206864) \
#define GRAPH_TYPED_DATA_INTRINSICS_LIST(V) \
- V(_Int8List, [], Int8ArrayGetIndexed, 0x49767a2c) \
- V(_Int8List, []=, Int8ArraySetIndexed, 0x24f42cd0) \
- V(_Uint8List, [], Uint8ArrayGetIndexed, 0x088d86d4) \
- V(_Uint8List, []=, Uint8ArraySetIndexed, 0x12639541) \
- V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 0x088d86d4) \
- V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 0x12639541) \
- V(_Uint8ClampedList, [], Uint8ClampedArrayGetIndexed, 0x088d86d4) \
- V(_Uint8ClampedList, []=, Uint8ClampedArraySetIndexed, 0x6790dba1) \
+ V(_Int8List, [], Int8ArrayGetIndexed, 0xdab47d5d) \
+ V(_Int8List, []=, Int8ArraySetIndexed, 0x09ba0f32) \
+ V(_Uint8List, [], Uint8ArrayGetIndexed, 0xa9468b1d) \
+ V(_Uint8List, []=, Uint8ArraySetIndexed, 0xa6fd9dce) \
+ V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 0xa9468b1d) \
+ V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 0xa6fd9dce) \
+ V(_Uint8ClampedList, [], Uint8ClampedArrayGetIndexed, 0xa9468b1d) \
+ V(_Uint8ClampedList, []=, Uint8ClampedArraySetIndexed, 0x7d60b42e) \
V(_ExternalUint8ClampedArray, [], ExternalUint8ClampedArrayGetIndexed, \
- 0x088d86d4) \
+ 0xa9468b1d) \
V(_ExternalUint8ClampedArray, []=, ExternalUint8ClampedArraySetIndexed, \
- 0x6790dba1) \
- V(_Int16List, [], Int16ArrayGetIndexed, 0x5ec64948) \
- V(_Int16List, []=, Int16ArraySetIndexed, 0x0e4e8221) \
- V(_Uint16List, [], Uint16ArrayGetIndexed, 0x5f49d093) \
- V(_Uint16List, []=, Uint16ArraySetIndexed, 0x2efbc90f) \
- V(_Int32List, [], Int32ArrayGetIndexed, 0x4bc0d3dd) \
- V(_Int32List, []=, Int32ArraySetIndexed, 0x1adf9823) \
- V(_Uint32List, [], Uint32ArrayGetIndexed, 0x188658ce) \
- V(_Uint32List, []=, Uint32ArraySetIndexed, 0x01f51a79) \
- V(_Int64List, [], Int64ArrayGetIndexed, 0x51eafb97) \
- V(_Int64List, []=, Int64ArraySetIndexed, 0x376181fb) \
- V(_Uint64List, [], Uint64ArrayGetIndexed, 0x4b2a1ba2) \
- V(_Uint64List, []=, Uint64ArraySetIndexed, 0x5f881bd4) \
- V(_Float64List, [], Float64ArrayGetIndexed, 0x0a714486) \
- V(_Float64List, []=, Float64ArraySetIndexed, 0x04937367) \
- V(_Float32List, [], Float32ArrayGetIndexed, 0x5ade301f) \
- V(_Float32List, []=, Float32ArraySetIndexed, 0x0d5c2e2b) \
- V(_Float32x4List, [], Float32x4ArrayGetIndexed, 0x128cddeb) \
- V(_Float32x4List, []=, Float32x4ArraySetIndexed, 0x7ad55c72) \
- V(_Int32x4List, [], Int32x4ArrayGetIndexed, 0x4b78af9c) \
- V(_Int32x4List, []=, Int32x4ArraySetIndexed, 0x31453dab) \
- V(_Float64x2List, [], Float64x2ArrayGetIndexed, 0x644a0be1) \
- V(_Float64x2List, []=, Float64x2ArraySetIndexed, 0x6b836b0b) \
- V(_TypedList, get:length, TypedListLength, 0x0) \
- V(_TypedListView, get:length, TypedListViewLength, 0x0) \
- V(_ByteDataView, get:length, ByteDataViewLength, 0x0) \
- V(_Float32x4, get:x, Float32x4ShuffleX, 0x63d1a9fd) \
- V(_Float32x4, get:y, Float32x4ShuffleY, 0x203523d9) \
- V(_Float32x4, get:z, Float32x4ShuffleZ, 0x13190678) \
- V(_Float32x4, get:w, Float32x4ShuffleW, 0x698a38de) \
- V(_Float32x4, *, Float32x4Mul, 0x5dec68b2) \
- V(_Float32x4, -, Float32x4Sub, 0x3ea14461) \
- V(_Float32x4, +, Float32x4Add, 0x7ffcf301) \
+ 0x7d60b42e) \
+ V(_Int16List, [], Int16ArrayGetIndexed, 0x2b783e9d) \
+ V(_Int16List, []=, Int16ArraySetIndexed, 0x894edd67) \
+ V(_Uint16List, [], Uint16ArrayGetIndexed, 0x3d599bdd) \
+ V(_Uint16List, []=, Uint16ArraySetIndexed, 0x146065d0) \
+ V(_Int32List, [], Int32ArrayGetIndexed, 0x645ac57e) \
+ V(_Int32List, []=, Int32ArraySetIndexed, 0x58343408) \
+ V(_Uint32List, [], Uint32ArrayGetIndexed, 0xe6f6183e) \
+ V(_Uint32List, []=, Uint32ArraySetIndexed, 0x7ee99568) \
+ V(_Int64List, [], Int64ArrayGetIndexed, 0x57d917de) \
+ V(_Int64List, []=, Int64ArraySetIndexed, 0x94485c32) \
+ V(_Uint64List, [], Uint64ArrayGetIndexed, 0x7fb017de) \
+ V(_Uint64List, []=, Uint64ArraySetIndexed, 0x1c695796) \
+ V(_Float64List, [], Float64ArrayGetIndexed, 0x9e20a2c3) \
+ V(_Float64List, []=, Float64ArraySetIndexed, 0xcd01ec0c) \
+ V(_Float32List, [], Float32ArrayGetIndexed, 0x7c01bb83) \
+ V(_Float32List, []=, Float32ArraySetIndexed, 0xcb87f800) \
+ V(_Float32x4List, [], Float32x4ArrayGetIndexed, 0x5a2a83fc) \
+ V(_Float32x4List, []=, Float32x4ArraySetIndexed, 0x5ae5c9f3) \
+ V(_Int32x4List, [], Int32x4ArrayGetIndexed, 0x05ef16d4) \
+ V(_Int32x4List, []=, Int32x4ArraySetIndexed, 0x2e8437b1) \
+ V(_Float64x2List, [], Float64x2ArrayGetIndexed, 0xe7fbf246) \
+ V(_Float64x2List, []=, Float64x2ArraySetIndexed, 0xce826d19) \
+ V(_TypedList, get:length, TypedListLength, 0x05176aac) \
+ V(_TypedListView, get:length, TypedListViewLength, 0x05176aac) \
+ V(_ByteDataView, get:length, ByteDataViewLength, 0x05176aac) \
+ V(_Float32x4, get:x, Float32x4ShuffleX, 0x00b83193) \
+ V(_Float32x4, get:y, Float32x4ShuffleY, 0xee498cb6) \
+ V(_Float32x4, get:z, Float32x4ShuffleZ, 0x2414f84c) \
+ V(_Float32x4, get:w, Float32x4ShuffleW, 0x06553cce) \
+ V(_Float32x4, *, Float32x4Mul, 0xf817cb64) \
+ V(_Float32x4, -, Float32x4Sub, 0xeff9bb27) \
+ V(_Float32x4, +, Float32x4Add, 0xcac0f0b6) \
#define GRAPH_CORE_INTRINSICS_LIST(V) \
- V(_List, get:length, ObjectArrayLength, 0x25952390) \
- V(_List, [], ObjectArrayGetIndexed, 0x653da02e) \
- V(_List, []=, ObjectArraySetIndexed, 0x16b3d2b0) \
- V(_List, _setIndexed, ObjectArraySetIndexedUnchecked, 0x50d64c75) \
- V(_ImmutableList, get:length, ImmutableArrayLength, 0x25952390) \
- V(_ImmutableList, [], ImmutableArrayGetIndexed, 0x653da02e) \
- V(_GrowableList, get:length, GrowableArrayLength, 0x18dd86b4) \
- V(_GrowableList, get:_capacity, GrowableArrayCapacity, 0x2e04be60) \
- V(_GrowableList, _setData, GrowableArraySetData, 0x3dbea348) \
- V(_GrowableList, _setLength, GrowableArraySetLength, 0x753e55da) \
- V(_GrowableList, [], GrowableArrayGetIndexed, 0x446fe1f0) \
- V(_GrowableList, []=, GrowableArraySetIndexed, 0x40a462ec) \
- V(_GrowableList, _setIndexed, GrowableArraySetIndexedUnchecked, 0x297083df) \
- V(_StringBase, get:length, StringBaseLength, 0x2a2d03d1) \
- V(_OneByteString, codeUnitAt, OneByteStringCodeUnitAt, 0x55a0a1f3) \
- V(_TwoByteString, codeUnitAt, TwoByteStringCodeUnitAt, 0x55a0a1f3) \
+ V(_List, get:length, ObjectArrayLength, 0x05176aac) \
+ V(_List, [], ObjectArrayGetIndexed, 0x7e13418e) \
+ V(_List, []=, ObjectArraySetIndexed, 0x4d5e74cf) \
+ V(_List, _setIndexed, ObjectArraySetIndexedUnchecked, 0x91b2c203) \
+ V(_ImmutableList, get:length, ImmutableArrayLength, 0x05176aac) \
+ V(_ImmutableList, [], ImmutableArrayGetIndexed, 0x7e13418e) \
+ V(_GrowableList, get:length, GrowableArrayLength, 0x05176aac) \
+ V(_GrowableList, get:_capacity, GrowableArrayCapacity, 0x2a661633) \
+ V(_GrowableList, _setData, GrowableArraySetData, 0x9e2350fe) \
+ V(_GrowableList, _setLength, GrowableArraySetLength, 0x8d94d91d) \
+ V(_GrowableList, [], GrowableArrayGetIndexed, 0x7e13418e) \
+ V(_GrowableList, []=, GrowableArraySetIndexed, 0x4d5e74cf) \
+ V(_GrowableList, _setIndexed, GrowableArraySetIndexedUnchecked, 0x91b2c203) \
+ V(_StringBase, get:length, StringBaseLength, 0x05176aac) \
+ V(_OneByteString, codeUnitAt, OneByteStringCodeUnitAt, 0xb0959953) \
+ V(_TwoByteString, codeUnitAt, TwoByteStringCodeUnitAt, 0xb0959953) \
V(_ExternalOneByteString, codeUnitAt, ExternalOneByteStringCodeUnitAt, \
- 0x55a0a1f3) \
+ 0xb0959953) \
V(_ExternalTwoByteString, codeUnitAt, ExternalTwoByteStringCodeUnitAt, \
- 0x55a0a1f3) \
- V(_Double, unary-, DoubleFlipSignBit, 0x6db4674f) \
- V(_Double, truncateToDouble, DoubleTruncate, 0x2f27e5d3) \
- V(_Double, roundToDouble, DoubleRound, 0x2f89c512) \
- V(_Double, floorToDouble, DoubleFloor, 0x6aa87a5f) \
- V(_Double, ceilToDouble, DoubleCeil, 0x1b045e9e) \
- V(_Double, _modulo, DoubleMod, 0x5b8ceed7)
+ 0xb0959953) \
+ V(_Double, unary-, DoubleFlipSignBit, 0x039c6e4a) \
+ V(_Double, truncateToDouble, DoubleTruncate, 0x2960d21d) \
+ V(_Double, roundToDouble, DoubleRound, 0x1cd615c4) \
+ V(_Double, floorToDouble, DoubleFloor, 0x1b41170c) \
+ V(_Double, ceilToDouble, DoubleCeil, 0x25a81a9d) \
+ V(_Double, _modulo, DoubleMod, 0x42a93471)
#define GRAPH_INTRINSICS_LIST(V) \
@@ -348,14 +346,14 @@
GRAPH_MATH_LIB_INTRINSIC_LIST(V) \
#define DEVELOPER_LIB_INTRINSIC_LIST(V) \
- V(_UserTag, makeCurrent, UserTag_makeCurrent, 0x0b3066fd) \
- V(::, _getDefaultTag, UserTag_defaultTag, 0x69f3f1ad) \
- V(::, _getCurrentTag, Profiler_getCurrentTag, 0x05fa99d2) \
- V(::, _isDartStreamEnabled, Timeline_isDartStreamEnabled, 0x72f13f7a) \
+ V(_UserTag, makeCurrent, UserTag_makeCurrent, 0x472d1eb5) \
+ V(::, _getDefaultTag, UserTag_defaultTag, 0x5c124271) \
+ V(::, _getCurrentTag, Profiler_getCurrentTag, 0x5d6d8a14) \
+ V(::, _isDartStreamEnabled, Timeline_isDartStreamEnabled, 0xcf6f3099) \
#define ASYNC_LIB_INTRINSIC_LIST(V) \
- V(::, _clearAsyncThreadStackTrace, ClearAsyncThreadStackTrace, 0x2edd4b25) \
- V(::, _setAsyncThreadStackTrace, SetAsyncThreadStackTrace, 0x04f429a7) \
+ V(::, _clearAsyncThreadStackTrace, ClearAsyncThreadStackTrace, 0x341efd8e) \
+ V(::, _setAsyncThreadStackTrace, SetAsyncThreadStackTrace, 0x5f29f453) \
#define ALL_INTRINSICS_NO_INTEGER_LIB_LIST(V) \
ASYNC_LIB_INTRINSIC_LIST(V) \
@@ -375,58 +373,58 @@
// A list of core functions that internally dispatch based on received id.
#define POLYMORPHIC_TARGET_LIST(V) \
- V(_StringBase, [], StringBaseCharAt, 0x7cbb8603) \
- V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0x7041895a) \
- V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0x336fa3ea) \
- V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0x231bbe2e) \
- V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0x0371785f) \
- V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0x65ab3a20) \
- V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x0cb0fcf6) \
- V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0x7db75d78) \
- V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0x1487cfc6) \
- V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0x6674ea6f) \
- V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0x236c6e7a) \
- V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0x5c367ffb) \
- V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0x772d1c0f) \
- V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0x12bae36a) \
- V(_TypedList, _setUint8, ByteArrayBaseSetInt8, 0x15821cc9) \
- V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0x1f8237fa) \
- V(_TypedList, _setUint16, ByteArrayBaseSetInt16, 0x181e5d16) \
- V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0x7ddb9f87) \
- V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0x74094f8d) \
- V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0x4741396e) \
- V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0x3b398ae4) \
- V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0x03db087b) \
- V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0x38a80b0d) \
- V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x40052c4e) \
- V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0x07b89f54) \
- V(Object, get:runtimeType, ObjectRuntimeType, 0x00e8ab29)
+ V(_StringBase, [], StringBaseCharAt, 0xe67164fe) \
+ V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0xa24c2704) \
+ V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0xa491df3e) \
+ V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0xb65ae1fc) \
+ V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0xb4b776e5) \
+ V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0xb460abe4) \
+ V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x8c066c71) \
+ V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0xacf2f222) \
+ V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0xa74b200b) \
+ V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0xa33a9f77) \
+ V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0x87d86b60) \
+ V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0x3e76086e) \
+ V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0xfea5f17f) \
+ V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0xd2c4e74b) \
+ V(_TypedList, _setUint8, ByteArrayBaseSetInt8, 0xec62b082) \
+ V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0xc3566903) \
+ V(_TypedList, _setUint16, ByteArrayBaseSetInt16, 0xdb50780f) \
+ V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0xbeeeea8a) \
+ V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0xca02f10a) \
+ V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0xcf587ccf) \
+ V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0xe01a1df0) \
+ V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0xb6a6294f) \
+ V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0xce7dad17) \
+ V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x4b773b59) \
+ V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0xfa2a6f88) \
+ V(Object, get:runtimeType, ObjectRuntimeType, 0x8cdba093)
// List of recognized list factories:
// (factory-name-symbol, class-name-string, constructor-name-string,
// result-cid, fingerprint).
#define RECOGNIZED_LIST_FACTORY_LIST(V) \
- V(_ListFactory, _List, ., kArrayCid, 0x2121902f) \
+ V(_ListFactory, _List, ., kArrayCid, 0xe9c6d2be) \
V(_GrowableListWithData, _GrowableList, ._withData, kGrowableObjectArrayCid, \
- 0x28b2138e) \
+ 0x55981e03) \
V(_GrowableListFactory, _GrowableList, ., kGrowableObjectArrayCid, \
0x3eed680b) \
- V(_Int8ArrayFactory, Int8List, ., kTypedDataInt8ArrayCid, 0x7e39a3a1) \
- V(_Uint8ArrayFactory, Uint8List, ., kTypedDataUint8ArrayCid, 0x3a79adf7) \
+ V(_Int8ArrayFactory, Int8List, ., kTypedDataInt8ArrayCid, 0x6ce2f102) \
+ V(_Uint8ArrayFactory, Uint8List, ., kTypedDataUint8ArrayCid, 0x1163d489) \
V(_Uint8ClampedArrayFactory, Uint8ClampedList, ., \
- kTypedDataUint8ClampedArrayCid, 0x67f38395) \
- V(_Int16ArrayFactory, Int16List, ., kTypedDataInt16ArrayCid, 0x6477bda8) \
- V(_Uint16ArrayFactory, Uint16List, ., kTypedDataUint16ArrayCid, 0x5707c5a2) \
- V(_Int32ArrayFactory, Int32List, ., kTypedDataInt32ArrayCid, 0x2b96ec0e) \
- V(_Uint32ArrayFactory, Uint32List, ., kTypedDataUint32ArrayCid, 0x0c1c0d62) \
- V(_Int64ArrayFactory, Int64List, ., kTypedDataInt64ArrayCid, 0x279ab485) \
- V(_Uint64ArrayFactory, Uint64List, ., kTypedDataUint64ArrayCid, 0x7bcb89c2) \
+ kTypedDataUint8ClampedArrayCid, 0x0b0e9f0f) \
+ V(_Int16ArrayFactory, Int16List, ., kTypedDataInt16ArrayCid, 0x6addd02d) \
+ V(_Uint16ArrayFactory, Uint16List, ., kTypedDataUint16ArrayCid, 0x139a6464) \
+ V(_Int32ArrayFactory, Int32List, ., kTypedDataInt32ArrayCid, 0x40dad19a) \
+ V(_Uint32ArrayFactory, Uint32List, ., kTypedDataUint32ArrayCid, 0x988357c5) \
+ V(_Int64ArrayFactory, Int64List, ., kTypedDataInt64ArrayCid, 0xef0a3469) \
+ V(_Uint64ArrayFactory, Uint64List, ., kTypedDataUint64ArrayCid, 0xf49c0472) \
V(_Float64ArrayFactory, Float64List, ., kTypedDataFloat64ArrayCid, \
- 0x1fde3eaf) \
+ 0xf623554b) \
V(_Float32ArrayFactory, Float32List, ., kTypedDataFloat32ArrayCid, \
- 0x43506c09) \
+ 0x779b26f8) \
V(_Float32x4ArrayFactory, Float32x4List, ., kTypedDataFloat32x4ArrayCid, \
- 0x4a4030d6)
+ 0x9edf5402)
// clang-format on
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index ef2bc61..0579418 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -755,15 +755,22 @@
#endif // !defined(PRODUCT)
};
+class SharedClassTable : public AllStatic {
+ public:
+ static word class_heap_stats_table_offset();
+};
+
class ClassTable : public AllStatic {
public:
static word table_offset();
+ static word shared_class_table_offset();
#if !defined(PRODUCT)
static word ClassOffsetFor(intptr_t cid);
static word StateOffsetFor(intptr_t cid);
- static word class_heap_stats_table_offset();
static word NewSpaceCounterOffsetFor(intptr_t cid);
static word NewSpaceSizeOffsetFor(intptr_t cid);
+ static word SharedTableOffsetFor();
+ static word SizeOffsetFor(intptr_t cid, bool is_new);
#endif // !defined(PRODUCT)
static const word kSizeOfClassPairLog2;
};
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 021c6dd..add5eab 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -22,8 +22,6 @@
static constexpr dart::compiler::target::word Array_kMaxElements = 268435455;
static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements =
65533;
-static constexpr dart::compiler::target::word ClassTable_kSizeOfClassPairLog2 =
- 3;
static constexpr dart::compiler::target::word
Instructions_kMonomorphicEntryOffsetJIT = 0;
static constexpr dart::compiler::target::word
@@ -85,7 +83,11 @@
static constexpr dart::compiler::target::word
ClassHeapStats_allocated_size_since_gc_new_space_offset = 52;
static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 160;
+static constexpr dart::compiler::target::word
+ ClassTable_shared_class_table_offset = 20;
static constexpr dart::compiler::target::word ClassTable_table_offset = 8;
+static constexpr dart::compiler::target::word
+ SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 20;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 12;
@@ -138,12 +140,12 @@
static constexpr dart::compiler::target::word ICData_state_bits_offset = 28;
static constexpr dart::compiler::target::word
ICData_receivers_static_type_offset = 16;
-static constexpr dart::compiler::target::word Isolate_class_table_offset = 36;
+static constexpr dart::compiler::target::word Isolate_class_table_offset = 40;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
-static constexpr dart::compiler::target::word Isolate_object_store_offset = 32;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 56;
+static constexpr dart::compiler::target::word Isolate_object_store_offset = 36;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 64;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16;
static constexpr dart::compiler::target::word
@@ -339,8 +341,6 @@
static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
0;
static constexpr dart::compiler::target::word ClassTable_element_size = 168;
-static constexpr dart::compiler::target::word
- ClassTable_class_heap_stats_table_offset = 16;
static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
4, 12, 8, 16};
static constexpr dart::compiler::target::word
@@ -378,8 +378,6 @@
576460752303423487;
static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements =
32765;
-static constexpr dart::compiler::target::word ClassTable_kSizeOfClassPairLog2 =
- 4;
static constexpr dart::compiler::target::word
Instructions_kMonomorphicEntryOffsetJIT = 8;
static constexpr dart::compiler::target::word
@@ -442,7 +440,11 @@
static constexpr dart::compiler::target::word
ClassHeapStats_allocated_size_since_gc_new_space_offset = 104;
static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 272;
+static constexpr dart::compiler::target::word
+ ClassTable_shared_class_table_offset = 40;
static constexpr dart::compiler::target::word ClassTable_table_offset = 16;
+static constexpr dart::compiler::target::word
+ SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 40;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 24;
@@ -495,12 +497,12 @@
static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
static constexpr dart::compiler::target::word
ICData_receivers_static_type_offset = 32;
-static constexpr dart::compiler::target::word Isolate_class_table_offset = 72;
+static constexpr dart::compiler::target::word Isolate_class_table_offset = 80;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
-static constexpr dart::compiler::target::word Isolate_object_store_offset = 64;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 112;
+static constexpr dart::compiler::target::word Isolate_object_store_offset = 72;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 128;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32;
static constexpr dart::compiler::target::word
@@ -698,8 +700,6 @@
static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
0;
static constexpr dart::compiler::target::word ClassTable_element_size = 288;
-static constexpr dart::compiler::target::word
- ClassTable_class_heap_stats_table_offset = 32;
static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
8, 24, 16, 32};
static constexpr dart::compiler::target::word
@@ -736,8 +736,6 @@
static constexpr dart::compiler::target::word Array_kMaxElements = 268435455;
static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements =
65533;
-static constexpr dart::compiler::target::word ClassTable_kSizeOfClassPairLog2 =
- 3;
static constexpr dart::compiler::target::word
Instructions_kMonomorphicEntryOffsetJIT = 6;
static constexpr dart::compiler::target::word
@@ -799,7 +797,11 @@
static constexpr dart::compiler::target::word
ClassHeapStats_allocated_size_since_gc_new_space_offset = 52;
static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 160;
+static constexpr dart::compiler::target::word
+ ClassTable_shared_class_table_offset = 20;
static constexpr dart::compiler::target::word ClassTable_table_offset = 8;
+static constexpr dart::compiler::target::word
+ SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 20;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 12;
@@ -852,12 +854,12 @@
static constexpr dart::compiler::target::word ICData_state_bits_offset = 28;
static constexpr dart::compiler::target::word
ICData_receivers_static_type_offset = 16;
-static constexpr dart::compiler::target::word Isolate_class_table_offset = 36;
+static constexpr dart::compiler::target::word Isolate_class_table_offset = 40;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
-static constexpr dart::compiler::target::word Isolate_object_store_offset = 32;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 56;
+static constexpr dart::compiler::target::word Isolate_object_store_offset = 36;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 64;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16;
static constexpr dart::compiler::target::word
@@ -1053,8 +1055,6 @@
static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
0;
static constexpr dart::compiler::target::word ClassTable_element_size = 168;
-static constexpr dart::compiler::target::word
- ClassTable_class_heap_stats_table_offset = 16;
static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
4, 12, 8, 16};
static constexpr dart::compiler::target::word
@@ -1088,8 +1088,6 @@
576460752303423487;
static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements =
32765;
-static constexpr dart::compiler::target::word ClassTable_kSizeOfClassPairLog2 =
- 4;
static constexpr dart::compiler::target::word
Instructions_kMonomorphicEntryOffsetJIT = 8;
static constexpr dart::compiler::target::word
@@ -1152,7 +1150,11 @@
static constexpr dart::compiler::target::word
ClassHeapStats_allocated_size_since_gc_new_space_offset = 104;
static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 272;
+static constexpr dart::compiler::target::word
+ ClassTable_shared_class_table_offset = 40;
static constexpr dart::compiler::target::word ClassTable_table_offset = 16;
+static constexpr dart::compiler::target::word
+ SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 40;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 24;
@@ -1205,12 +1207,12 @@
static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
static constexpr dart::compiler::target::word
ICData_receivers_static_type_offset = 32;
-static constexpr dart::compiler::target::word Isolate_class_table_offset = 72;
+static constexpr dart::compiler::target::word Isolate_class_table_offset = 80;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
-static constexpr dart::compiler::target::word Isolate_object_store_offset = 64;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 112;
+static constexpr dart::compiler::target::word Isolate_object_store_offset = 72;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 128;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32;
static constexpr dart::compiler::target::word
@@ -1408,8 +1410,6 @@
static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
0;
static constexpr dart::compiler::target::word ClassTable_element_size = 288;
-static constexpr dart::compiler::target::word
- ClassTable_class_heap_stats_table_offset = 32;
static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
8, 24, 16, 32};
static constexpr dart::compiler::target::word
@@ -1448,8 +1448,6 @@
576460752303423487;
static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements =
32765;
-static constexpr dart::compiler::target::word ClassTable_kSizeOfClassPairLog2 =
- 4;
static constexpr dart::compiler::target::word
Instructions_kMonomorphicEntryOffsetJIT = 0;
static constexpr dart::compiler::target::word
@@ -1512,7 +1510,11 @@
static constexpr dart::compiler::target::word
ClassHeapStats_allocated_size_since_gc_new_space_offset = 104;
static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 272;
+static constexpr dart::compiler::target::word
+ ClassTable_shared_class_table_offset = 40;
static constexpr dart::compiler::target::word ClassTable_table_offset = 16;
+static constexpr dart::compiler::target::word
+ SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 40;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 24;
@@ -1565,12 +1567,12 @@
static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
static constexpr dart::compiler::target::word
ICData_receivers_static_type_offset = 32;
-static constexpr dart::compiler::target::word Isolate_class_table_offset = 72;
+static constexpr dart::compiler::target::word Isolate_class_table_offset = 80;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
-static constexpr dart::compiler::target::word Isolate_object_store_offset = 64;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 112;
+static constexpr dart::compiler::target::word Isolate_object_store_offset = 72;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 128;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32;
static constexpr dart::compiler::target::word
@@ -1700,8 +1702,6 @@
static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
0;
static constexpr dart::compiler::target::word ClassTable_element_size = 288;
-static constexpr dart::compiler::target::word
- ClassTable_class_heap_stats_table_offset = 32;
static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
8, 24, 16, 32};
static constexpr dart::compiler::target::word
@@ -1734,8 +1734,6 @@
static constexpr dart::compiler::target::word Array_kMaxElements = 268435455;
static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements =
65533;
-static constexpr dart::compiler::target::word ClassTable_kSizeOfClassPairLog2 =
- 3;
static constexpr dart::compiler::target::word
Instructions_kMonomorphicEntryOffsetJIT = 0;
static constexpr dart::compiler::target::word
@@ -1797,7 +1795,11 @@
static constexpr dart::compiler::target::word
ClassHeapStats_allocated_size_since_gc_new_space_offset = 52;
static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 160;
+static constexpr dart::compiler::target::word
+ ClassTable_shared_class_table_offset = 20;
static constexpr dart::compiler::target::word ClassTable_table_offset = 8;
+static constexpr dart::compiler::target::word
+ SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 20;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 12;
@@ -1850,12 +1852,12 @@
static constexpr dart::compiler::target::word ICData_state_bits_offset = 28;
static constexpr dart::compiler::target::word
ICData_receivers_static_type_offset = 16;
-static constexpr dart::compiler::target::word Isolate_class_table_offset = 36;
+static constexpr dart::compiler::target::word Isolate_class_table_offset = 40;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
-static constexpr dart::compiler::target::word Isolate_object_store_offset = 32;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 56;
+static constexpr dart::compiler::target::word Isolate_object_store_offset = 36;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 64;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16;
static constexpr dart::compiler::target::word
@@ -1984,8 +1986,6 @@
static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
0;
static constexpr dart::compiler::target::word ClassTable_element_size = 168;
-static constexpr dart::compiler::target::word
- ClassTable_class_heap_stats_table_offset = 16;
static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
4, 12, 8, 16};
static constexpr dart::compiler::target::word
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index f67e729..eb574eb 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -34,7 +34,6 @@
ARRAY(ObjectPool, element_offset) \
CONSTANT(Array, kMaxElements) \
CONSTANT(Array, kMaxNewSpaceElements) \
- CONSTANT(ClassTable, kSizeOfClassPairLog2) \
CONSTANT(Instructions, kMonomorphicEntryOffsetJIT) \
CONSTANT(Instructions, kPolymorphicEntryOffsetJIT) \
CONSTANT(Instructions, kMonomorphicEntryOffsetAOT) \
@@ -71,7 +70,9 @@
NOT_IN_PRODUCT( \
FIELD(ClassHeapStats, allocated_size_since_gc_new_space_offset)) \
NOT_IN_PRODUCT(FIELD(ClassHeapStats, state_offset)) \
+ FIELD(ClassTable, shared_class_table_offset) \
FIELD(ClassTable, table_offset) \
+ NOT_IN_PRODUCT(FIELD(SharedClassTable, class_heap_stats_table_offset)) \
FIELD(Closure, context_offset) \
FIELD(Closure, delayed_type_arguments_offset) \
FIELD(Closure, function_offset) \
@@ -244,7 +245,6 @@
NOT_IN_PRODUCT(ARRAY_STRUCTFIELD( \
ClassTable, NewSpaceSizeOffsetFor, ClassOffsetFor, \
ClassHeapStats::allocated_size_since_gc_new_space_offset())) \
- NOT_IN_PRODUCT(FIELD(ClassTable, class_heap_stats_table_offset)) \
RANGE(Code, entry_point_offset, CodeEntryKind, CodeEntryKind::kNormal, \
CodeEntryKind::kMonomorphicUnchecked, \
[](CodeEntryKind value) { return true; }) \
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index c565ba5..16746a5 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -2796,12 +2796,8 @@
// Non-Closure handling.
{
__ Bind(¬_closure);
- if (n == 1) {
- __ SmiTag(kInstanceCidOrFunction);
- } else {
- ASSERT(n >= 2);
+ if (n >= 2) {
Label has_no_type_arguments;
- // [LoadClassById] also tags [kInstanceCidOrFunction] as a side-effect.
__ LoadClassById(R5, kInstanceCidOrFunction);
__ mov(kInstanceInstantiatorTypeArgumentsReg, kNullReg);
__ LoadFieldFromOffset(
@@ -2818,6 +2814,7 @@
__ mov(kInstanceDelayedFunctionTypeArgumentsReg, kNullReg);
}
}
+ __ SmiTag(kInstanceCidOrFunction);
}
Label found, not_found, next_iteration;
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index 7ac6ced..b376b02 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -2782,12 +2782,8 @@
// Non-Closure handling.
{
__ Bind(¬_closure);
- if (n == 1) {
- __ SmiTag(kInstanceCidOrFunction);
- } else {
- ASSERT(n >= 2);
+ if (n >= 2) {
Label has_no_type_arguments;
- // [LoadClassById] also tags [kInstanceCidOrFunction] as a side-effect.
__ LoadClassById(RDI, kInstanceCidOrFunction);
__ movq(kInstanceInstantiatorTypeArgumentsReg, kNullReg);
__ movl(
@@ -2806,6 +2802,7 @@
__ movq(kInstanceDelayedFunctionTypeArgumentsReg, kNullReg);
}
}
+ __ SmiTag(kInstanceCidOrFunction);
}
Label found, not_found, next_iteration;
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 59f903a..0463a15 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -859,14 +859,6 @@
#else
#error What architecture?
#endif
- } else {
-#if defined(ARCH_IS_32_BIT)
- buffer.AddString(" 32-bit");
-#elif defined(ARCH_IS_64_BIT)
- buffer.AddString(" 64-bit");
-#else
-#error What word size?
-#endif
}
if (FLAG_precompiled_mode && FLAG_dwarf_stack_traces) {
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 4b259aa..4c62313 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1666,21 +1666,10 @@
Symbols::Compact();
- uint8_t* vm_snapshot_instruction_buffer = nullptr;
- BlobImageWriter vm_image_writer(T, &vm_snapshot_instruction_buffer,
- ApiReallocate, 2 * MB /* initial_size */,
- /*shared_objects=*/nullptr,
- /*shared_instructions=*/nullptr,
- /*reused_instructions=*/nullptr);
- uint8_t* isolate_snapshot_instruction_buffer = nullptr;
- BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instruction_buffer,
- ApiReallocate, 2 * MB /* initial_size */,
- /*shared_objects=*/nullptr,
- /*shared_instructions=*/nullptr,
- /*reused_instructions=*/nullptr);
FullSnapshotWriter writer(Snapshot::kFull, vm_snapshot_data_buffer,
isolate_snapshot_data_buffer, ApiReallocate,
- &vm_image_writer, &isolate_image_writer);
+ NULL /* vm_image_writer */,
+ NULL /* isolate_image_writer */);
writer.WriteFullSnapshot();
if (vm_snapshot_data_buffer != NULL) {
*vm_snapshot_data_size = writer.VmIsolateSnapshotSize();
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 0dd231a..6e3bcc2 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -637,13 +637,14 @@
}
}
-// Compute token_pos_ and token_pos_initialized_.
-// If not IsInterpreted(), then also compute try_index_ and deopt_id_.
+// If not token_pos_initialized_, compute token_pos_, try_index_ and,
+// if not IsInterpreted(), also compute deopt_id_.
TokenPosition ActivationFrame::TokenPos() {
if (!token_pos_initialized_) {
token_pos_initialized_ = true;
if (IsInterpreted()) {
token_pos_ = bytecode().GetTokenIndexOfPC(pc_);
+ try_index_ = bytecode().GetTryIndexAtPc(pc_);
return token_pos_;
}
token_pos_ = TokenPosition::kNoSource;
@@ -663,16 +664,6 @@
}
intptr_t ActivationFrame::TryIndex() {
-#if !defined(DART_PRECOMPILED_RUNTIME)
- if (IsInterpreted()) {
- if (pc_desc_.IsNull()) {
- ASSERT(try_index_ == -1);
- pc_desc_ = bytecode().pc_descriptors();
- try_index_ = bytecode().GetTryIndexAtPc(pc_);
- }
- return try_index_;
- }
-#endif // !defined(DART_PRECOMPILED_RUNTIME)
if (!token_pos_initialized_) {
TokenPos(); // Side effect: computes token_pos_initialized_, try_index_.
}
@@ -2467,9 +2458,9 @@
// Grab the awaiter.
async_activation ^= activation->GetAsyncAwaiter();
async_stack_trace ^= activation->GetCausalStack();
- // see comment regarding skipping frames of async functions called
- // synchronously above.
- skip_sync_async_frames_count = 2;
+ // Interpreted bytecode does not invoke _ClosureCall().
+ // Skip _AsyncAwaitCompleterStart() only.
+ skip_sync_async_frames_count = 1;
} else {
stack_trace->AddActivation(
CollectDartFrame(isolate, frame->pc(), frame, bytecode));
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 2e9d7f4..33487fb 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -885,10 +885,10 @@
for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
const auto selector = static_cast<Heap::WeakSelector>(sel);
auto before_table = GetWeakTable(before_space, selector);
- intptr_t entry = before_table->RemoveValue(before_object);
+ intptr_t entry = before_table->RemoveValueExclusive(before_object);
if (entry != 0) {
auto after_table = GetWeakTable(after_space, selector);
- after_table->SetValue(after_object, entry);
+ after_table->SetValueExclusive(after_object, entry);
}
}
diff --git a/runtime/vm/heap/heap_test.cc b/runtime/vm/heap/heap_test.cc
index c79848e..a456287 100644
--- a/runtime/vm/heap/heap_test.cc
+++ b/runtime/vm/heap/heap_test.cc
@@ -82,7 +82,7 @@
public:
static ClassHeapStats* GetHeapStatsForCid(ClassTable* class_table,
intptr_t cid) {
- return class_table->PreliminaryStatsAt(cid);
+ return class_table->shared_class_table()->PreliminaryStatsAt(cid);
}
static void DumpClassHeapStats(ClassHeapStats* stats) {
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index be5a212..5558aa8 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -90,7 +90,7 @@
: ObjectPointerVisitor(isolate),
thread_(Thread::Current()),
#ifndef PRODUCT
- num_classes_(isolate->class_table()->Capacity()),
+ num_classes_(isolate->shared_class_table()->Capacity()),
class_stats_count_(new intptr_t[num_classes_]),
class_stats_size_(new intptr_t[num_classes_]),
#endif // !PRODUCT
@@ -372,7 +372,8 @@
class MarkingWeakVisitor : public HandleVisitor {
public:
explicit MarkingWeakVisitor(Thread* thread)
- : HandleVisitor(thread), class_table_(thread->isolate()->class_table()) {}
+ : HandleVisitor(thread),
+ class_table_(thread->isolate()->shared_class_table()) {}
void VisitHandle(uword addr) {
FinalizablePersistentHandle* handle =
@@ -394,7 +395,7 @@
}
private:
- ClassTable* class_table_;
+ SharedClassTable* class_table_;
DISALLOW_COPY_AND_ASSIGN(MarkingWeakVisitor);
};
@@ -500,11 +501,11 @@
heap_->GetWeakTable(Heap::kOld, static_cast<Heap::WeakSelector>(sel));
intptr_t size = table->size();
for (intptr_t i = 0; i < size; i++) {
- if (table->IsValidEntryAt(i)) {
- RawObject* raw_obj = table->ObjectAt(i);
+ if (table->IsValidEntryAtExclusive(i)) {
+ RawObject* raw_obj = table->ObjectAtExclusive(i);
ASSERT(raw_obj->IsHeapObject());
if (!raw_obj->IsMarked()) {
- table->InvalidateAt(i);
+ table->InvalidateAtExclusive(i);
}
}
}
@@ -724,7 +725,7 @@
#ifndef PRODUCT
// Class heap stats are not themselves thread-safe yet, so we update the
// stats while holding stats_mutex_.
- ClassTable* table = heap_->isolate()->class_table();
+ auto table = heap_->isolate()->shared_class_table();
for (intptr_t i = 0; i < table->NumCids(); ++i) {
const intptr_t count = visitor->live_count(i);
if (count > 0) {
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 4a85864..88222d0 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -541,7 +541,8 @@
intptr_t size_in_words = size >> kWordSizeLog2;
AtomicOperations::IncrementBy(&(usage_.external_in_words), size_in_words);
NOT_IN_PRODUCT(
- heap_->isolate()->class_table()->UpdateAllocatedExternalOld(cid, size));
+ heap_->isolate()->shared_class_table()->UpdateAllocatedExternalOld(cid,
+ size));
}
void PageSpace::PromoteExternal(intptr_t cid, intptr_t size) {
@@ -1097,7 +1098,7 @@
return;
}
- NOT_IN_PRODUCT(isolate->class_table()->ResetCountersOld());
+ NOT_IN_PRODUCT(isolate->shared_class_table()->ResetCountersOld());
marker_->MarkObjects(this);
usage_.used_in_words = marker_->marked_words() + allocated_black_in_words_;
allocated_black_in_words_ = 0;
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index accb638..b92a870 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -281,7 +281,7 @@
ScavengerWeakVisitor(Thread* thread, Scavenger* scavenger)
: HandleVisitor(thread),
scavenger_(scavenger),
- class_table_(thread->isolate()->class_table()) {
+ class_table_(thread->isolate()->shared_class_table()) {
ASSERT(scavenger->heap_->isolate() == thread->isolate());
}
@@ -307,7 +307,7 @@
private:
Scavenger* scavenger_;
- ClassTable* class_table_;
+ SharedClassTable* class_table_;
DISALLOW_COPY_AND_ASSIGN(ScavengerWeakVisitor);
};
@@ -486,7 +486,7 @@
}
SemiSpace* Scavenger::Prologue(Isolate* isolate) {
- NOT_IN_PRODUCT(isolate->class_table()->ResetCountersNew());
+ NOT_IN_PRODUCT(isolate->shared_class_table()->ResetCountersNew());
isolate->ReleaseStoreBuffers();
AbandonTLABs(isolate);
@@ -593,7 +593,7 @@
heap_->UpdateGlobalMaxUsed();
}
- NOT_IN_PRODUCT(isolate->class_table()->UpdatePromoted());
+ NOT_IN_PRODUCT(isolate->shared_class_table()->UpdatePromoted());
}
bool Scavenger::ShouldPerformIdleScavenge(int64_t deadline) {
@@ -708,7 +708,7 @@
void Scavenger::ProcessToSpace(ScavengerVisitor* visitor) {
Thread* thread = Thread::Current();
- NOT_IN_PRODUCT(ClassTable* class_table = thread->isolate()->class_table());
+ NOT_IN_PRODUCT(auto class_table = visitor->isolate()->shared_class_table());
// Iterate until all work has been drained.
while ((resolved_top_ < top_) || PromotedStackHasMore()) {
@@ -851,8 +851,8 @@
WeakTable* replacement_old) {
intptr_t size = table->size();
for (intptr_t i = 0; i < size; i++) {
- if (table->IsValidEntryAt(i)) {
- RawObject* raw_obj = table->ObjectAt(i);
+ if (table->IsValidEntryAtExclusive(i)) {
+ RawObject* raw_obj = table->ObjectAtExclusive(i);
ASSERT(raw_obj->IsHeapObject());
uword raw_addr = RawObject::ToAddr(raw_obj);
uword header = *reinterpret_cast<uword*>(raw_addr);
@@ -862,7 +862,7 @@
raw_obj = RawObject::FromAddr(new_addr);
auto replacement =
raw_obj->IsNewObject() ? replacement_new : replacement_old;
- replacement->SetValue(raw_obj, table->ValueAt(i));
+ replacement->SetValueExclusive(raw_obj, table->ValueAtExclusive(i));
}
}
}
@@ -1161,7 +1161,8 @@
ASSERT(size >= 0);
external_size_ += size;
NOT_IN_PRODUCT(
- heap_->isolate()->class_table()->UpdateAllocatedExternalNew(cid, size));
+ heap_->isolate()->shared_class_table()->UpdateAllocatedExternalNew(cid,
+ size));
}
void Scavenger::FreeExternal(intptr_t size) {
diff --git a/runtime/vm/heap/weak_table.cc b/runtime/vm/heap/weak_table.cc
index 4fd7917..95acc86 100644
--- a/runtime/vm/heap/weak_table.cc
+++ b/runtime/vm/heap/weak_table.cc
@@ -29,11 +29,11 @@
return result;
}
-void WeakTable::SetValue(RawObject* key, intptr_t val) {
+void WeakTable::SetValueExclusive(RawObject* key, intptr_t val) {
intptr_t mask = size() - 1;
intptr_t idx = Hash(key) & mask;
intptr_t empty_idx = -1;
- RawObject* obj = ObjectAt(idx);
+ RawObject* obj = ObjectAtExclusive(idx);
while (obj != NULL) {
if (obj == key) {
@@ -44,7 +44,7 @@
empty_idx = idx; // Insert at this location if not found.
}
idx = (idx + 1) & mask;
- obj = ObjectAt(idx);
+ obj = ObjectAtExclusive(idx);
}
if (val == 0) {
@@ -60,7 +60,7 @@
idx = empty_idx;
}
- ASSERT(!IsValidEntryAt(idx));
+ ASSERT(!IsValidEntryAtExclusive(idx));
// Set the key and value.
SetObjectAt(idx, key);
SetValueAt(idx, val);
@@ -87,7 +87,7 @@
if (used_ == 0) return;
for (intptr_t i = 0; i < size_; i++) {
- if (IsValidEntryAt(i)) {
+ if (IsValidEntryAtExclusive(i)) {
visitor->VisitPointer(ObjectPointerAt(i));
}
}
@@ -107,9 +107,9 @@
intptr_t mask = new_size - 1;
set_used(0);
for (intptr_t i = 0; i < old_size; i++) {
- if (IsValidEntryAt(i)) {
+ if (IsValidEntryAtExclusive(i)) {
// Find the new hash location for this entry.
- RawObject* key = ObjectAt(i);
+ RawObject* key = ObjectAtExclusive(i);
intptr_t idx = Hash(key) & mask;
RawObject* obj = reinterpret_cast<RawObject*>(new_data[ObjectIndex(idx)]);
while (obj != NULL) {
@@ -119,7 +119,7 @@
}
new_data[ObjectIndex(idx)] = reinterpret_cast<intptr_t>(key);
- new_data[ValueIndex(idx)] = ValueAt(i);
+ new_data[ValueIndex(idx)] = ValueAtExclusive(i);
set_used(used() + 1);
}
}
diff --git a/runtime/vm/heap/weak_table.h b/runtime/vm/heap/weak_table.h
index c7970cf..c1487b1 100644
--- a/runtime/vm/heap/weak_table.h
+++ b/runtime/vm/heap/weak_table.h
@@ -8,6 +8,7 @@
#include "vm/globals.h"
#include "platform/assert.h"
+#include "vm/lockers.h"
#include "vm/raw_object.h"
namespace dart {
@@ -46,64 +47,82 @@
intptr_t used() const { return used_; }
intptr_t count() const { return count_; }
- bool IsValidEntryAt(intptr_t i) const {
- ASSERT(((ValueAt(i) == 0) && ((ObjectAt(i) == NULL) ||
- (data_[ObjectIndex(i)] == kDeletedEntry))) ||
- ((ValueAt(i) != 0) && (ObjectAt(i) != NULL) &&
- (data_[ObjectIndex(i)] != kDeletedEntry)));
+ // The following methods can be called concurrently and are guarded by a lock.
+
+ intptr_t GetValue(RawObject* key) {
+ MutexLocker ml(&mutex_);
+ return GetValueExclusive(key);
+ }
+
+ void SetValue(RawObject* key, intptr_t val) {
+ MutexLocker ml(&mutex_);
+ return SetValueExclusive(key, val);
+ }
+
+ // The following "exclusive" methods must only be called from call sites
+ // which are known to have exclusive access to the weak table.
+ //
+ // This is mostly limited to GC related code (e.g. scavenger, marker, ...)
+
+ bool IsValidEntryAtExclusive(intptr_t i) const {
+ ASSERT((ValueAtExclusive(i) == 0 &&
+ (ObjectAtExclusive(i) == NULL ||
+ data_[ObjectIndex(i)] == kDeletedEntry)) ||
+ (ValueAtExclusive(i) != 0 && ObjectAtExclusive(i) != NULL &&
+ data_[ObjectIndex(i)] != kDeletedEntry));
return (data_[ValueIndex(i)] != 0);
}
- void InvalidateAt(intptr_t i) {
- ASSERT(IsValidEntryAt(i));
+ void InvalidateAtExclusive(intptr_t i) {
+ ASSERT(IsValidEntryAtExclusive(i));
SetValueAt(i, 0);
}
- RawObject* ObjectAt(intptr_t i) const {
+ RawObject* ObjectAtExclusive(intptr_t i) const {
ASSERT(i >= 0);
ASSERT(i < size());
return reinterpret_cast<RawObject*>(data_[ObjectIndex(i)]);
}
- intptr_t ValueAt(intptr_t i) const {
+ intptr_t ValueAtExclusive(intptr_t i) const {
ASSERT(i >= 0);
ASSERT(i < size());
return data_[ValueIndex(i)];
}
- void SetValue(RawObject* key, intptr_t val);
+ void SetValueExclusive(RawObject* key, intptr_t val);
- intptr_t GetValue(RawObject* key) const {
+ intptr_t GetValueExclusive(RawObject* key) const {
intptr_t mask = size() - 1;
intptr_t idx = Hash(key) & mask;
- RawObject* obj = ObjectAt(idx);
+ RawObject* obj = ObjectAtExclusive(idx);
while (obj != NULL) {
if (obj == key) {
- return ValueAt(idx);
+ return ValueAtExclusive(idx);
}
idx = (idx + 1) & mask;
- obj = ObjectAt(idx);
+ obj = ObjectAtExclusive(idx);
}
- ASSERT(ValueAt(idx) == 0);
+ ASSERT(ValueAtExclusive(idx) == 0);
return 0;
}
// Removes and returns the value associated with |key|. Returns 0 if there is
// no value associated with |key|.
- intptr_t RemoveValue(RawObject* key) {
+ intptr_t RemoveValueExclusive(RawObject* key) {
intptr_t mask = size() - 1;
intptr_t idx = Hash(key) & mask;
- RawObject* obj = ObjectAt(idx);
+ RawObject* obj = ObjectAtExclusive(idx);
while (obj != NULL) {
if (obj == key) {
- intptr_t result = ValueAt(idx);
- InvalidateAt(idx);
+ intptr_t result = ValueAtExclusive(idx);
+ InvalidateAtExclusive(idx);
return result;
}
idx = (idx + 1) & mask;
- obj = ObjectAt(idx);
+ obj = ObjectAtExclusive(idx);
}
- ASSERT(ValueAt(idx) == 0);
+ ASSERT(ValueAtExclusive(idx) == 0);
return 0;
}
@@ -174,6 +193,8 @@
return reinterpret_cast<uintptr_t>(key) * 92821;
}
+ Mutex mutex_;
+
// data_ contains size_ tuples of key/value.
intptr_t* data_;
// size_ keeps the number of entries in data_. used_ maintains the number of
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 03672dc..c097744 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -1090,6 +1090,7 @@
shared_data_image_(shared_data_image),
shared_instructions_image_(shared_instructions_image) {
ASSERT(data_image != NULL);
+ ASSERT(instructions_image != NULL);
}
RawApiError* ImageReader::VerifyAlignment() const {
@@ -1106,7 +1107,6 @@
}
RawInstructions* ImageReader::GetInstructionsAt(int32_t offset) const {
- ASSERT(instructions_image_ != nullptr);
ASSERT(Utils::IsAligned(offset, OS::PreferredCodeAlignment()));
RawObject* result;
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index 77bd91d..e4a735a 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -264,7 +264,7 @@
RawObject** result) {
const uword start = thread->top();
#ifndef PRODUCT
- ClassTable* table = thread->isolate()->class_table();
+ auto table = thread->isolate()->shared_class_table();
if (UNLIKELY(table->TraceAllocationFor(class_id))) {
return false;
}
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index c341416..261fde1 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1050,7 +1050,8 @@
current_tag_(UserTag::null()),
default_tag_(UserTag::null()),
ic_miss_code_(Code::null()),
- class_table_(),
+ shared_class_table_(new SharedClassTable()),
+ class_table_(shared_class_table_.get()),
store_buffer_(new StoreBuffer()),
#if !defined(TARGET_ARCH_DBC) && !defined(DART_PRECOMPILED_RUNTIME)
native_callback_trampolines_(),
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 48895f3..faef0b3 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -340,6 +340,9 @@
SafepointHandler* safepoint_handler() const {
return group()->safepoint_handler();
}
+
+ SharedClassTable* shared_class_table() { return shared_class_table_.get(); }
+
ClassTable* class_table() { return &class_table_; }
static intptr_t class_table_offset() {
return OFFSET_OF(Isolate, class_table_);
@@ -1023,6 +1026,7 @@
RawUserTag* current_tag_;
RawUserTag* default_tag_;
RawCode* ic_miss_code_;
+ std::unique_ptr<SharedClassTable> shared_class_table_;
ObjectStore* object_store_ = nullptr;
ClassTable class_table_;
bool single_step_ = false;
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 640c358..17fa30e 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -676,9 +676,6 @@
if (skip_reload) {
ASSERT(modified_libs_->IsEmpty());
reload_skipped_ = true;
- // Inform GetUnusedChangesInLastReload that a reload has happened.
- I->object_store()->set_changed_in_last_reload(
- GrowableObjectArray::Handle(GrowableObjectArray::New()));
ReportOnJSON(js_);
// If we use the CFE and performed a compilation, we need to notify that
@@ -1218,81 +1215,6 @@
}
#endif
-static void RecordChanges(const GrowableObjectArray& changed_in_last_reload,
- const Class& old_cls,
- const Class& new_cls) {
- // All members of enum classes are synthetic, so nothing to report here.
- if (new_cls.is_enum_class()) {
- return;
- }
-
- // Don't report `typedef bool Predicate(Object o)` as unused. There is nothing
- // to execute.
- if (new_cls.IsTypedefClass()) {
- return;
- }
-
- if (new_cls.raw() == old_cls.raw()) {
- // A new class maps to itself. All its functions, field initizers, and so
- // on are new.
- changed_in_last_reload.Add(new_cls);
- return;
- }
-
- if (old_cls.IsTopLevel()) {
- return;
- }
-
- if (!old_cls.is_finalized()) {
- if (new_cls.SourceFingerprint() == old_cls.SourceFingerprint()) {
- return;
- }
- // We don't know the members. Register interest in the whole class. Creates
- // false positives.
- changed_in_last_reload.Add(new_cls);
- return;
- }
- ASSERT(new_cls.is_finalized());
-
- Zone* zone = Thread::Current()->zone();
- const Array& functions = Array::Handle(zone, new_cls.functions());
- const Array& fields = Array::Handle(zone, new_cls.fields());
- Function& new_function = Function::Handle(zone);
- Function& old_function = Function::Handle(zone);
- Field& new_field = Field::Handle(zone);
- Field& old_field = Field::Handle(zone);
- String& selector = String::Handle(zone);
- for (intptr_t i = 0; i < functions.Length(); i++) {
- new_function ^= functions.At(i);
- selector = new_function.name();
- old_function = old_cls.LookupFunction(selector);
- // If we made live changes with proper structed edits, this would just be
- // old != new.
- if (old_function.IsNull() || (new_function.SourceFingerprint() !=
- old_function.SourceFingerprint())) {
- ASSERT(!new_function.HasCode());
- ASSERT(new_function.usage_counter() == 0);
- changed_in_last_reload.Add(new_function);
- }
- }
- for (intptr_t i = 0; i < fields.Length(); i++) {
- new_field ^= fields.At(i);
- if (!new_field.is_static()) continue;
- selector = new_field.name();
- old_field = old_cls.LookupField(selector);
- if (old_field.IsNull() || !old_field.is_static()) {
- // New field.
- changed_in_last_reload.Add(new_field);
- } else if (new_field.SourceFingerprint() != old_field.SourceFingerprint()) {
- // Changed field.
- changed_in_last_reload.Add(new_field);
- if (!old_field.IsUninitialized()) {
- new_field.set_initializer_changed_after_initialization(true);
- }
- }
- }
-}
-
void IsolateReloadContext::Commit() {
TIMELINE_SCOPE(Commit);
TIR_Print("---- COMMITTING RELOAD\n");
@@ -1331,9 +1253,6 @@
lib_map.Release();
}
- const GrowableObjectArray& changed_in_last_reload =
- GrowableObjectArray::Handle(GrowableObjectArray::New());
-
{
TIMELINE_SCOPE(CopyStaticFieldsAndPatchFieldsAndFunctions);
// Copy static field values from the old classes to the new classes.
@@ -1359,7 +1278,6 @@
old_cls.PatchFieldsAndFunctions();
old_cls.MigrateImplicitStaticClosures(this, new_cls);
}
- RecordChanges(changed_in_last_reload, old_cls, new_cls);
}
}
@@ -1378,15 +1296,6 @@
}
}
- if (FLAG_identity_reload) {
- Object& changed = Object::Handle();
- for (intptr_t i = 0; i < changed_in_last_reload.Length(); i++) {
- changed = changed_in_last_reload.At(i);
- ASSERT(changed.IsClass()); // Only fuzzy from lazy finalization.
- }
- }
- I->object_store()->set_changed_in_last_reload(changed_in_last_reload);
-
{
TIMELINE_SCOPE(UpdateLibrariesArray);
// Update the libraries array.
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
index 300195e..b6e0553 100644
--- a/runtime/vm/isolate_reload.h
+++ b/runtime/vm/isolate_reload.h
@@ -145,6 +145,8 @@
// All zone allocated objects must be allocated from this zone.
Zone* zone() const { return zone_; }
+ bool UseSavedClassTableForGC() const { return saved_class_table_ != nullptr; }
+
bool reload_skipped() const { return reload_skipped_; }
bool reload_aborted() const { return reload_aborted_; }
RawError* error() const;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 5dbc67b..c541cd2 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -2202,7 +2202,7 @@
}
}
#ifndef PRODUCT
- ClassTable* class_table = thread->isolate()->class_table();
+ auto class_table = thread->isolate()->shared_class_table();
if (space == Heap::kNew) {
class_table->UpdateAllocatedNew(cls_id, size);
} else {
@@ -3298,7 +3298,7 @@
bool Class::TraceAllocation(Isolate* isolate) const {
#ifndef PRODUCT
- ClassTable* class_table = isolate->class_table();
+ auto class_table = isolate->shared_class_table();
return class_table->TraceAllocationFor(id());
#else
return false;
@@ -3310,7 +3310,7 @@
Isolate* isolate = Isolate::Current();
const bool changed = trace_allocation != this->TraceAllocation(isolate);
if (changed) {
- ClassTable* class_table = isolate->class_table();
+ auto class_table = isolate->shared_class_table();
class_table->SetTraceAllocationFor(id(), trace_allocation);
DisableAllocationStub();
}
@@ -8104,21 +8104,31 @@
}
bool Function::CheckSourceFingerprint(const char* prefix, int32_t fp) const {
- // TODO(36376): Restore checking fingerprints of recognized methods.
- // '(kernel_offset() <= 0)' looks like an impossible condition, fix this and
- // re-enable fingerprints checking.
- if (!Isolate::Current()->obfuscate() && !is_declared_in_bytecode() &&
- (kernel_offset() <= 0) && (SourceFingerprint() != fp)) {
+ if (Isolate::Current()->obfuscate() || FLAG_precompiled_mode ||
+ (Dart::vm_snapshot_kind() != Snapshot::kNone)) {
+ return true; // The kernel structure has been altered, skip checking.
+ }
+
+ if (is_declared_in_bytecode()) {
+ // AST and bytecode compute different fingerprints, and we only track one
+ // fingerprint set.
+ return true;
+ }
+
+ if (SourceFingerprint() != fp) {
const bool recalculatingFingerprints = false;
if (recalculatingFingerprints) {
// This output can be copied into a file, then used with sed
// to replace the old values.
- // sed -i.bak -f /tmp/newkeys runtime/vm/compiler/method_recognizer.h
+ // sed -i.bak -f /tmp/newkeys \
+ // runtime/vm/compiler/recognized_methods_list.h
THR_Print("s/0x%08x/0x%08x/\n", fp, SourceFingerprint());
} else {
THR_Print(
- "FP mismatch while recognizing method %s:"
- " expecting 0x%08x found 0x%08x\n",
+ "FP mismatch while recognizing method %s: expecting 0x%08x found "
+ "0x%08x.\nIf the behavior of this function has changed, then changes "
+ "are also needed in the VM's compiler. Otherwise the fingerprint can "
+ "simply be updated in recognized_methods_list.h\n",
ToFullyQualifiedCString(), fp, SourceFingerprint());
return false;
}
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 77461f0..8fab9f4 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -139,7 +139,6 @@
R_(Function, megamorphic_miss_function) \
RW(Array, code_order_table) \
RW(Array, obfuscation_map) \
- RW(GrowableObjectArray, changed_in_last_reload) \
RW(Class, ffi_pointer_class) \
RW(Class, ffi_native_type_class) \
RW(Class, ffi_struct_class) \
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 21566b5..65e7a5f 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -494,7 +494,7 @@
}
#if defined(DART_USE_TCMALLOC) && defined(HOST_OS_LINUX) && defined(DEBUG) && \
- defined(HOST_ARCH_x64)
+ defined(HOST_ARCH_X64)
DART_NOINLINE static void NativeAllocationSampleHelper(char** result) {
ASSERT(result != NULL);
@@ -502,12 +502,12 @@
}
ISOLATE_UNIT_TEST_CASE(Profiler_NativeAllocation) {
- EnableProfiler();
-
bool enable_malloc_hooks_saved = FLAG_profiler_native_memory;
FLAG_profiler_native_memory = true;
- MallocHooks::InitOnce();
+ EnableProfiler();
+
+ MallocHooks::Init();
MallocHooks::ResetStats();
bool stack_trace_collection_enabled =
MallocHooks::stack_trace_collection_enabled();
@@ -536,31 +536,27 @@
// Filter for the class in the time range.
NativeAllocationSampleFilter filter(before_allocations_micros,
allocation_extent_micros);
- profile.Build(thread, &filter, Profiler::sample_buffer());
+ profile.Build(thread, &filter, Profiler::allocation_sample_buffer());
// We should have 1 allocation sample.
EXPECT_EQ(1, profile.sample_count());
- ProfileStackWalker walker(&profile)
+ ProfileStackWalker walker(&profile);
- // Move down from the root.
- EXPECT(walker.Down());
+ // Move down from the root.
EXPECT_SUBSTRING("[Native]", walker.CurrentName());
- EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
+ EXPECT_EQ(1024ul, profile.SampleAt(0)->native_allocation_size_bytes());
EXPECT(walker.Down());
EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()",
walker.CurrentName());
- EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
EXPECT(walker.Down());
EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName());
- EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
EXPECT(walker.Down());
EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName());
- EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
EXPECT(walker.Down());
EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName());
- EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
+ EXPECT(walker.Down());
+ EXPECT_SUBSTRING("[Native]", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
EXPECT(!walker.Down());
}
@@ -601,11 +597,10 @@
MallocHooks::set_stack_trace_collection_enabled(
stack_trace_collection_enabled);
- MallocHooks::TearDown();
FLAG_profiler_native_memory = enable_malloc_hooks_saved;
}
-#endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) &&
- // !defined(TARGET_ARCH_DBC) && !defined(HOST_OS_FUCHSIA)
+#endif // defined(DART_USE_TCMALLOC) && defined(HOST_OS_LINUX) && \
+ // defined(DEBUG) && defined(HOST_ARCH_X64)
ISOLATE_UNIT_TEST_CASE(Profiler_ToggleRecordAllocation) {
EnableProfiler();
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 1f2ccdb..212d274 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -9,6 +9,7 @@
#include "vm/heap/become.h"
#include "vm/heap/freelist.h"
#include "vm/isolate.h"
+#include "vm/isolate_reload.h"
#include "vm/object.h"
#include "vm/runtime_entry.h"
#include "vm/visitor.h"
@@ -57,11 +58,11 @@
}
}
intptr_t class_id = ClassIdTag::decode(tags);
- if (!isolate->class_table()->IsValidIndex(class_id)) {
+ if (!isolate->shared_class_table()->IsValidIndex(class_id)) {
FATAL1("Invalid class id encountered %" Pd "\n", class_id);
}
- if ((class_id == kNullCid) &&
- (isolate->class_table()->At(class_id) == NULL)) {
+ if (class_id == kNullCid &&
+ isolate->shared_class_table()->HasValidClassAt(class_id)) {
// Null class not yet initialized; skip.
return;
}
@@ -212,9 +213,19 @@
// TODO(koda): Add Size(ClassTable*) interface to allow caching in loops.
Isolate* isolate = Isolate::Current();
#if defined(DEBUG)
- ClassTable* class_table = isolate->class_table();
+ auto class_table = isolate->shared_class_table();
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ auto reload_context = isolate->reload_context();
+ const bool use_saved_class_table =
+ reload_context != nullptr ? reload_context->UseSavedClassTableForGC()
+ : false;
+#else
+ const bool use_saved_class_table = false;
+#endif
+
+ ASSERT(use_saved_class_table || class_table->SizeAt(class_id) > 0);
if (!class_table->IsValidIndex(class_id) ||
- !class_table->HasValidClassAt(class_id)) {
+ (!class_table->HasValidClassAt(class_id) && !use_saved_class_table)) {
FATAL2("Invalid class id: %" Pd " from tags %x\n", class_id,
ptr()->tags_);
}
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index fc8dfc7..0c88bdc 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -2140,6 +2140,10 @@
private:
friend class Library;
+ friend class OneByteStringSerializationCluster;
+ friend class TwoByteStringSerializationCluster;
+ friend class OneByteStringDeserializationCluster;
+ friend class TwoByteStringDeserializationCluster;
friend class RODataSerializationCluster;
friend class ImageWriter;
};
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 4ab9c57..98539e3 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -1415,70 +1415,6 @@
return true;
}
-static const MethodParameter* get_unused_changes_in_last_reload_params[] = {
- ISOLATE_PARAMETER, NULL,
-};
-
-static bool GetUnusedChangesInLastReload(Thread* thread, JSONStream* js) {
- if (CheckCompilerDisabled(thread, js)) {
- return true;
- }
-
- const GrowableObjectArray& changed_in_last_reload =
- GrowableObjectArray::Handle(
- thread->isolate()->object_store()->changed_in_last_reload());
- if (changed_in_last_reload.IsNull()) {
- js->PrintError(kIsolateMustHaveReloaded, "No change to compare with.");
- return true;
- }
- JSONObject jsobj(js);
- jsobj.AddProperty("type", "UnusedChangesInLastReload");
- JSONArray jsarr(&jsobj, "unused");
- Object& changed = Object::Handle();
- Function& function = Function::Handle();
- Field& field = Field::Handle();
- Class& cls = Class::Handle();
- Array& functions = Array::Handle();
- Array& fields = Array::Handle();
- for (intptr_t i = 0; i < changed_in_last_reload.Length(); i++) {
- changed = changed_in_last_reload.At(i);
- if (changed.IsFunction()) {
- function ^= changed.raw();
- if (!function.WasExecuted()) {
- jsarr.AddValue(function);
- }
- } else if (changed.IsField()) {
- field ^= changed.raw();
- if (field.IsUninitialized() ||
- field.initializer_changed_after_initialization()) {
- jsarr.AddValue(field);
- }
- } else if (changed.IsClass()) {
- cls ^= changed.raw();
- if (!cls.is_finalized()) {
- // Not used at all.
- jsarr.AddValue(cls);
- } else {
- functions = cls.functions();
- for (intptr_t j = 0; j < functions.Length(); j++) {
- function ^= functions.At(j);
- if (!function.WasExecuted()) {
- jsarr.AddValue(function);
- }
- }
- fields = cls.fields();
- for (intptr_t j = 0; j < fields.Length(); j++) {
- field ^= fields.At(j);
- if (field.IsUninitialized()) {
- jsarr.AddValue(field);
- }
- }
- }
- }
- }
- return true;
-}
-
static const MethodParameter* get_stack_params[] = {
RUNNABLE_ISOLATE_PARAMETER,
NULL,
@@ -3943,7 +3879,7 @@
Isolate* isolate = thread->isolate();
if (should_reset_accumulator) {
isolate->UpdateLastAllocationProfileAccumulatorResetTimestamp();
- isolate->class_table()->ResetAllocationAccumulators();
+ isolate->shared_class_table()->ResetAllocationAccumulators();
}
if (should_collect) {
isolate->UpdateLastAllocationProfileGCTimestamp();
@@ -4763,8 +4699,6 @@
get_source_report_params },
{ "getStack", GetStack,
get_stack_params },
- { "_getUnusedChangesInLastReload", GetUnusedChangesInLastReload,
- get_unused_changes_in_last_reload_params },
{ "_getTagProfile", GetTagProfile,
get_tag_profile_params },
{ "_getTypeArgumentsList", GetTypeArgumentsList,
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 5c3b68e..1f7beaa 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -196,6 +196,9 @@
const uint8_t* Addr() const { return reinterpret_cast<const uint8_t*>(this); }
const uint8_t* DataImage() const {
+ if (!IncludesCode(kind())) {
+ return NULL;
+ }
uword offset = Utils::RoundUp(length(), OS::kMaxPreferredCodeAlignment);
return Addr() + offset;
}
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 3da6666..e05f475 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -724,8 +724,7 @@
"}\n";
Dart_Handle result;
- uint8_t* isolate_snapshot_data_buffer = nullptr;
- intptr_t isolate_snapshot_data_size = 0;
+ uint8_t* isolate_snapshot_data_buffer;
// Start an Isolate, load a script and create a full snapshot.
Timer timer1(true, "Snapshot_test");
@@ -750,38 +749,17 @@
OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
// Write snapshot with object content.
- uint8_t* isolate_snapshot_text_buffer = nullptr;
- BlobImageWriter image_writer(thread, &isolate_snapshot_text_buffer,
- &malloc_allocator, 2 * MB /* initial_size */,
- /*shared_objects=*/nullptr,
- /*shared_instructions=*/nullptr,
- /*reused_instructions=*/nullptr);
- FullSnapshotWriter writer(Snapshot::kFull, nullptr,
+ FullSnapshotWriter writer(Snapshot::kFull, NULL,
&isolate_snapshot_data_buffer, &malloc_allocator,
- nullptr, &image_writer);
+ NULL, /*image_writer*/ nullptr);
writer.WriteFullSnapshot();
- isolate_snapshot_data_size = writer.IsolateSnapshotSize();
- free(isolate_snapshot_text_buffer);
}
- // Malloc gives only 8 byte alignment, but we need
- // OS::kMaxPreferredCodeAlignment. Rellocate to VirtualMemory to get page
- // alignment.
- std::unique_ptr<VirtualMemory> aligned_isolate_snapshot_data_buffer(
- VirtualMemory::Allocate(
- Utils::RoundUp(isolate_snapshot_data_size, VirtualMemory::PageSize()),
- false, "snapshot_test"));
- memmove(aligned_isolate_snapshot_data_buffer->address(),
- isolate_snapshot_data_buffer, isolate_snapshot_data_size);
- free(isolate_snapshot_data_buffer);
- isolate_snapshot_data_buffer = nullptr;
-
// Now Create another isolate using the snapshot and execute a method
// from the script.
Timer timer2(true, "Snapshot_test");
timer2.Start();
- TestCase::CreateTestIsolateFromSnapshot(reinterpret_cast<uint8_t*>(
- aligned_isolate_snapshot_data_buffer->address()));
+ TestCase::CreateTestIsolateFromSnapshot(isolate_snapshot_data_buffer);
{
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
timer2.Stop();
@@ -794,6 +772,7 @@
Dart_ExitScope();
}
Dart_ShutdownIsolate();
+ free(isolate_snapshot_data_buffer);
}
// Helper function to call a top level Dart function and serialize the result.
diff --git a/sdk_nnbd/BUILD.gn b/sdk_nnbd/BUILD.gn
new file mode 100644
index 0000000..228fc3c
--- /dev/null
+++ b/sdk_nnbd/BUILD.gn
@@ -0,0 +1,1069 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# This GN file contains build rules for assembling the Dart SDK. There are
+# two possible variants: the "Full" SDK, and the "Platform" SDK. If you want
+# to make a new subset of the Full SDK, make it the same way we make
+# the Platform SDK.
+#
+# Warning:
+# If you need to copy something into dart-sdk/lib/foo in addition to the stuff
+# copied there by :copy_libraries, then you must depend on ":copy_libraries",
+# or ":copy_libraries" may delete/overwrite your addition, and the build will
+# fail.
+
+import("../build/dart/copy_tree.gni")
+import("../runtime/runtime_args.gni")
+
+declare_args() {
+ # Build a SDK with less stuff. It excludes dart2js, ddc, and web libraries.
+ dart_platform_sdk = true
+
+ # Path to stripped dart binaries relative to build output directory.
+ dart_stripped_binary = "dart"
+ dartaotruntime_stripped_binary = "dartaotruntime"
+ gen_snapshot_stripped_binary = "gen_snapshot"
+}
+
+# The directory layout of the SDK is as follows:
+#
+# ..dart-sdk/
+# ....bin/
+# ......dart or dart.exe (executable)
+# ......dart.lib (import library for VM native extensions on Windows)
+# ......dartaotruntime or dartaotruntime.exe (executable)
+# ......dartdoc
+# ......dartfmt
+# ......dart2aot
+# ......dart2js
+# ......dartanalyzer
+# ......dartdevc
+# ......utils/gen_snapshot or utils/gen_snapshot.exe (executable)
+# ......pub
+# ......snapshots/
+# ........analysis_server.dart.snapshot
+# ........dart2js.dart.snapshot
+# ........dartanalyzer.dart.snapshot
+# ........dartdoc.dart.snapshot
+# ........dartfmt.dart.snapshot
+# ........dartdevc.dart.snapshot
+# ........gen_kernel.dart.snapshot
+# ........kernel_worker.dart.snapshot
+# ........pub.dart.snapshot
+#.........resources/
+#...........dartdoc/
+#..............packages
+#.............resources/
+#.............templates/
+# ....include/
+# ......dart_api.h
+# ......dart_native_api.h
+# ......dart_tools_api.h
+# ....lib/
+# ......libraries.json
+# ......_internal/
+#.........strong.sum
+#.........dart2js_platform.dill
+#.........dart2js_server_platform.dill
+#.........dart2js_platform_strong.dill
+#.........dart2js_server_platform_strong.dill
+#.........vm_platform_strong.dill
+#.........dev_compiler/
+# ......async/
+# ......collection/
+# ......convert/
+# ......core/
+# ......html/
+# ......_http/
+# ......internal/
+# ......io/
+# ......isolate/
+# ......js/
+# ......js_util/
+# ......math/
+# ......mirrors/
+# ......typed_data/
+# ......wasm/
+# ......api_readme.md
+# ....model/
+# ......lexeme/
+# ........idx2word.json
+# ........model.tflite
+# ........word2idx.json
+
+# Scripts that go under bin/
+_platform_sdk_scripts = [
+ "dartanalyzer",
+ "dartfmt",
+ "pub",
+]
+
+_full_sdk_scripts = [
+ "dart2js",
+ "dartanalyzer",
+ "dartdevc",
+ "dartfmt",
+ "pub",
+]
+
+# Scripts not ending in _sdk that go under bin/
+_scripts = [ "dartdoc" ]
+
+# Snapshots that go under bin/snapshots
+_platform_sdk_snapshots = [
+ [
+ "dartanalyzer",
+ "../utils/dartanalyzer:generate_dartanalyzer_snapshot",
+ ],
+ [
+ "dart2native",
+ "../utils/dart2native:generate_dart2native_snapshot",
+ ],
+ [
+ "dartdoc",
+ "../utils/dartdoc",
+ ],
+ [
+ "dartfmt",
+ "../utils/dartfmt",
+ ],
+ [
+ "pub",
+ "../utils/pub",
+ ],
+]
+if (create_kernel_service_snapshot) {
+ _platform_sdk_snapshots += [
+ [
+ "kernel-service",
+ "../utils/kernel-service:kernel-service_snapshot",
+ ],
+ ]
+}
+if (dart_target_arch != "arm") {
+ _platform_sdk_snapshots += [
+ [
+ "analysis_server",
+ "../utils/analysis_server",
+ ],
+ ]
+}
+
+_full_sdk_snapshots = [
+ [
+ "dart2js",
+ "../utils/compiler:dart2js",
+ ],
+ [
+ "dartanalyzer",
+ "../utils/dartanalyzer:generate_dartanalyzer_snapshot",
+ ],
+ [
+ "dart2native",
+ "../utils/dart2native:generate_dart2native_snapshot",
+ ],
+ [
+ "dartdevc",
+ "../utils/dartdevc",
+ ],
+ [
+ "dartdoc",
+ "../utils/dartdoc",
+ ],
+ [
+ "dartfmt",
+ "../utils/dartfmt",
+ ],
+ [
+ "kernel_worker",
+ "../utils/bazel:kernel_worker",
+ ],
+ [
+ "pub",
+ "../utils/pub",
+ ],
+]
+if (create_kernel_service_snapshot) {
+ _full_sdk_snapshots += [
+ [
+ "kernel-service",
+ "../utils/kernel-service:kernel-service_snapshot",
+ ],
+ ]
+}
+if (dart_target_arch != "arm") {
+ _full_sdk_snapshots += [
+ [
+ "analysis_server",
+ "../utils/analysis_server",
+ ],
+ ]
+}
+
+# Libraries that go under lib/
+_full_sdk_libraries = [
+ "_chrome",
+ "_internal",
+ "async",
+ "cli",
+ "collection",
+ "convert",
+ "core",
+ "developer",
+ "ffi",
+ "html",
+ "_http",
+ "indexed_db",
+ "internal",
+ "io",
+ "isolate",
+ "js",
+ "js_util",
+ "math",
+ "mirrors",
+ "profiler",
+ "svg",
+ "typed_data",
+ "wasm",
+ "web_audio",
+ "web_gl",
+ "web_sql",
+]
+
+# Apps running on the platform SDK shouldn't be using Dart4Web libraries, but
+# the analyzer and dartdoc expect all the library sources to be present.
+#
+# _platform_sdk_libraries = [
+# "_internal",
+# "async",
+# "cli",
+# "collection",
+# "convert",
+# "core",
+# "developer",
+# "html",
+# "_http",
+# "internal",
+# "io",
+# "isolate",
+# "math",
+# "mirrors",
+# "profiler",
+# "typed_data",
+# ]
+_platform_sdk_libraries = _full_sdk_libraries
+
+# From here down to the copy_trees() invocation, we collect all the information
+# about trees that need to be copied in the list of scopes, copy_tree_specs.
+copy_tree_specs = []
+
+# This rule copies dartdoc templates to
+# bin/resources/dartdoc/templates
+copy_tree_specs += [ {
+ target = "copy_dartdoc_templates"
+ visibility = [ ":copy_dartdoc_files" ]
+ source = "../third_party/pkg/dartdoc/lib/templates"
+ dest = "$root_out_dir/dart-sdk/bin/resources/dartdoc/templates"
+ ignore_patterns = "{}"
+ } ]
+
+# This rule copies dartdoc resources to
+# bin/resources/dartdoc/resources
+copy_tree_specs += [ {
+ target = "copy_dartdoc_resources"
+ visibility = [ ":copy_dartdoc_files" ]
+ source = "../third_party/pkg/dartdoc/lib/resources"
+ dest = "$root_out_dir/dart-sdk/bin/resources/dartdoc/resources"
+ ignore_patterns = "{}"
+ } ]
+
+# This loop generates rules to copy libraries to lib/
+foreach(library, _full_sdk_libraries) {
+ copy_tree_specs += [ {
+ target = "copy_${library}_library"
+ visibility = [
+ ":copy_platform_sdk_libraries",
+ ":copy_full_sdk_libraries",
+ ]
+ source = "lib/$library"
+ dest = "$root_out_dir/dart-sdk/lib/$library"
+ ignore_patterns = "*.svn,doc,*.py,*.gypi,*.sh,.gitignore"
+ } ]
+}
+
+if (is_win) {
+ copy_tree_specs += [ {
+ target = "copy_7zip"
+ visibility = [ ":create_common_sdk" ]
+ deps = [
+ ":copy_libraries",
+ ]
+ source = "../third_party/7zip"
+ dest = "$root_out_dir/dart-sdk/lib/_internal/pub/asset/7zip"
+ ignore_patterns = ".svn"
+ } ]
+}
+
+if (target_cpu == "x64") {
+ copy_tree_specs += [
+ {
+ target = "copy_language_model"
+ visibility = [ ":create_common_sdk" ]
+ deps = [
+ ":copy_libraries",
+ ]
+ source = "../pkg/analysis_server/language_model"
+ dest = "$root_out_dir/dart-sdk/model"
+ ignore_patterns = "{}"
+ },
+ {
+ target = "copy_libtensorflowlite_c"
+ visibility = [ ":create_common_sdk" ]
+ deps = [
+ ":copy_libraries",
+ ]
+ source = "../third_party/pkg/tflite_native/lib/src/blobs"
+ dest = "$root_out_dir/dart-sdk/bin/snapshots"
+ ignore_patterns = "{}"
+ }
+ ]
+}
+
+# This generates targets for everything in copy_tree_specs. The targets have the
+# same name as the "target" fields in the scopes of copy_tree_specs.
+copy_trees("copy_trees") {
+ sources = copy_tree_specs
+}
+
+# Copies the Dart VM binary into bin/
+if (target_os != current_os && target_os == "fuchsia") {
+ # In the Fuchsia build, this has to use a symlink for two reasons.
+ # First, it makes the lookup of shared libraries relative to $ORIGIN
+ # (Linux) or @loader_path (macOS) find the libraries where they are,
+ # since those lookups use the directory of the symlink target rather
+ # than of the link itself (as they would for a copy or hard link).
+ # Second, when the dart binary is built as a "variant" (e.g. with a
+ # sanitizer), then $root_out_dir/dart is itself a symlink to the real
+ # binary in the selected variant toolchain's $root_out_dir and since
+ # the "copy" tool is actually a hard link rather than a copy, it will
+ # make a link to the symlink rather than the symlink's target, and the
+ # relative symlink interpreted from a different containing directory
+ # will not find the actual binary.
+ action("copy_dart") {
+ visibility = [ ":create_common_sdk" ]
+ dart_label = "../runtime/bin:dart"
+ deps = [
+ dart_label,
+ ]
+ dart_out = get_label_info(dart_label, "root_out_dir")
+ sources = [
+ "$dart_out/$dart_stripped_binary",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/bin/$dart_stripped_binary",
+ ]
+ script = "/bin/ln"
+ args = [
+ "-snf",
+ rebase_path(sources[0], get_path_info(outputs[0], "dir")),
+ rebase_path(outputs[0]),
+ ]
+ }
+} else {
+ copy("copy_dart") {
+ visibility = [ ":create_common_sdk" ]
+ deps = [
+ "../runtime/bin:dart",
+ ]
+ dart_out = get_label_info("../runtime/bin:dart", "root_out_dir")
+ if (is_win) {
+ sources = [
+ "$dart_out/dart.exe",
+ ]
+ } else {
+ sources = [
+ "$dart_out/$dart_stripped_binary",
+ ]
+ }
+ if (is_win) {
+ sources += [ "$dart_out/dart.lib" ]
+ }
+ outputs = [
+ "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
+ ]
+ }
+}
+
+copy("copy_dartaotruntime") {
+ deps = [
+ "../runtime/bin:dartaotruntime",
+ ]
+ dartaotruntime_out = get_label_info("../runtime/bin:dartaotruntime", "root_out_dir")
+ if (is_win) {
+ sources = [
+ "$dartaotruntime_out/dartaotruntime.exe",
+ ]
+ } else {
+ sources = [
+ "$dartaotruntime_out/$dartaotruntime_stripped_binary",
+ ]
+ }
+ if (is_win) {
+ sources += [ "$dartaotruntime_out/dartaotruntime.lib" ]
+ }
+ outputs = [
+ "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
+ ]
+}
+
+copy("copy_gen_snapshot") {
+ deps = [
+ "../runtime/bin:gen_snapshot",
+ ]
+ gen_snapshot_out = get_label_info("../runtime/bin:gen_snapshot", "root_out_dir")
+ if (is_win) {
+ sources = [
+ "$gen_snapshot_out/gen_snapshot.exe",
+ ]
+ } else {
+ sources = [
+ "$gen_snapshot_out/$gen_snapshot_stripped_binary",
+ ]
+ }
+ outputs = [
+ "$root_out_dir/dart-sdk/bin/utils/{{source_file_part}}",
+ ]
+}
+
+copy("copy_dart2aot") {
+ ext = ""
+ if (is_win) {
+ ext = ".bat"
+ }
+ sources = [
+ "bin/dart2aot$ext",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
+ ]
+}
+
+copy("copy_dart2native") {
+ deps = [
+ ":copy_gen_kernel_snapshot",
+ ":copy_gen_snapshot",
+ ]
+ ext = ""
+ if (is_win) {
+ ext = ".bat"
+ }
+ sources = [
+ "bin/dart2native$ext",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
+ ]
+}
+
+copy("copy_gen_kernel_snapshot") {
+ deps = [
+ "../utils/gen_kernel",
+ ]
+ sources = [
+ "$root_gen_dir/gen_kernel.dart.snapshot",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/bin/snapshots/{{source_file_part}}",
+ ]
+}
+
+# A template for copying the things in _platform_sdk_scripts and
+# _full_sdk_scripts into bin/
+template("copy_sdk_script") {
+ assert(defined(invoker.name), "copy_sdk_script must define 'name'")
+ name = invoker.name
+ ext = ""
+ if (is_win) {
+ ext = ".bat"
+ }
+ copy(target_name) {
+ visibility = [
+ ":copy_platform_sdk_scripts",
+ ":copy_full_sdk_scripts",
+ ]
+ sources = [
+ "bin/${name}_sdk$ext",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/bin/$name$ext",
+ ]
+ }
+}
+
+foreach(sdk_script, _full_sdk_scripts) {
+ copy_sdk_script("copy_${sdk_script}_script") {
+ name = sdk_script
+ }
+}
+
+foreach(script, _scripts) {
+ copy("copy_${script}_script") {
+ visibility = [
+ ":copy_platform_sdk_scripts",
+ ":copy_full_sdk_scripts",
+ ]
+ ext = ""
+ if (is_win) {
+ ext = ".bat"
+ }
+ sources = [
+ "bin/$script$ext",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
+ ]
+ }
+}
+
+# This is the main target for copying scripts in _platform_sdk_scripts to bin/
+group("copy_platform_sdk_scripts") {
+ visibility = [ ":create_platform_sdk" ]
+ public_deps = []
+ foreach(sdk_script, _platform_sdk_scripts) {
+ public_deps += [ ":copy_${sdk_script}_script" ]
+ }
+ foreach(script, _scripts) {
+ public_deps += [ ":copy_${script}_script" ]
+ }
+}
+
+# This is the main target for copying scripts in _full_sdk_scripts to bin/
+group("copy_full_sdk_scripts") {
+ visibility = [ ":create_full_sdk" ]
+ public_deps = []
+ foreach(sdk_script, _full_sdk_scripts) {
+ public_deps += [ ":copy_${sdk_script}_script" ]
+ }
+ foreach(script, _scripts) {
+ public_deps += [ ":copy_${script}_script" ]
+ }
+}
+
+# This loop generates "copy" targets that put snapshots into bin/snapshots
+foreach(snapshot, _full_sdk_snapshots) {
+ copy("copy_${snapshot[0]}_snapshot") {
+ visibility = [
+ ":copy_platform_sdk_snapshots",
+ ":copy_full_sdk_snapshots",
+ ]
+ deps = [
+ snapshot[1],
+ ]
+ sources = [
+ "$root_gen_dir/${snapshot[0]}.dart.snapshot",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/bin/snapshots/{{source_file_part}}",
+ ]
+ }
+}
+
+# This is the main rule for copying snapshots from _platform_sdk_snapshots to
+# bin/snapshots
+group("copy_platform_sdk_snapshots") {
+ visibility = [ ":create_platform_sdk" ]
+ public_deps = []
+ foreach(snapshot, _platform_sdk_snapshots) {
+ public_deps += [ ":copy_${snapshot[0]}_snapshot" ]
+ }
+}
+
+# This is the main rule for copying snapshots from _full_sdk_snapshots to
+# bin/snapshots
+group("copy_full_sdk_snapshots") {
+ visibility = [ ":create_full_sdk" ]
+ public_deps = []
+ foreach(snapshot, _full_sdk_snapshots) {
+ public_deps += [ ":copy_${snapshot[0]}_snapshot" ]
+ }
+}
+
+# This rule writes the .packages file for dartdoc resources.
+write_file("$root_out_dir/dart-sdk/bin/resources/dartdoc/.packages",
+ "dartdoc:.")
+
+# This is the main rule for copying the files that dartdoc needs.
+group("copy_dartdoc_files") {
+ visibility = [ ":create_common_sdk" ]
+ public_deps = [
+ ":copy_dartdoc_resources",
+ ":copy_dartdoc_templates",
+ ]
+}
+
+# This rule copies analyzer summaries to lib/_internal
+copy("copy_analysis_summaries") {
+ visibility = [ ":create_common_sdk" ]
+ deps = [
+ ":copy_libraries",
+ "../utils/dartanalyzer:generate_summary_strong",
+ ]
+ sources = [
+ "$root_gen_dir/strong.sum",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
+ ]
+}
+
+# This rule copies dill files to lib/_internal.
+copy("copy_vm_dill_files") {
+ visibility = [ ":create_common_sdk" ]
+ deps = [
+ ":copy_libraries",
+ "../runtime/vm:kernel_platform_files",
+ ]
+ sources = [
+ "$root_out_dir/vm_platform_strong.dill",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
+ ]
+}
+
+copy("copy_abi_dill_files") {
+ visibility = [ ":create_sdk_with_abi_versions" ]
+ sources = [
+ "../tools/abiversions",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/_internal/abiversions",
+ ]
+}
+
+copy("copy_dart2js_dill_files") {
+ visibility = [ ":create_full_sdk" ]
+ deps = [
+ ":copy_libraries",
+ "../utils/compiler:compile_dart2js_platform",
+ "../utils/compiler:compile_dart2js_server_platform",
+ ]
+ sources = [
+ "$root_out_dir/dart2js_platform.dill",
+ "$root_out_dir/dart2js_server_platform.dill",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
+ ]
+}
+
+# This rule copies ddc summaries to lib/_internal
+copy("copy_dev_compiler_summary") {
+ visibility = [ ":copy_dev_compiler_sdk" ]
+ deps = [
+ ":copy_libraries",
+ "../utils/dartdevc:dartdevc_sdk",
+ "../utils/dartdevc:dartdevc_kernel_sdk_outline",
+ ]
+ gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
+ sources = [
+ # TODO(vsm): Remove post CFE.
+ "$gen_dir/ddc_sdk.sum",
+ "$gen_dir/kernel/ddc_sdk.dill",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
+ ]
+}
+
+# TODO(vsm): Remove the old non-CFE versions of the SDK once we've completed
+# DDC to Kernel (DDK) migration.
+
+# This rule copies DDC's JS SDK and require.js to lib/dev_compiler/amd.
+copy("copy_dev_compiler_js_amd") {
+ visibility = [ ":copy_dev_compiler_js" ]
+ deps = [
+ "../utils/dartdevc:dartdevc_sdk",
+ ]
+ gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
+ sources = [
+ "$gen_dir/js/amd/dart_sdk.js",
+ "$gen_dir/js/amd/dart_sdk.js.map",
+ "../third_party/requirejs/require.js",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/dev_compiler/amd/{{source_file_part}}",
+ ]
+}
+
+# This rule copies DDC's JS SDK and run.js to lib/dev_compiler/common.
+copy("copy_dev_compiler_js_common") {
+ visibility = [ ":copy_dev_compiler_js" ]
+ deps = [
+ "../utils/dartdevc:dartdevc_sdk",
+ ]
+ gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
+ sources = [
+ "$gen_dir/js/common/dart_sdk.js",
+ "$gen_dir/js/common/dart_sdk.js.map",
+ "../pkg/dev_compiler/lib/js/common/run.js",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/dev_compiler/common/{{source_file_part}}",
+ ]
+}
+
+# This rule copies DDC's JS SDK to lib/dev_compiler/es6.
+copy("copy_dev_compiler_js_es6") {
+ visibility = [ ":copy_dev_compiler_js" ]
+ deps = [
+ "../utils/dartdevc:dartdevc_sdk",
+ ]
+ gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
+ sources = [
+ "$gen_dir/js/es6/dart_sdk.js",
+ "$gen_dir/js/es6/dart_sdk.js.map",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/dev_compiler/es6/{{source_file_part}}",
+ ]
+}
+
+# This rule copies DDK's JS SDK and require.js to lib/dev_compiler/kernel/amd.
+copy("copy_dev_compiler_js_amd_kernel") {
+ visibility = [ ":copy_dev_compiler_js" ]
+ deps = [
+ "../utils/dartdevc:dartdevc_kernel_sdk",
+ ]
+ gen_dir = get_label_info("../utils/dartdevc:dartdevc_kernel_sdk",
+ "target_gen_dir")
+ sources = [
+ "$gen_dir/kernel/amd/dart_sdk.js",
+ "$gen_dir/kernel/amd/dart_sdk.js.map",
+ "../third_party/requirejs/require.js",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/dev_compiler/kernel/amd/{{source_file_part}}",
+ ]
+}
+
+# This rule copies DDK's JS SDK to lib/dev_compiler/kernel/common.
+copy("copy_dev_compiler_js_common_kernel") {
+ visibility = [ ":copy_dev_compiler_js" ]
+ deps = [
+ "../utils/dartdevc:dartdevc_kernel_sdk",
+ ]
+ gen_dir = get_label_info("../utils/dartdevc:dartdevc_kernel_sdk",
+ "target_gen_dir")
+ sources = [
+ "$gen_dir/kernel/common/dart_sdk.js",
+ "$gen_dir/kernel/common/dart_sdk.js.map",
+ "../pkg/dev_compiler/lib/js/common/run.js",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/dev_compiler/kernel/common/{{source_file_part}}",
+ ]
+}
+
+# This rule copies DDK's JS SDK to lib/dev_compiler/kernel/es6.
+copy("copy_dev_compiler_js_es6_kernel") {
+ visibility = [ ":copy_dev_compiler_js" ]
+ deps = [
+ "../utils/dartdevc:dartdevc_kernel_sdk",
+ ]
+ gen_dir = get_label_info("../utils/dartdevc:dartdevc_kernel_sdk",
+ "target_gen_dir")
+ sources = [
+ "$gen_dir/kernel/es6/dart_sdk.js",
+ "$gen_dir/kernel/es6/dart_sdk.js.map",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/dev_compiler/kernel/es6/{{source_file_part}}",
+ ]
+}
+
+# Copies all of the JS artifacts needed by DDC.
+group("copy_dev_compiler_js") {
+ visibility = [
+ ":copy_dev_compiler_sdk",
+ ":copy_dev_compiler_tools",
+ ]
+ public_deps = [
+ ":copy_dev_compiler_js_amd",
+ ":copy_dev_compiler_js_amd_kernel",
+ ":copy_dev_compiler_js_common",
+ ":copy_dev_compiler_js_common_kernel",
+ ":copy_dev_compiler_js_es6",
+ ":copy_dev_compiler_js_es6_kernel",
+ ]
+}
+
+# This rule copies tools to go along with ddc.
+copy("copy_dev_compiler_tools") {
+ visibility = [ ":copy_dev_compiler_sdk" ]
+ deps = [
+ ":copy_dev_compiler_js",
+ "../utils/dartdevc:dartdevc_web",
+ "../utils/dartdevc:stack_trace_mapper",
+ ]
+ dart_out = get_label_info("../utils/dartdevc:dartdevc_web", "root_out_dir")
+ sources = [
+ "$dart_out/dev_compiler/build/web/dart_stack_trace_mapper.js",
+ "$dart_out/dev_compiler/build/web/ddc_web_compiler.js",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/dev_compiler/web/{{source_file_part}}",
+ ]
+}
+
+# This is the main rule for copying ddc's dependencies to lib/
+group("copy_dev_compiler_sdk") {
+ visibility = [ ":create_full_sdk" ]
+ public_deps = [
+ ":copy_dev_compiler_js",
+ ":copy_dev_compiler_summary",
+ ":copy_dev_compiler_tools",
+ ]
+}
+
+# This rule copies header files to include/
+copy("copy_headers") {
+ visibility = [ ":create_common_sdk" ]
+ sources = [
+ "../runtime/include/dart_api.h",
+ "../runtime/include/dart_native_api.h",
+ "../runtime/include/dart_tools_api.h",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/include/{{source_file_part}}",
+ ]
+}
+
+# This rule copies libraries.json files to lib/
+copy("copy_libraries_specification") {
+ visibility = [ ":create_common_sdk" ]
+ sources = [
+ "lib/libraries.json",
+ ]
+ deps = [
+ ":copy_libraries",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/{{source_file_part}}",
+ ]
+}
+
+# This is the main rule to copy libraries in _platform_sdk_libraries to lib/
+group("copy_platform_sdk_libraries") {
+ visibility = [
+ ":create_platform_sdk",
+ ":copy_libraries",
+ ]
+ public_deps = []
+ foreach(library, _platform_sdk_libraries) {
+ public_deps += [ ":copy_${library}_library" ]
+ }
+}
+
+# This is the main rule to copy libraries in _full_sdk_libraries to lib/
+group("copy_full_sdk_libraries") {
+ visibility = [
+ ":create_full_sdk",
+ ":copy_libraries",
+ ]
+ public_deps = []
+ foreach(library, _full_sdk_libraries) {
+ public_deps += [ ":copy_${library}_library" ]
+ }
+}
+
+group("copy_libraries") {
+ if (dart_platform_sdk) {
+ public_deps = [
+ ":copy_platform_sdk_libraries",
+ ]
+ } else {
+ public_deps = [
+ ":copy_full_sdk_libraries",
+ ]
+ }
+}
+
+# This rule writes the version file.
+action("write_version_file") {
+ visibility = [ ":create_common_sdk" ]
+ inputs = [
+ "../tools/VERSION",
+ "../.git/logs/HEAD",
+ ]
+ output = "$root_out_dir/dart-sdk/version"
+ outputs = [
+ output,
+ ]
+ script = "../tools/write_version_file.py"
+ args = [
+ "--output",
+ rebase_path(output),
+ ]
+}
+
+# This rule writes the revision file.
+action("write_revision_file") {
+ visibility = [ ":create_common_sdk" ]
+ inputs = [
+ "../.git/logs/HEAD",
+ ]
+ output = "$root_out_dir/dart-sdk/revision"
+ outputs = [
+ output,
+ ]
+ script = "../tools/write_revision_file.py"
+ args = [
+ "--output",
+ rebase_path(output),
+ ]
+}
+
+# Copy libraries.dart to lib/_internal/libraries.dart for backwards
+# compatibility.
+#
+# TODO(sigmund): stop copying libraries.dart. Old versions (<=0.25.1-alpha.4)
+# of the analyzer package do not support the new location of this file. We
+# should be able to remove the old file once we release a newer version of
+# analyzer and popular frameworks have migrated to use it.
+copy("copy_libraries_dart") {
+ visibility = [ ":create_common_sdk" ]
+ deps = [
+ ":copy_libraries",
+ ]
+ sources = [
+ "lib/_internal/sdk_library_metadata/lib/libraries.dart",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
+ ]
+}
+
+# This rule copies the README file.
+copy("copy_readme") {
+ visibility = [ ":create_common_sdk" ]
+ sources = [
+ "../README.dart-sdk",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/README",
+ ]
+}
+
+# This rule copies the LICENSE file.
+copy("copy_license") {
+ visibility = [ ":create_common_sdk" ]
+ sources = [
+ "../LICENSE",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/LICENSE",
+ ]
+}
+
+# This rule generates a custom dartdoc_options.yaml file.
+action("write_dartdoc_options") {
+ visibility = [ ":create_common_sdk" ]
+ inputs = [
+ "../.git/logs/HEAD",
+ ]
+ output = "$root_out_dir/dart-sdk/dartdoc_options.yaml"
+ outputs = [
+ output,
+ ]
+ script = "../tools/write_dartdoc_options_file.py"
+ args = [
+ "--output",
+ rebase_path(output),
+ ]
+}
+
+# This rule copies the API readme file to lib/
+copy("copy_api_readme") {
+ visibility = [ ":create_common_sdk" ]
+ sources = [
+ "api_readme.md",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/lib/api_readme.md",
+ ]
+}
+
+# Parts common to both platform and full SDKs.
+group("create_common_sdk") {
+ visibility = [ ":create_sdk" ]
+ public_deps = [
+ ":copy_analysis_summaries",
+ ":copy_api_readme",
+ ":copy_dart",
+ ":copy_dart2native",
+ ":copy_dartdoc_files",
+ ":copy_headers",
+ ":copy_libraries_dart",
+ ":copy_license",
+ ":copy_libraries_specification",
+ ":copy_readme",
+ ":copy_vm_dill_files",
+ ":write_dartdoc_options",
+ ":write_revision_file",
+ ":write_version_file",
+ ]
+ if (is_win) {
+ public_deps += [ ":copy_7zip" ]
+ }
+ if (target_cpu == "x64") {
+ public_deps += [
+ ":copy_language_model",
+ ":copy_libtensorflowlite_c",
+ ]
+ }
+}
+
+# Parts specific to the platform SDK.
+group("create_platform_sdk") {
+ visibility = [ ":create_sdk" ]
+ public_deps = [
+ ":copy_platform_sdk_libraries",
+ ":copy_platform_sdk_scripts",
+ ":copy_platform_sdk_snapshots",
+ ]
+}
+
+# Parts specific to the full SDK.
+group("create_full_sdk") {
+ visibility = [ ":create_sdk" ]
+
+ public_deps = [
+ ":copy_dart2js_dill_files",
+ ":copy_dev_compiler_sdk",
+ ":copy_full_sdk_libraries",
+ ":copy_full_sdk_scripts",
+ ":copy_full_sdk_snapshots",
+ ]
+}
+
+# The main target to depend on from ../BUILD.gn
+group("create_sdk") {
+ public_deps = [
+ ":create_common_sdk",
+ ]
+ if (dart_platform_sdk) {
+ public_deps += [ ":create_platform_sdk" ]
+ } else {
+ public_deps += [ ":create_full_sdk" ]
+ }
+}
+
+# Same as create_sdk, but with abi version files.
+group("create_sdk_with_abi_versions") {
+ public_deps = [
+ ":copy_abi_dill_files",
+ ":create_sdk",
+ ]
+}
diff --git a/sdk_nnbd/api_readme.md b/sdk_nnbd/api_readme.md
new file mode 100644
index 0000000..2f51f7e
--- /dev/null
+++ b/sdk_nnbd/api_readme.md
@@ -0,0 +1,32 @@
+Welcome to the Dart API reference documentation, covering the core Dart API
+libraries. Some of the most fundamental Dart libraries include:
+
+ * [dart:core](dart-core/dart-core-library.html): Core functionality such as
+ strings, numbers, collections, errors, dates, and URIs.
+ * [dart:html](dart-html/dart-html-library.html): DOM manipulation for web apps
+ (available only to web apps).
+ * [dart:io](dart-io/dart-io-library.html): I/O for non-web apps.
+
+Except for `dart:core`, you must import a library before you can use it. Here's
+an example of importing `dart:async` and `dart:math`:
+
+```dart
+import 'dart:async';
+import 'dart:math';
+```
+
+You can install more libraries using the
+[pub package manager](https://dart.dev/guides/packages).
+
+The main site for learning and using Dart is
+[dart.dev](https://dart.dev). Check out these pages:
+
+ * [Platforms](https://dart.dev/platforms)
+ * [Language tour](https://dart.dev/guides/language/language-tour)
+ * [Library tour](https://dart.dev/guides/libraries/library-tour)
+ * [Sample code](https://dart.dev/samples)
+
+This API reference is automatically generated from source code in the [Dart
+SDK project](https://github.com/dart-lang/sdk).
+If you'd like to give feedback or edit this documentation, see
+[Contributing](https://github.com/dart-lang/sdk/wiki/Contributing).
diff --git a/sdk_nnbd/bin/dart b/sdk_nnbd/bin/dart
new file mode 100755
index 0000000..f50184b
--- /dev/null
+++ b/sdk_nnbd/bin/dart
@@ -0,0 +1,57 @@
+#!/usr/bin/env bash
+# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+CUR_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+if [[ `uname` == 'Darwin' ]];
+then
+ OUT_DIR="$CUR_DIR"/../../xcodebuild/
+else
+ OUT_DIR="$CUR_DIR"/../../out/
+fi
+
+if [ -z "$DART_CONFIGURATION" ];
+then
+ DIRS=$( ls "$OUT_DIR" )
+ # list of possible configurations in decreasing desirability
+ CONFIGS=("ReleaseX64" "ReleaseIA32" "DebugX64" "DebugIA32"
+ "ReleaseARM" "ReleaseARM64" "ReleaseARMV5TE"
+ "DebugARM" "DebugARM64" "DebugARMV5TE")
+ DART_CONFIGURATION="None"
+ for CONFIG in ${CONFIGS[*]}
+ do
+ for DIR in $DIRS;
+ do
+ if [ "$CONFIG" = "$DIR" ];
+ then
+ # choose most desirable configuration that is available and break
+ DART_CONFIGURATION="$DIR"
+ break 2
+ fi
+ done
+ done
+ if [ "$DART_CONFIGURATION" = "None" ]
+ then
+ echo "No valid dart configuration found in $OUT_DIR"
+ exit 1
+ fi
+fi
+
+BIN_DIR="$OUT_DIR$DART_CONFIGURATION"
+
+exec "$BIN_DIR"/dart "$@"
diff --git a/sdk_nnbd/bin/dart.bat b/sdk_nnbd/bin/dart.bat
new file mode 100644
index 0000000..a6a24de
--- /dev/null
+++ b/sdk_nnbd/bin/dart.bat
@@ -0,0 +1,16 @@
+@echo off
+REM Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+set SCRIPTPATH=%~dp0
+
+REM Does the path have a trailing slash? If so, remove it.
+if %SCRIPTPATH:~-1%== set SCRIPTPATH=%SCRIPTPATH:~0,-1%
+
+REM DART_CONFIGURATION defaults to ReleaseX64
+if "%DART_CONFIGURATION%"=="" set DART_CONFIGURATION=ReleaseX64
+
+set arguments=%*
+
+"%SCRIPTPATH%\..\..\out\%DART_CONFIGURATION%\dart.exe" %arguments%
diff --git a/sdk_nnbd/bin/dart2aot b/sdk_nnbd/bin/dart2aot
new file mode 100755
index 0000000..9390db6
--- /dev/null
+++ b/sdk_nnbd/bin/dart2aot
@@ -0,0 +1,111 @@
+#!/usr/bin/env bash
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Script for generating AOT snapshot in two steps:
+# - Compilation to kernel with additional AOT specific transformations.
+# - Compilation of kernel into snapshot using gen_snapshot.
+
+# Parse incoming arguments and extract the value of --packages option if any
+# was passed. Split options (--xyz) and non-options into two separate arrays.
+# All options will be passed to gen_snapshot, while --packages will be
+# passed to the CFE (Common Front-End).
+
+set -e
+
+OPTIONS=()
+GEN_KERNEL_OPTIONS=()
+PACKAGES=
+BUILD_ELF=0
+
+ARGV=()
+for arg in "$@"; do
+ case $arg in
+ --packages=*)
+ PACKAGES="$arg"
+ ;;
+ --enable-asserts)
+ GEN_KERNEL_OPTIONS+=("$arg")
+ OPTIONS+=("$arg")
+ ;;
+ --tfa | \
+ --no-tfa | \
+ -D* )
+ GEN_KERNEL_OPTIONS+=("$arg")
+ ;;
+ --build-elf)
+ BUILD_ELF=1
+ ;;
+ --*)
+ OPTIONS+=("$arg")
+ ;;
+ *)
+ ARGV+=("$arg")
+ ;;
+ esac
+done
+
+if [ "${#ARGV[@]}" -ne 2 ]; then
+ echo "Usage: $0 [options] <dart-source-file> <dart-aot-file>"
+ echo ""
+ echo "Dart AOT (ahead-of-time) compile Dart source code into native machine code."
+ exit 1
+fi
+
+SOURCE_FILE="${ARGV[0]}"
+SNAPSHOT_FILE="${ARGV[1]}"
+
+if [ $BUILD_ELF -eq 1 ]; then
+ GEN_SNAPSHOT_OPTION="--snapshot-kind=app-aot-assembly"
+ GEN_SNAPSHOT_FILENAME="--assembly=${SNAPSHOT_FILE}.S"
+else
+ GEN_SNAPSHOT_OPTION="--snapshot-kind=app-aot-blobs"
+ GEN_SNAPSHOT_FILENAME="--blobs_container_filename=${SNAPSHOT_FILE}"
+fi
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+DART="$BIN_DIR/dart"
+GEN_SNAPSHOT="$BIN_DIR/utils/gen_snapshot"
+
+SNAPSHOT_DIR="$BIN_DIR/snapshots"
+SNAPSHOT="$SNAPSHOT_DIR/gen_kernel.dart.snapshot"
+
+# Step 1: Generate Kernel binary from the input Dart source.
+"$DART" \
+ "${SNAPSHOT}" \
+ --platform "${SDK_DIR}/lib/_internal/vm_platform_strong.dill" \
+ --aot \
+ -Ddart.vm.product=true \
+ "${GEN_KERNEL_OPTIONS[@]}" \
+ $PACKAGES \
+ -o "$SNAPSHOT_FILE.dill" \
+ "$SOURCE_FILE"
+
+# Step 2: Generate snapshot from the Kernel binary.
+"$GEN_SNAPSHOT" \
+ "$GEN_SNAPSHOT_OPTION" \
+ "$GEN_SNAPSHOT_FILENAME" \
+ "${OPTIONS[@]}" \
+ "$SNAPSHOT_FILE.dill"
+
+# Step 3: Assemble the assembly file into an ELF object.
+if [ $BUILD_ELF -eq 1 ]; then
+ gcc -shared -o "$SNAPSHOT_FILE" "${SNAPSHOT_FILE}.S"
+fi
diff --git a/sdk_nnbd/bin/dart2aot.bat b/sdk_nnbd/bin/dart2aot.bat
new file mode 100644
index 0000000..321e867
--- /dev/null
+++ b/sdk_nnbd/bin/dart2aot.bat
@@ -0,0 +1,58 @@
+@echo off
+REM Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+rem Get absolute full name for DART_ROOT.
+for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
+
+rem Remove trailing backslash if there is one
+if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
+
+set DART=%BIN_DIR%\dart.exe
+set GEN_KERNEL=%BIN_DIR%\snapshots\gen_kernel.dart.snapshot
+set VM_PLATFORM_STRONG=%SDK_DIR%\lib\_internal\vm_platform_strong.dill
+set GEN_SNAPSHOT=%BIN_DIR%\utils\gen_snapshot.exe
+
+set SOURCE_FILE=%1
+set SNAPSHOT_FILE=%2
+set GEN_SNAPSHOT_OPTION=--snapshot-kind=app-aot-blobs
+set GEN_SNAPSHOT_FILENAME=--blobs_container_filename=%SNAPSHOT_FILE%
+
+REM Step 1: Generate Kernel binary from the input Dart source.
+%DART% %GEN_KERNEL% --platform %VM_PLATFORM_STRONG% --aot -Ddart.vm.product=true -o %SNAPSHOT_FILE%.dill %SOURCE_FILE%
+
+REM Step 2: Generate snapshot from the Kernel binary.
+%GEN_SNAPSHOT% %GEN_SNAPSHOT_OPTION% %GEN_SNAPSHOT_FILENAME% %SNAPSHOT_FILE%.dill
+
+endlocal
+
+exit /b %errorlevel%
+
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dart2js b/sdk_nnbd/bin/dart2js
new file mode 100755
index 0000000..cfc91b1
--- /dev/null
+++ b/sdk_nnbd/bin/dart2js
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+DART="$BIN_DIR/dart"
+
+unset EXTRA_OPTIONS
+declare -a EXTRA_OPTIONS
+
+if test -t 1; then
+ # Stdout is a terminal.
+ if test 8 -le `tput colors`; then
+ # Stdout has at least 8 colors, so enable colors.
+ EXTRA_OPTIONS+=('--enable-diagnostic-colors')
+ fi
+fi
+
+unset EXTRA_VM_OPTIONS
+declare -a EXTRA_VM_OPTIONS
+
+case $0 in
+ *_developer)
+ EXTRA_VM_OPTIONS+=('--enable-asserts')
+ ;;
+esac
+
+# We allow extra vm options to be passed in through an environment variable.
+if [[ $DART_VM_OPTIONS ]]; then
+ read -a OPTIONS <<< "$DART_VM_OPTIONS"
+ EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
+fi
+
+DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
+
+DART2JS="package:compiler/src/dart2js.dart"
+
+exec "$DART" "--packages=$DART_ROOT/.packages" "${EXTRA_VM_OPTIONS[@]}" "$DART2JS" "${EXTRA_OPTIONS[@]}" "$@"
diff --git a/sdk_nnbd/bin/dart2js.bat b/sdk_nnbd/bin/dart2js.bat
new file mode 100644
index 0000000..9341ad8
--- /dev/null
+++ b/sdk_nnbd/bin/dart2js.bat
@@ -0,0 +1,60 @@
+@echo off
+REM Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set DART=%BIN_DIR%\dart
+
+set EXTRA_OPTIONS=
+set EXTRA_VM_OPTIONS=
+
+if _%DART2JS_DEVELOPER_MODE%_ == _1_ (
+ set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% --enable-asserts
+)
+
+rem We allow extra vm options to be passed in through an environment variable.
+if not "_%DART_VM_OPTIONS%_" == "__" (
+ set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
+)
+
+rem Get absolute full name for DART_ROOT.
+for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
+
+rem Remove trailing backslash if there is one
+if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
+
+set DART2JS=%DART_ROOT%\pkg\compiler\lib\src\dart2js.dart
+
+"%DART%" "--packages=%DART_ROOT%\.packages" %EXTRA_VM_OPTIONS% "%DART2JS%" %EXTRA_OPTIONS% %*
+
+endlocal
+
+exit /b %errorlevel%
+
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dart2js_developer b/sdk_nnbd/bin/dart2js_developer
new file mode 100755
index 0000000..226d1a9
--- /dev/null
+++ b/sdk_nnbd/bin/dart2js_developer
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+. ${BASH_SOURCE%_developer}
diff --git a/sdk_nnbd/bin/dart2js_developer.bat b/sdk_nnbd/bin/dart2js_developer.bat
new file mode 100644
index 0000000..c4a2959
--- /dev/null
+++ b/sdk_nnbd/bin/dart2js_developer.bat
@@ -0,0 +1,10 @@
+@echo off
+REM Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+set DART2JS_DEVELOPER_MODE=1
+call "%~dp0dart2js.bat" %*
+endlocal
+exit /b %errorlevel%
diff --git a/sdk_nnbd/bin/dart2js_sdk b/sdk_nnbd/bin/dart2js_sdk
new file mode 100755
index 0000000..e7999b4
--- /dev/null
+++ b/sdk_nnbd/bin/dart2js_sdk
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+DART="$BIN_DIR/dart"
+
+SNAPSHOT_DIR="$BIN_DIR/snapshots"
+SNAPSHOT="$SNAPSHOT_DIR/dart2js.dart.snapshot"
+
+unset EXTRA_OPTIONS
+declare -a EXTRA_OPTIONS
+
+if test -t 1; then
+ # Stdout is a terminal.
+ if test 8 -le `tput colors`; then
+ # Stdout has at least 8 colors, so enable colors.
+ EXTRA_OPTIONS+=('--enable-diagnostic-colors')
+ fi
+fi
+
+unset EXTRA_VM_OPTIONS
+declare -a EXTRA_VM_OPTIONS
+
+if test -f "$SNAPSHOT"; then
+ EXTRA_OPTIONS+=("--libraries-spec=$SDK_DIR/lib/libraries.json")
+fi
+
+case $0 in
+ *_developer)
+ EXTRA_VM_OPTIONS+=('--enable-asserts')
+ ;;
+esac
+
+# We allow extra vm options to be passed in through an environment variable.
+if [[ $DART_VM_OPTIONS ]]; then
+ read -a OPTIONS <<< "$DART_VM_OPTIONS"
+ EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
+fi
+
+exec "$DART" "${EXTRA_VM_OPTIONS[@]}" "$SNAPSHOT" "${EXTRA_OPTIONS[@]}" "$@"
diff --git a/sdk_nnbd/bin/dart2js_sdk.bat b/sdk_nnbd/bin/dart2js_sdk.bat
new file mode 100755
index 0000000..8485cdc
--- /dev/null
+++ b/sdk_nnbd/bin/dart2js_sdk.bat
@@ -0,0 +1,57 @@
+@echo off
+REM Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set DART=%BIN_DIR%\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\dart2js.dart.snapshot
+
+set EXTRA_OPTIONS=
+set EXTRA_VM_OPTIONS=
+
+if _%DART2JS_DEVELOPER_MODE%_ == _1_ (
+ set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% --enable-asserts
+)
+
+if exist "%SNAPSHOT%" (
+ set EXTRA_OPTIONS=%EXTRA_OPTIONS% "--libraries-spec=%SDK_DIR%\lib\libraries.json"
+)
+
+rem We allow extra vm options to be passed in through an environment variable.
+if not "_%DART_VM_OPTIONS%_" == "__" (
+ set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
+)
+
+"%DART%" %EXTRA_VM_OPTIONS% "%SNAPSHOT%" %EXTRA_OPTIONS% %*
+
+endlocal
+
+exit /b %errorlevel%
+
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| find "> %~n1 [" 2^>nul`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dart2native b/sdk_nnbd/bin/dart2native
new file mode 100755
index 0000000..29f29d7
--- /dev/null
+++ b/sdk_nnbd/bin/dart2native
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dart2native.dart.snapshot on the Dart VM
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SNAPSHOTS_DIR="${BIN_DIR}/snapshots"
+DART="$BIN_DIR/dart"
+
+exec "$DART" "${SNAPSHOTS_DIR}/dart2native.dart.snapshot" $*
diff --git a/sdk_nnbd/bin/dart2native.bat b/sdk_nnbd/bin/dart2native.bat
new file mode 100644
index 0000000..631dce8
--- /dev/null
+++ b/sdk_nnbd/bin/dart2native.bat
@@ -0,0 +1,43 @@
+@echo off
+REM Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+
+"%DART%" "%BIN_DIR%\snapshots\dart2native.dart.snapshot" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013 10:11 PM <JUNCTION> abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartanalyzer b/sdk_nnbd/bin/dartanalyzer
new file mode 100755
index 0000000..7ea062c
--- /dev/null
+++ b/sdk_nnbd/bin/dartanalyzer
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dartanalyzer.dart on the Dart VM. This script assumes the Dart repo's
+# directory structure.
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+SDK_ARG="--dart-sdk=$SDK_DIR"
+
+DART="$BIN_DIR/dart"
+
+unset EXTRA_VM_OPTIONS
+declare -a EXTRA_VM_OPTIONS
+
+case $0 in
+ *_developer)
+ EXTRA_VM_OPTIONS+=('--enable-asserts')
+ ;;
+esac
+
+# We allow extra vm options to be passed in through an environment variable.
+if [[ $DART_VM_OPTIONS ]]; then
+ read -a OPTIONS <<< "$DART_VM_OPTIONS"
+ EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
+fi
+
+DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
+
+ANALYZER="$DART_ROOT/pkg/analyzer_cli/bin/analyzer.dart"
+
+DEV_OPTIONS="--use-analysis-driver-memory-byte-store"
+
+exec "$DART" "--packages=$DART_ROOT/.packages" "${EXTRA_VM_OPTIONS[@]}" "$ANALYZER" "$DEV_OPTIONS" "$SDK_ARG" "$@"
diff --git a/sdk_nnbd/bin/dartanalyzer.bat b/sdk_nnbd/bin/dartanalyzer.bat
new file mode 100644
index 0000000..efa3a6a
--- /dev/null
+++ b/sdk_nnbd/bin/dartanalyzer.bat
@@ -0,0 +1,70 @@
+@echo off
+REM Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set SDK_ARG=--dart-sdk=%SDK_DIR%
+
+set EXTRA_VM_OPTIONS=
+
+if _%DARTANALYZER_DEVELOPER_MODE%_ == _1_ (
+ set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% --enable_asserts
+)
+
+rem We allow extra vm options to be passed in through an environment variable.
+if not "_%DART_VM_OPTIONS%_" == "__" (
+ set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
+)
+
+rem Get absolute full name for DART_ROOT.
+for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
+
+rem Remove trailing backslash if there is one
+if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
+
+set ANALYZER=%DART_ROOT%\pkg\analyzer_cli\bin\analyzer.dart
+
+"%DART%" "--packages=%DART_ROOT%\.packages" %EXTRA_VM_OPTIONS% "%ANALYZER%" "%SDK_ARG%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013 10:11 PM <JUNCTION> abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartanalyzer_developer b/sdk_nnbd/bin/dartanalyzer_developer
new file mode 100755
index 0000000..373dc67
--- /dev/null
+++ b/sdk_nnbd/bin/dartanalyzer_developer
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+. ${BASH_SOURCE%_developer}
diff --git a/sdk_nnbd/bin/dartanalyzer_developer.bat b/sdk_nnbd/bin/dartanalyzer_developer.bat
new file mode 100644
index 0000000..b560fe8
--- /dev/null
+++ b/sdk_nnbd/bin/dartanalyzer_developer.bat
@@ -0,0 +1,10 @@
+@echo off
+REM Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+set DARTANALYZER_DEVELOPER_MODE=1
+call "%~dp0dartanalyzer.bat" %*
+endlocal
+exit /b %errorlevel%
diff --git a/sdk_nnbd/bin/dartanalyzer_sdk b/sdk_nnbd/bin/dartanalyzer_sdk
new file mode 100755
index 0000000..28f37ab
--- /dev/null
+++ b/sdk_nnbd/bin/dartanalyzer_sdk
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dartanalyzer.dart on the Dart VM. This script assumes the Dart SDK's
+# directory structure.
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+SDK_ARG="--dart-sdk=$SDK_DIR"
+
+SNAPSHOT="$BIN_DIR/snapshots/dartanalyzer.dart.snapshot"
+
+# We are running the snapshot in the built SDK.
+DART="$BIN_DIR/dart"
+exec "$DART" "$SNAPSHOT" "$SDK_ARG" "$@"
diff --git a/sdk_nnbd/bin/dartanalyzer_sdk.bat b/sdk_nnbd/bin/dartanalyzer_sdk.bat
new file mode 100644
index 0000000..ab66885
--- /dev/null
+++ b/sdk_nnbd/bin/dartanalyzer_sdk.bat
@@ -0,0 +1,52 @@
+@echo off
+REM Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\dartanalyzer.dart.snapshot
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set SDK_ARG=--dart-sdk=%SDK_DIR%
+
+"%DART%" "%SNAPSHOT%" "%SDK_ARG%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013 10:11 PM <JUNCTION> abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| find "> %~n1 [" 2^>nul`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartdevc b/sdk_nnbd/bin/dartdevc
new file mode 100755
index 0000000..5b75ad2
--- /dev/null
+++ b/sdk_nnbd/bin/dartdevc
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dev compiler on the Dart VM. This script assumes the Dart repo's
+# directory structure.
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+SDK_ARG="--dart-sdk=$SDK_DIR"
+
+DART="$BIN_DIR/dart"
+
+unset EXTRA_VM_OPTIONS
+declare -a EXTRA_VM_OPTIONS
+
+case $0 in
+ *_developer)
+ EXTRA_VM_OPTIONS+=('--checked')
+ ;;
+esac
+
+# We allow extra vm options to be passed in through an environment variable.
+if [[ $DART_VM_OPTIONS ]]; then
+ read -a OPTIONS <<< "$DART_VM_OPTIONS"
+ EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
+fi
+
+DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
+
+DEV_COMPILER="$DART_ROOT/pkg/dev_compiler/bin/dartdevc.dart"
+
+exec "$DART" "--packages=$DART_ROOT/.packages" "${EXTRA_VM_OPTIONS[@]}" "$DEV_COMPILER" "$SDK_ARG" "$@"
diff --git a/sdk_nnbd/bin/dartdevc.bat b/sdk_nnbd/bin/dartdevc.bat
new file mode 100644
index 0000000..fec39e4
--- /dev/null
+++ b/sdk_nnbd/bin/dartdevc.bat
@@ -0,0 +1,66 @@
+@echo off
+REM Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set SDK_ARG=--dart-sdk=%SDK_DIR%
+
+set EXTRA_VM_OPTIONS=
+
+rem We allow extra vm options to be passed in through an environment variable.
+if not "_%DART_VM_OPTIONS%_" == "__" (
+ set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
+)
+
+rem Get absolute full name for DART_ROOT.
+for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
+
+rem Remove trailing backslash if there is one
+if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
+
+set DEV_COMPILER=%DART_ROOT%\third_party\pkg\dev_compiler\bin\dartdevc.dart
+
+"%DART%" "--packages=%DART_ROOT%\.packages" %EXTRA_VM_OPTIONS% "DEV_COMPILER%" "%SDK_ARG%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013 10:11 PM <JUNCTION> abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| find "> %~n1 [" 2^>nul`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartdevc_sdk b/sdk_nnbd/bin/dartdevc_sdk
new file mode 100755
index 0000000..60d2fe1
--- /dev/null
+++ b/sdk_nnbd/bin/dartdevc_sdk
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dev compiler on the Dart VM. This script assumes the Dart SDK's
+# directory structure.
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+SNAPSHOT="$BIN_DIR/snapshots/dartdevc.dart.snapshot"
+
+# We are running the snapshot in the built SDK.
+DART="$BIN_DIR/dart"
+exec "$DART" "$SNAPSHOT" "$@"
diff --git a/sdk_nnbd/bin/dartdevc_sdk.bat b/sdk_nnbd/bin/dartdevc_sdk.bat
new file mode 100644
index 0000000..5dbf707
--- /dev/null
+++ b/sdk_nnbd/bin/dartdevc_sdk.bat
@@ -0,0 +1,52 @@
+@echo off
+REM Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\dartdevc.dart.snapshot
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set SDK_ARG=--dart-sdk=%SDK_DIR%
+
+"%DART%" "%SNAPSHOT%" "%SDK_ARG%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013 10:11 PM <JUNCTION> abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| find "> %~n1 ["`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartdoc b/sdk_nnbd/bin/dartdoc
new file mode 100755
index 0000000..e9584c1
--- /dev/null
+++ b/sdk_nnbd/bin/dartdoc
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+SNAPSHOT="$BIN_DIR/snapshots/dartdoc.dart.snapshot"
+
+# We are running the snapshot in the built SDK.
+DART="$BIN_DIR/dart"
+exec "$DART" "--packages=$BIN_DIR/resources/dartdoc/.packages" "$SNAPSHOT" "$@"
diff --git a/sdk_nnbd/bin/dartdoc.bat b/sdk_nnbd/bin/dartdoc.bat
new file mode 100644
index 0000000..876eb0e
--- /dev/null
+++ b/sdk_nnbd/bin/dartdoc.bat
@@ -0,0 +1,44 @@
+@echo off
+REM Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\dartdoc.dart.snapshot
+
+"%DART%" "--packages=%BIN_DIR%/resources/dartdoc/.packages" "%SNAPSHOT%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013 10:11 PM <JUNCTION> abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartfmt b/sdk_nnbd/bin/dartfmt
new file mode 100755
index 0000000..ad54140
--- /dev/null
+++ b/sdk_nnbd/bin/dartfmt
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dart_style/bin/format.dart on the Dart VM. This script assumes the Dart
+# repo's directory structure.
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+DART="$BIN_DIR/dart"
+
+DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
+
+DARTFMT="$DART_ROOT/third_party/pkg_tested/dart_style/bin/format.dart"
+
+exec "$DART" "--packages=$DART_ROOT/.packages" "$DARTFMT" "$@"
diff --git a/sdk_nnbd/bin/dartfmt.bat b/sdk_nnbd/bin/dartfmt.bat
new file mode 100644
index 0000000..7a7412b
--- /dev/null
+++ b/sdk_nnbd/bin/dartfmt.bat
@@ -0,0 +1,57 @@
+@echo off
+REM Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+rem Get absolute full name for DART_ROOT.
+for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
+
+rem Remove trailing backslash if there is one
+if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
+
+set DARTFMT=%DART_ROOT%\third_party\pkg_tested\dart_style\bin\format.dart
+
+"%DART%" "--packages=%DART_ROOT%\.packages" "%DARTFMT%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013 10:11 PM <JUNCTION> abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/dartfmt_sdk b/sdk_nnbd/bin/dartfmt_sdk
new file mode 100755
index 0000000..273733c
--- /dev/null
+++ b/sdk_nnbd/bin/dartfmt_sdk
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dart_style/bin/format.dart on the Dart VM. This script assumes the Dart
+# SDK's directory structure.
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+SNAPSHOT="$BIN_DIR/snapshots/dartfmt.dart.snapshot"
+
+# We are running the snapshot in the built SDK.
+DART="$BIN_DIR/dart"
+exec "$DART" "$SNAPSHOT" "$@"
diff --git a/sdk_nnbd/bin/dartfmt_sdk.bat b/sdk_nnbd/bin/dartfmt_sdk.bat
new file mode 100644
index 0000000..295b977
--- /dev/null
+++ b/sdk_nnbd/bin/dartfmt_sdk.bat
@@ -0,0 +1,44 @@
+@echo off
+REM Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\dartfmt.dart.snapshot
+
+"%DART%" "%SNAPSHOT%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013 10:11 PM <JUNCTION> abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| find "> %~n1 ["`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/pub b/sdk_nnbd/bin/pub
new file mode 100755
index 0000000..5dda611
--- /dev/null
+++ b/sdk_nnbd/bin/pub
@@ -0,0 +1,85 @@
+#!/usr/bin/env bash
+# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run pub.dart on the Dart VM. This script is only used when running pub from
+# within the Dart source repo. The shipped SDK instead uses "pub_sdk", which is
+# renamed to "pub" when the SDK is built.
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+SNAPSHOT="$BIN_DIR/snapshots/pub.dart.snapshot"
+
+unset VM_OPTIONS
+declare -a VM_OPTIONS
+
+if [[ `uname` == 'Darwin' ]];
+then
+ OUT_DIR="$BIN_DIR"/../../xcodebuild/
+else
+ OUT_DIR="$BIN_DIR"/../../out/
+fi
+
+# Allow extra VM options to be passed in through an environment variable.
+if [[ $DART_VM_OPTIONS ]]; then
+ read -a OPTIONS <<< "$DART_VM_OPTIONS"
+ VM_OPTIONS+=("${OPTIONS[@]}")
+fi
+
+if [ -z "$DART_CONFIGURATION" ];
+then
+ DIRS=$( ls "$OUT_DIR" )
+ # list of possible configurations in decreasing desirability
+ CONFIGS=("ReleaseX64" "ReleaseIA32" "DebugX64" "DebugIA32"
+ "ReleaseARM" "ReleaseARM64" "ReleaseARMV5TE"
+ "DebugARM" "DebugARM64" "DebugARMV5TE")
+ DART_CONFIGURATION="None"
+ for CONFIG in ${CONFIGS[*]}
+ do
+ for DIR in $DIRS;
+ do
+ if [ "$CONFIG" = "$DIR" ];
+ then
+ # choose most desirable configuration that is available and break
+ DART_CONFIGURATION="$DIR"
+ break 2
+ fi
+ done
+ done
+ if [ "$DART_CONFIGURATION" = "None" ]
+ then
+ echo "No valid dart configuration found in $OUT_DIR"
+ exit 1
+ fi
+fi
+
+if [[ `uname` == 'Darwin' ]];
+then
+ BUILD_DIR="$SDK_DIR/../xcodebuild/$DART_CONFIGURATION"
+else
+ BUILD_DIR="$SDK_DIR/../out/$DART_CONFIGURATION"
+fi
+
+# Use the Dart binary in the built SDK so pub can find the version file next
+# to it.
+DART="$BUILD_DIR/dart-sdk/bin/dart"
+
+# Run pub.
+PUB="$SDK_DIR/../third_party/pkg/pub/bin/pub.dart"
+exec "$DART" "--packages=$SDK_DIR/../.packages" "${VM_OPTIONS[@]}" "$PUB" "$@"
diff --git a/sdk_nnbd/bin/pub.bat b/sdk_nnbd/bin/pub.bat
new file mode 100644
index 0000000..7eb8b0d
--- /dev/null
+++ b/sdk_nnbd/bin/pub.bat
@@ -0,0 +1,56 @@
+@echo off
+REM Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+rem Run pub.dart on the Dart VM. This script is only used when running pub from
+rem within the Dart source repo. The shipped SDK instead uses "pub_sdk.bat",
+rem which is renamed to "pub.bat" when the SDK is built.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set VM_OPTIONS=
+
+rem We allow extra vm options to be passed in through an environment variable.
+if not "_%DART_VM_OPTIONS%_" == "__" (
+ set VM_OPTIONS=%VM_OPTIONS% %DART_VM_OPTIONS%
+)
+
+rem Use the Dart binary in the built SDK so pub can find the version file next
+rem to it.
+set BUILD_DIR=%SDK_DIR%\..\out\ReleaseX64
+set DART=%BUILD_DIR%\dart-sdk\bin\dart
+
+rem Run pub.
+set PUB="%SDK_DIR%\..\third_party\pkg\pub\bin\pub.dart"
+"%DART%" "--packages=%SDK_DIR%\..\.packages" %VM_OPTIONS% "%PUB%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/bin/pub_sdk b/sdk_nnbd/bin/pub_sdk
new file mode 100755
index 0000000..4d29878
--- /dev/null
+++ b/sdk_nnbd/bin/pub_sdk
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run pub.dart on the Dart VM. This script assumes the Dart SDK's directory
+# structure.
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+function array_contains() {
+ local needle="$1"
+ local element
+ shift
+ for element; do [ "$element" = "$needle" ] && return 0; done
+ return 1
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+
+unset VM_OPTIONS
+declare -a VM_OPTIONS
+
+# Allow extra VM options to be passed in through an environment variable.
+if [[ $DART_VM_OPTIONS ]]; then
+ read -a OPTIONS <<< "$DART_VM_OPTIONS"
+ VM_OPTIONS+=("${OPTIONS[@]}")
+fi
+
+# Run the pub snapshot.
+DART="$BIN_DIR/dart"
+if array_contains "--no-preview-dart-2" "${VM_OPTIONS[@]}"; then
+ echo "Pub no longer supports Dart 1"
+ exit -1
+else
+ SNAPSHOT="$BIN_DIR/snapshots/pub.dart.snapshot"
+ exec "$DART" "${VM_OPTIONS[@]}" "$SNAPSHOT" "$@"
+fi
diff --git a/sdk_nnbd/bin/pub_sdk.bat b/sdk_nnbd/bin/pub_sdk.bat
new file mode 100644
index 0000000..bde0e4a
--- /dev/null
+++ b/sdk_nnbd/bin/pub_sdk.bat
@@ -0,0 +1,53 @@
+@echo off
+REM Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
+
+rem Remove trailing backslash if there is one
+IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
+
+set VM_OPTIONS=
+set USING_DART_1=
+
+rem We allow extra vm options to be passed in through an environment variable.
+if not "_%DART_VM_OPTIONS%_" == "__" (
+ set VM_OPTIONS=%VM_OPTIONS% %DART_VM_OPTIONS%
+ for %%o in (%DART_VM_OPTIONS%) do (
+ if "%%o" equ "--no-preview-dart-2" set USING_DART_1=y
+ )
+)
+
+if defined USING_DART_1 (
+ echo "Pub no longer supports Dart 1"
+) else (
+ "%BIN_DIR%\dart" %VM_OPTIONS% "%BIN_DIR%\snapshots\pub.dart.snapshot" %*
+)
+
+endlocal
+
+exit /b %errorlevel%
+
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| find "> %~n1 [" 2^>nul`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk_nnbd/lib/_chrome/dart2js/chrome_dart2js.dart b/sdk_nnbd/lib/_chrome/dart2js/chrome_dart2js.dart
new file mode 100644
index 0000000..023afe4
--- /dev/null
+++ b/sdk_nnbd/lib/_chrome/dart2js/chrome_dart2js.dart
@@ -0,0 +1,1258 @@
+/// Native wrappers for the Chrome packaged app APIs.
+///
+/// These functions allow direct access to the chrome.* APIs, allowing
+/// Chrome packaged apps to be written using Dart.
+///
+/// For more information on these APIs, see the
+/// [chrome.* API documentation](http://developer.chrome.com/apps/api_index.html).
+library _chrome;
+
+import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper';
+import 'dart:html_common';
+import 'dart:html';
+
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// DO NOT EDIT
+// Auto-generated dart:_chrome library.
+
+/* TODO(sashab): Add "show convertDartClosureToJS" once 'show' works. */
+
+// Generated files below this line.
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A set of utilities for use with the Chrome Extension APIs.
+ *
+ * Allows for easy access to required JS objects.
+ */
+
+/**
+ * A dart object, that is convertible to JS. Used for creating objects in dart,
+ * then passing them to JS.
+ *
+ * Objects that are passable to JS need to implement this interface.
+ */
+abstract class ChromeObject {
+ /*
+ * Default Constructor
+ *
+ * Called by child objects during their regular construction.
+ */
+ ChromeObject() : _jsObject = JS('var', '{}');
+
+ /*
+ * Internal proxy constructor
+ *
+ * Creates a new Dart object using this existing proxy.
+ */
+ ChromeObject._proxy(this._jsObject);
+
+ /*
+ * JS Object Representation
+ */
+ final Object _jsObject;
+}
+
+/**
+ * Useful functions for converting arguments.
+ */
+
+/**
+ * Converts the given map-type argument to js-friendly format, recursively.
+ * Returns the new Map object.
+ */
+Object _convertMapArgument(Map argument) {
+ Map m = new Map();
+ for (Object key in argument.keys) m[key] = convertArgument(argument[key]);
+ return convertDartToNative_Dictionary(m);
+}
+
+/**
+ * Converts the given list-type argument to js-friendly format, recursively.
+ * Returns the new List object.
+ */
+List _convertListArgument(List argument) {
+ List l = new List();
+ for (var i = 0; i < argument.length; i++) l.add(convertArgument(argument[i]));
+ return l;
+}
+
+/**
+ * Converts the given argument Object to js-friendly format, recursively.
+ *
+ * Flattens out all Chrome objects into their corresponding ._toMap()
+ * definitions, then converts them to JS objects.
+ *
+ * Returns the new argument.
+ *
+ * Cannot be used for functions.
+ */
+Object convertArgument(var argument) {
+ if (argument == null) return argument;
+
+ if (argument is num || argument is String || argument is bool)
+ return argument;
+
+ if (argument is ChromeObject) return argument._jsObject;
+
+ if (argument is List) return _convertListArgument(argument);
+
+ if (argument is Map) return _convertMapArgument(argument);
+
+ if (argument is Function)
+ throw new Exception("Cannot serialize Function argument ${argument}.");
+
+ // TODO(sashab): Try and detect whether the argument is already serialized.
+ return argument;
+}
+
+/// Description of a declarative rule for handling events.
+class Rule extends ChromeObject {
+ /*
+ * Public (Dart) constructor
+ */
+ Rule({String id, List conditions, List actions, int priority}) {
+ this.id = id;
+ this.conditions = conditions;
+ this.actions = actions;
+ this.priority = priority;
+ }
+
+ /*
+ * Private (JS) constructor
+ */
+ Rule._proxy(_jsObject) : super._proxy(_jsObject);
+
+ /*
+ * Public accessors
+ */
+ String get id => JS('String', '#.id', this._jsObject);
+
+ void set id(String id) {
+ JS('void', '#.id = #', this._jsObject, id);
+ }
+
+ // TODO(sashab): Wrap these generic Lists somehow.
+ List get conditions => JS('List', '#.conditions', this._jsObject);
+
+ void set conditions(List conditions) {
+ JS('void', '#.conditions = #', this._jsObject, convertArgument(conditions));
+ }
+
+ // TODO(sashab): Wrap these generic Lists somehow.
+ List get actions => JS('List', '#.actions', this._jsObject);
+
+ void set actions(List actions) {
+ JS('void', '#.actions = #', this._jsObject, convertArgument(actions));
+ }
+
+ int get priority => JS('int', '#.priority', this._jsObject);
+
+ void set priority(int priority) {
+ JS('void', '#.priority = #', this._jsObject, priority);
+ }
+}
+
+/**
+ * The Event class.
+ *
+ * Chrome Event classes extend this interface.
+ *
+ * e.g.
+ *
+ * // chrome.app.runtime.onLaunched
+ * class Event_ChromeAppRuntimeOnLaunched extends Event {
+ * // constructor, passing the arity of the callback
+ * Event_ChromeAppRuntimeOnLaunched(jsObject) :
+ * super._(jsObject, 1);
+ *
+ * // methods, strengthening the Function parameter specificity
+ * void addListener(void callback(LaunchData launchData))
+ * => super.addListener(callback);
+ * void removeListener(void callback(LaunchData launchData))
+ * => super.removeListener(callback);
+ * bool hasListener(void callback(LaunchData launchData))
+ * => super.hasListener(callback);
+ * }
+ *
+ */
+class Event {
+ /*
+ * JS Object Representation
+ */
+ final Object _jsObject;
+
+ /*
+ * Number of arguments the callback takes.
+ */
+ final int _callbackArity;
+
+ /*
+ * Private constructor
+ */
+ Event._(this._jsObject, this._callbackArity);
+
+ /*
+ * Methods
+ */
+
+ /// Registers an event listener <em>callback</em> to an event.
+ void addListener(covariant Function callback) => JS(
+ 'void',
+ '#.addListener(#)',
+ this._jsObject,
+ convertDartClosureToJS(callback, this._callbackArity));
+
+ /// Deregisters an event listener <em>callback</em> from an event.
+ void removeListener(covariant Function callback) => JS(
+ 'void',
+ '#.removeListener(#)',
+ this._jsObject,
+ convertDartClosureToJS(callback, this._callbackArity));
+
+ /// Returns True if <em>callback</em> is registered to the event.
+ bool hasListener(covariant Function callback) => JS(
+ 'bool',
+ '#.hasListener(#)',
+ this._jsObject,
+ convertDartClosureToJS(callback, this._callbackArity));
+
+ /// Returns true if any event listeners are registered to the event.
+ bool hasListeners() => JS('bool', '#.hasListeners()', this._jsObject);
+
+ /// Registers rules to handle events.
+ ///
+ /// [eventName] is the name of the event this function affects and [rules] are
+ /// the rules to be registered. These do not replace previously registered
+ /// rules. [callback] is called with registered rules.
+ ///
+ void addRules(String eventName, List<Rule> rules,
+ [void callback(List<Rule> rules)]) {
+ // proxy the callback
+ void __proxy_callback(List rules) {
+ if (callback != null) {
+ List<Rule> __proxy_rules = new List<Rule>();
+
+ for (Object o in rules) __proxy_rules.add(new Rule._proxy(o));
+
+ callback(__proxy_rules);
+ }
+ }
+
+ JS(
+ 'void',
+ '#.addRules(#, #, #)',
+ this._jsObject,
+ convertArgument(eventName),
+ convertArgument(rules),
+ convertDartClosureToJS(__proxy_callback, 1));
+ }
+
+ /// Returns currently registered rules.
+ ///
+ /// [eventName] is the name of the event this function affects and, if an array
+ /// is passed as [ruleIdentifiers], only rules with identifiers contained in
+ /// this array are returned. [callback] is called with registered rules.
+ ///
+ void getRules(String eventName,
+ [List<String> ruleIdentifiers, void callback(List<Rule> rules)]) {
+ // proxy the callback
+ void __proxy_callback(List rules) {
+ if (callback != null) {
+ List<Rule> __proxy_rules = new List<Rule>();
+
+ for (Object o in rules) __proxy_rules.add(new Rule._proxy(o));
+
+ callback(__proxy_rules);
+ }
+ }
+
+ JS(
+ 'void',
+ '#.getRules(#, #, #)',
+ this._jsObject,
+ convertArgument(eventName),
+ convertArgument(ruleIdentifiers),
+ convertDartClosureToJS(__proxy_callback, 1));
+ }
+
+ /// Unregisters currently registered rules.
+ ///
+ /// [eventName] is the name of the event this function affects and, if an array
+ /// is passed as [ruleIdentifiers], only rules with identifiers contained in
+ /// this array are unregistered. [callback] is called when the rules are
+ /// unregistered.
+ ///
+ void removeRules(String eventName,
+ [List<String> ruleIdentifiers, void callback()]) =>
+ JS(
+ 'void',
+ '#.removeRules(#, #, #)',
+ this._jsObject,
+ convertArgument(eventName),
+ convertArgument(ruleIdentifiers),
+ convertDartClosureToJS(callback, 0));
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// chrome.app
+class API_ChromeApp {
+ /*
+ * JS Variable
+ */
+ final Object _jsObject;
+
+ /*
+ * Members
+ */
+ API_app_window window;
+ API_app_runtime runtime;
+
+ /*
+ * Constructor
+ */
+ API_ChromeApp(this._jsObject) {
+ var window_object = JS('', '#.window', this._jsObject);
+ if (window_object == null)
+ throw new UnsupportedError('Not supported by current browser.');
+ window = new API_app_window(window_object);
+
+ var runtime_object = JS('', '#.runtime', this._jsObject);
+ if (runtime_object == null)
+ throw new UnsupportedError('Not supported by current browser.');
+ runtime = new API_app_runtime(runtime_object);
+ }
+}
+
+// chrome
+class API_Chrome {
+ /*
+ * JS Variable
+ */
+ Object _jsObject;
+
+ /*
+ * Members
+ */
+ API_ChromeApp app;
+ API_file_system fileSystem;
+
+ /*
+ * Constructor
+ */
+ API_Chrome() {
+ this._jsObject = JS("Object", "chrome");
+ if (this._jsObject == null)
+ throw new UnsupportedError('Not supported by current browser.');
+
+ var app_object = JS('', '#.app', this._jsObject);
+ if (app_object == null)
+ throw new UnsupportedError('Not supported by current browser.');
+ app = new API_ChromeApp(app_object);
+
+ var file_system_object = JS('', '#.fileSystem', this._jsObject);
+ if (file_system_object == null)
+ throw new UnsupportedError('Not supported by current browser.');
+ fileSystem = new API_file_system(file_system_object);
+ }
+}
+
+// The final chrome objects
+final API_Chrome chrome = new API_Chrome();
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Generated from namespace: app.window
+
+/**
+ * Types
+ */
+
+class AppWindowBounds extends ChromeObject {
+ /*
+ * Public constructor
+ */
+ AppWindowBounds({int left, int top, int width, int height}) {
+ if (left != null) this.left = left;
+ if (top != null) this.top = top;
+ if (width != null) this.width = width;
+ if (height != null) this.height = height;
+ }
+
+ /*
+ * Private constructor
+ */
+ AppWindowBounds._proxy(_jsObject) : super._proxy(_jsObject);
+
+ /*
+ * Public accessors
+ */
+ int get left => JS('int', '#.left', this._jsObject);
+
+ void set left(int left) {
+ JS('void', '#.left = #', this._jsObject, left);
+ }
+
+ int get top => JS('int', '#.top', this._jsObject);
+
+ void set top(int top) {
+ JS('void', '#.top = #', this._jsObject, top);
+ }
+
+ int get width => JS('int', '#.width', this._jsObject);
+
+ void set width(int width) {
+ JS('void', '#.width = #', this._jsObject, width);
+ }
+
+ int get height => JS('int', '#.height', this._jsObject);
+
+ void set height(int height) {
+ JS('void', '#.height = #', this._jsObject, height);
+ }
+}
+
+class AppWindowCreateWindowOptions extends ChromeObject {
+ /*
+ * Public constructor
+ */
+ AppWindowCreateWindowOptions(
+ {String id,
+ int defaultWidth,
+ int defaultHeight,
+ int defaultLeft,
+ int defaultTop,
+ int width,
+ int height,
+ int left,
+ int top,
+ int minWidth,
+ int minHeight,
+ int maxWidth,
+ int maxHeight,
+ String type,
+ String frame,
+ AppWindowBounds bounds,
+ bool transparentBackground,
+ String state,
+ bool hidden,
+ bool resizable,
+ bool singleton}) {
+ if (id != null) this.id = id;
+ if (defaultWidth != null) this.defaultWidth = defaultWidth;
+ if (defaultHeight != null) this.defaultHeight = defaultHeight;
+ if (defaultLeft != null) this.defaultLeft = defaultLeft;
+ if (defaultTop != null) this.defaultTop = defaultTop;
+ if (width != null) this.width = width;
+ if (height != null) this.height = height;
+ if (left != null) this.left = left;
+ if (top != null) this.top = top;
+ if (minWidth != null) this.minWidth = minWidth;
+ if (minHeight != null) this.minHeight = minHeight;
+ if (maxWidth != null) this.maxWidth = maxWidth;
+ if (maxHeight != null) this.maxHeight = maxHeight;
+ if (type != null) this.type = type;
+ if (frame != null) this.frame = frame;
+ if (bounds != null) this.bounds = bounds;
+ if (transparentBackground != null)
+ this.transparentBackground = transparentBackground;
+ if (state != null) this.state = state;
+ if (hidden != null) this.hidden = hidden;
+ if (resizable != null) this.resizable = resizable;
+ if (singleton != null) this.singleton = singleton;
+ }
+
+ /*
+ * Private constructor
+ */
+ AppWindowCreateWindowOptions._proxy(_jsObject) : super._proxy(_jsObject);
+
+ /*
+ * Public accessors
+ */
+ /// Id to identify the window. This will be used to remember the size and
+ /// position of the window and restore that geometry when a window with the
+ /// same id is later opened.
+ String get id => JS('String', '#.id', this._jsObject);
+
+ void set id(String id) {
+ JS('void', '#.id = #', this._jsObject, id);
+ }
+
+ /// Default width of the window. (Deprecated; regular bounds act like this
+ /// now.)
+ int get defaultWidth => JS('int', '#.defaultWidth', this._jsObject);
+
+ void set defaultWidth(int defaultWidth) {
+ JS('void', '#.defaultWidth = #', this._jsObject, defaultWidth);
+ }
+
+ /// Default height of the window. (Deprecated; regular bounds act like this
+ /// now.)
+ int get defaultHeight => JS('int', '#.defaultHeight', this._jsObject);
+
+ void set defaultHeight(int defaultHeight) {
+ JS('void', '#.defaultHeight = #', this._jsObject, defaultHeight);
+ }
+
+ /// Default X coordinate of the window. (Deprecated; regular bounds act like
+ /// this now.)
+ int get defaultLeft => JS('int', '#.defaultLeft', this._jsObject);
+
+ void set defaultLeft(int defaultLeft) {
+ JS('void', '#.defaultLeft = #', this._jsObject, defaultLeft);
+ }
+
+ /// Default Y coordinate of the window. (Deprecated; regular bounds act like
+ /// this now.)
+ int get defaultTop => JS('int', '#.defaultTop', this._jsObject);
+
+ void set defaultTop(int defaultTop) {
+ JS('void', '#.defaultTop = #', this._jsObject, defaultTop);
+ }
+
+ /// Width of the window. (Deprecated; use 'bounds'.)
+ int get width => JS('int', '#.width', this._jsObject);
+
+ void set width(int width) {
+ JS('void', '#.width = #', this._jsObject, width);
+ }
+
+ /// Height of the window. (Deprecated; use 'bounds'.)
+ int get height => JS('int', '#.height', this._jsObject);
+
+ void set height(int height) {
+ JS('void', '#.height = #', this._jsObject, height);
+ }
+
+ /// X coordinate of the window. (Deprecated; use 'bounds'.)
+ int get left => JS('int', '#.left', this._jsObject);
+
+ void set left(int left) {
+ JS('void', '#.left = #', this._jsObject, left);
+ }
+
+ /// Y coordinate of the window. (Deprecated; use 'bounds'.)
+ int get top => JS('int', '#.top', this._jsObject);
+
+ void set top(int top) {
+ JS('void', '#.top = #', this._jsObject, top);
+ }
+
+ /// Minimum width for the lifetime of the window.
+ int get minWidth => JS('int', '#.minWidth', this._jsObject);
+
+ void set minWidth(int minWidth) {
+ JS('void', '#.minWidth = #', this._jsObject, minWidth);
+ }
+
+ /// Minimum height for the lifetime of the window.
+ int get minHeight => JS('int', '#.minHeight', this._jsObject);
+
+ void set minHeight(int minHeight) {
+ JS('void', '#.minHeight = #', this._jsObject, minHeight);
+ }
+
+ /// Maximum width for the lifetime of the window.
+ int get maxWidth => JS('int', '#.maxWidth', this._jsObject);
+
+ void set maxWidth(int maxWidth) {
+ JS('void', '#.maxWidth = #', this._jsObject, maxWidth);
+ }
+
+ /// Maximum height for the lifetime of the window.
+ int get maxHeight => JS('int', '#.maxHeight', this._jsObject);
+
+ void set maxHeight(int maxHeight) {
+ JS('void', '#.maxHeight = #', this._jsObject, maxHeight);
+ }
+
+ /// Type of window to create.
+ String get type => JS('String', '#.type', this._jsObject);
+
+ void set type(String type) {
+ JS('void', '#.type = #', this._jsObject, type);
+ }
+
+ /// Frame type: 'none' or 'chrome' (defaults to 'chrome').
+ String get frame => JS('String', '#.frame', this._jsObject);
+
+ void set frame(String frame) {
+ JS('void', '#.frame = #', this._jsObject, frame);
+ }
+
+ /// Size and position of the content in the window (excluding the titlebar). If
+ /// an id is also specified and a window with a matching id has been shown
+ /// before, the remembered bounds of the window will be used instead.
+ AppWindowBounds get bounds =>
+ new AppWindowBounds._proxy(JS('', '#.bounds', this._jsObject));
+
+ void set bounds(AppWindowBounds bounds) {
+ JS('void', '#.bounds = #', this._jsObject, convertArgument(bounds));
+ }
+
+ /// Enable window background transparency. Only supported in ash. Requires
+ /// experimental API permission.
+ bool get transparentBackground =>
+ JS('bool', '#.transparentBackground', this._jsObject);
+
+ void set transparentBackground(bool transparentBackground) {
+ JS('void', '#.transparentBackground = #', this._jsObject,
+ transparentBackground);
+ }
+
+ /// The initial state of the window, allowing it to be created already
+ /// fullscreen, maximized, or minimized. Defaults to 'normal'.
+ String get state => JS('String', '#.state', this._jsObject);
+
+ void set state(String state) {
+ JS('void', '#.state = #', this._jsObject, state);
+ }
+
+ /// If true, the window will be created in a hidden state. Call show() on the
+ /// window to show it once it has been created. Defaults to false.
+ bool get hidden => JS('bool', '#.hidden', this._jsObject);
+
+ void set hidden(bool hidden) {
+ JS('void', '#.hidden = #', this._jsObject, hidden);
+ }
+
+ /// If true, the window will be resizable by the user. Defaults to true.
+ bool get resizable => JS('bool', '#.resizable', this._jsObject);
+
+ void set resizable(bool resizable) {
+ JS('void', '#.resizable = #', this._jsObject, resizable);
+ }
+
+ /// By default if you specify an id for the window, the window will only be
+ /// created if another window with the same id doesn't already exist. If a
+ /// window with the same id already exists that window is activated instead. If
+ /// you do want to create multiple windows with the same id, you can set this
+ /// property to false.
+ bool get singleton => JS('bool', '#.singleton', this._jsObject);
+
+ void set singleton(bool singleton) {
+ JS('void', '#.singleton = #', this._jsObject, singleton);
+ }
+}
+
+class AppWindowAppWindow extends ChromeObject {
+ /*
+ * Private constructor
+ */
+ AppWindowAppWindow._proxy(_jsObject) : super._proxy(_jsObject);
+
+ /*
+ * Public accessors
+ */
+ /// The JavaScript 'window' object for the created child.
+ // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+ // for details. All rights reserved. Use of this source code is governed by a
+ // BSD-style license that can be found in the LICENSE file.
+
+ // TODO(sashab, sra): Detect whether this is the current window, or an
+ // external one, and return an appropriately-typed object
+ WindowBase get contentWindow =>
+ JS("Window", "#.contentWindow", this._jsObject);
+
+ /*
+ * Methods
+ */
+ /// Focus the window.
+ void focus() => JS('void', '#.focus()', this._jsObject);
+
+ /// Fullscreens the window.
+ void fullscreen() => JS('void', '#.fullscreen()', this._jsObject);
+
+ /// Is the window fullscreen?
+ bool isFullscreen() => JS('bool', '#.isFullscreen()', this._jsObject);
+
+ /// Minimize the window.
+ void minimize() => JS('void', '#.minimize()', this._jsObject);
+
+ /// Is the window minimized?
+ bool isMinimized() => JS('bool', '#.isMinimized()', this._jsObject);
+
+ /// Maximize the window.
+ void maximize() => JS('void', '#.maximize()', this._jsObject);
+
+ /// Is the window maximized?
+ bool isMaximized() => JS('bool', '#.isMaximized()', this._jsObject);
+
+ /// Restore the window, exiting a maximized, minimized, or fullscreen state.
+ void restore() => JS('void', '#.restore()', this._jsObject);
+
+ /// Move the window to the position (|left|, |top|).
+ void moveTo(int left, int top) =>
+ JS('void', '#.moveTo(#, #)', this._jsObject, left, top);
+
+ /// Resize the window to |width|x|height| pixels in size.
+ void resizeTo(int width, int height) =>
+ JS('void', '#.resizeTo(#, #)', this._jsObject, width, height);
+
+ /// Draw attention to the window.
+ void drawAttention() => JS('void', '#.drawAttention()', this._jsObject);
+
+ /// Clear attention to the window.
+ void clearAttention() => JS('void', '#.clearAttention()', this._jsObject);
+
+ /// Close the window.
+ void close() => JS('void', '#.close()', this._jsObject);
+
+ /// Show the window. Does nothing if the window is already visible.
+ void show() => JS('void', '#.show()', this._jsObject);
+
+ /// Hide the window. Does nothing if the window is already hidden.
+ void hide() => JS('void', '#.hide()', this._jsObject);
+
+ /// Get the window's bounds as a $ref:Bounds object.
+ // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+ // for details. All rights reserved. Use of this source code is governed by a
+ // BSD-style license that can be found in the LICENSE file.
+
+ // TODO(sashab, kalman): Fix IDL parser to read function return values
+ // correctly. Currently, it just reads void for all functions.
+ AppWindowBounds getBounds() =>
+ new AppWindowBounds._proxy(JS('void', '#.getBounds()', this._jsObject));
+
+ /// Set the window's bounds.
+ void setBounds(AppWindowBounds bounds) =>
+ JS('void', '#.setBounds(#)', this._jsObject, convertArgument(bounds));
+
+ /// Set the app icon for the window (experimental). Currently this is only
+ /// being implemented on Ash. TODO(stevenjb): Investigate implementing this on
+ /// Windows and OSX.
+ void setIcon(String icon_url) =>
+ JS('void', '#.setIcon(#)', this._jsObject, icon_url);
+}
+
+/**
+ * Events
+ */
+
+/// Fired when the window is resized.
+class Event_app_window_onBoundsChanged extends Event {
+ void addListener(void callback()) => super.addListener(callback);
+
+ void removeListener(void callback()) => super.removeListener(callback);
+
+ bool hasListener(void callback()) => super.hasListener(callback);
+
+ Event_app_window_onBoundsChanged(jsObject) : super._(jsObject, 0);
+}
+
+/// Fired when the window is closed.
+class Event_app_window_onClosed extends Event {
+ void addListener(void callback()) => super.addListener(callback);
+
+ void removeListener(void callback()) => super.removeListener(callback);
+
+ bool hasListener(void callback()) => super.hasListener(callback);
+
+ Event_app_window_onClosed(jsObject) : super._(jsObject, 0);
+}
+
+/// Fired when the window is fullscreened.
+class Event_app_window_onFullscreened extends Event {
+ void addListener(void callback()) => super.addListener(callback);
+
+ void removeListener(void callback()) => super.removeListener(callback);
+
+ bool hasListener(void callback()) => super.hasListener(callback);
+
+ Event_app_window_onFullscreened(jsObject) : super._(jsObject, 0);
+}
+
+/// Fired when the window is maximized.
+class Event_app_window_onMaximized extends Event {
+ void addListener(void callback()) => super.addListener(callback);
+
+ void removeListener(void callback()) => super.removeListener(callback);
+
+ bool hasListener(void callback()) => super.hasListener(callback);
+
+ Event_app_window_onMaximized(jsObject) : super._(jsObject, 0);
+}
+
+/// Fired when the window is minimized.
+class Event_app_window_onMinimized extends Event {
+ void addListener(void callback()) => super.addListener(callback);
+
+ void removeListener(void callback()) => super.removeListener(callback);
+
+ bool hasListener(void callback()) => super.hasListener(callback);
+
+ Event_app_window_onMinimized(jsObject) : super._(jsObject, 0);
+}
+
+/// Fired when the window is restored from being minimized or maximized.
+class Event_app_window_onRestored extends Event {
+ void addListener(void callback()) => super.addListener(callback);
+
+ void removeListener(void callback()) => super.removeListener(callback);
+
+ bool hasListener(void callback()) => super.hasListener(callback);
+
+ Event_app_window_onRestored(jsObject) : super._(jsObject, 0);
+}
+
+/**
+ * Functions
+ */
+
+class API_app_window {
+ /*
+ * API connection
+ */
+ Object _jsObject;
+
+ /*
+ * Events
+ */
+ Event_app_window_onBoundsChanged onBoundsChanged;
+ Event_app_window_onClosed onClosed;
+ Event_app_window_onFullscreened onFullscreened;
+ Event_app_window_onMaximized onMaximized;
+ Event_app_window_onMinimized onMinimized;
+ Event_app_window_onRestored onRestored;
+
+ /*
+ * Functions
+ */
+ /// The size and position of a window can be specified in a number of different
+ /// ways. The most simple option is not specifying anything at all, in which
+ /// case a default size and platform dependent position will be used.<br/><br/>
+ /// Another option is to use the bounds property, which will put the window at
+ /// the specified coordinates with the specified size. If the window has a
+ /// frame, it's total size will be the size given plus the size of the frame;
+ /// that is, the size in bounds is the content size, not the window
+ /// size.<br/><br/> To automatically remember the positions of windows you can
+ /// give them ids. If a window has an id, This id is used to remember the size
+ /// and position of the window whenever it is moved or resized. This size and
+ /// position is then used instead of the specified bounds on subsequent opening
+ /// of a window with the same id. If you need to open a window with an id at a
+ /// location other than the remembered default, you can create it hidden, move
+ /// it to the desired location, then show it.
+ // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+ // for details. All rights reserved. Use of this source code is governed by a
+ // BSD-style license that can be found in the LICENSE file.
+
+ // TODO(sashab): This override is no longer needed once prefixes are removed.
+ void create(String url,
+ [AppWindowCreateWindowOptions options,
+ void callback(AppWindowAppWindow created_window)]) {
+ void __proxy_callback(created_window) {
+ if (callback != null)
+ callback(new AppWindowAppWindow._proxy(created_window));
+ }
+
+ JS('void', '#.create(#, #, #)', this._jsObject, url,
+ convertArgument(options), convertDartClosureToJS(__proxy_callback, 1));
+ }
+
+ /// Returns an $ref:AppWindow object for the current script context (ie
+ /// JavaScript 'window' object). This can also be called on a handle to a
+ /// script context for another page, for example:
+ /// otherWindow.chrome.app.window.current().
+ // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+ // for details. All rights reserved. Use of this source code is governed by a
+ // BSD-style license that can be found in the LICENSE file.
+
+ // TODO(sashab, kalman): Fix IDL parser to read function return values
+ // correctly. Currently, it just reads void for all functions.
+ AppWindowAppWindow current() =>
+ new AppWindowAppWindow._proxy(JS('void', '#.current()', this._jsObject));
+
+ void initializeAppWindow(Object state) => JS('void',
+ '#.initializeAppWindow(#)', this._jsObject, convertArgument(state));
+
+ API_app_window(this._jsObject) {
+ onBoundsChanged = new Event_app_window_onBoundsChanged(
+ JS('', '#.onBoundsChanged', this._jsObject));
+ onClosed =
+ new Event_app_window_onClosed(JS('', '#.onClosed', this._jsObject));
+ onFullscreened = new Event_app_window_onFullscreened(
+ JS('', '#.onFullscreened', this._jsObject));
+ onMaximized = new Event_app_window_onMaximized(
+ JS('', '#.onMaximized', this._jsObject));
+ onMinimized = new Event_app_window_onMinimized(
+ JS('', '#.onMinimized', this._jsObject));
+ onRestored =
+ new Event_app_window_onRestored(JS('', '#.onRestored', this._jsObject));
+ }
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Generated from namespace: app.runtime
+
+/**
+ * Types
+ */
+
+class AppRuntimeLaunchItem extends ChromeObject {
+ /*
+ * Public constructor
+ */
+ AppRuntimeLaunchItem({FileEntry entry, String type}) {
+ if (entry != null) this.entry = entry;
+ if (type != null) this.type = type;
+ }
+
+ /*
+ * Private constructor
+ */
+ AppRuntimeLaunchItem._proxy(_jsObject) : super._proxy(_jsObject);
+
+ /*
+ * Public accessors
+ */
+ /// FileEntry for the file.
+ FileEntry get entry => JS('FileEntry', '#.entry', this._jsObject);
+
+ void set entry(FileEntry entry) {
+ JS('void', '#.entry = #', this._jsObject, convertArgument(entry));
+ }
+
+ /// The MIME type of the file.
+ String get type => JS('String', '#.type', this._jsObject);
+
+ void set type(String type) {
+ JS('void', '#.type = #', this._jsObject, type);
+ }
+}
+
+class AppRuntimeLaunchData extends ChromeObject {
+ /*
+ * Public constructor
+ */
+ AppRuntimeLaunchData({String id, List<AppRuntimeLaunchItem> items}) {
+ if (id != null) this.id = id;
+ if (items != null) this.items = items;
+ }
+
+ /*
+ * Private constructor
+ */
+ AppRuntimeLaunchData._proxy(_jsObject) : super._proxy(_jsObject);
+
+ /*
+ * Public accessors
+ */
+ /// The id of the file handler that the app is being invoked with.
+ String get id => JS('String', '#.id', this._jsObject);
+
+ void set id(String id) {
+ JS('void', '#.id = #', this._jsObject, id);
+ }
+
+ List<AppRuntimeLaunchItem> get items {
+ List<AppRuntimeLaunchItem> __proxy_items = new List<AppRuntimeLaunchItem>();
+ int count = JS('int', '#.items.length', this._jsObject);
+ for (int i = 0; i < count; i++) {
+ var item = JS('', '#.items[#]', this._jsObject, i);
+ __proxy_items.add(new AppRuntimeLaunchItem._proxy(item));
+ }
+ return __proxy_items;
+ }
+
+ void set items(List<AppRuntimeLaunchItem> items) {
+ JS('void', '#.items = #', this._jsObject, convertArgument(items));
+ }
+}
+
+/**
+ * Events
+ */
+
+/// Fired when an app is launched from the launcher.
+class Event_app_runtime_onLaunched extends Event {
+ void addListener(void callback(AppRuntimeLaunchData launchData)) {
+ void __proxy_callback(launchData) {
+ if (callback != null) {
+ callback(new AppRuntimeLaunchData._proxy(launchData));
+ }
+ }
+
+ super.addListener(__proxy_callback);
+ }
+
+ void removeListener(void callback(AppRuntimeLaunchData launchData)) {
+ void __proxy_callback(launchData) {
+ if (callback != null) {
+ callback(new AppRuntimeLaunchData._proxy(launchData));
+ }
+ }
+
+ super.removeListener(__proxy_callback);
+ }
+
+ bool hasListener(void callback(AppRuntimeLaunchData launchData)) {
+ void __proxy_callback(launchData) {
+ if (callback != null) {
+ callback(new AppRuntimeLaunchData._proxy(launchData));
+ }
+ }
+
+ super.hasListener(__proxy_callback);
+ }
+
+ Event_app_runtime_onLaunched(jsObject) : super._(jsObject, 1);
+}
+
+/// Fired at Chrome startup to apps that were running when Chrome last shut
+/// down.
+class Event_app_runtime_onRestarted extends Event {
+ void addListener(void callback()) => super.addListener(callback);
+
+ void removeListener(void callback()) => super.removeListener(callback);
+
+ bool hasListener(void callback()) => super.hasListener(callback);
+
+ Event_app_runtime_onRestarted(jsObject) : super._(jsObject, 0);
+}
+
+/**
+ * Functions
+ */
+
+class API_app_runtime {
+ /*
+ * API connection
+ */
+ Object _jsObject;
+
+ /*
+ * Events
+ */
+ Event_app_runtime_onLaunched onLaunched;
+ Event_app_runtime_onRestarted onRestarted;
+ API_app_runtime(this._jsObject) {
+ onLaunched = new Event_app_runtime_onLaunched(
+ JS('', '#.onLaunched', this._jsObject));
+ onRestarted = new Event_app_runtime_onRestarted(
+ JS('', '#.onRestarted', this._jsObject));
+ }
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Generated from namespace: fileSystem
+
+/**
+ * Types
+ */
+
+class FilesystemAcceptOption extends ChromeObject {
+ /*
+ * Public constructor
+ */
+ FilesystemAcceptOption(
+ {String description, List<String> mimeTypes, List<String> extensions}) {
+ if (description != null) this.description = description;
+ if (mimeTypes != null) this.mimeTypes = mimeTypes;
+ if (extensions != null) this.extensions = extensions;
+ }
+
+ /*
+ * Private constructor
+ */
+ FilesystemAcceptOption._proxy(_jsObject) : super._proxy(_jsObject);
+
+ /*
+ * Public accessors
+ */
+ /// This is the optional text description for this option. If not present, a
+ /// description will be automatically generated; typically containing an
+ /// expanded list of valid extensions (e.g. "text/html" may expand to "*.html,
+ /// *.htm").
+ String get description => JS('String', '#.description', this._jsObject);
+
+ void set description(String description) {
+ JS('void', '#.description = #', this._jsObject, description);
+ }
+
+ /// Mime-types to accept, e.g. "image/jpeg" or "audio/*". One of mimeTypes or
+ /// extensions must contain at least one valid element.
+ List<String> get mimeTypes =>
+ JS('List<String>', '#.mimeTypes', this._jsObject);
+
+ void set mimeTypes(List<String> mimeTypes) {
+ JS('void', '#.mimeTypes = #', this._jsObject, mimeTypes);
+ }
+
+ /// Extensions to accept, e.g. "jpg", "gif", "crx".
+ List<String> get extensions =>
+ JS('List<String>', '#.extensions', this._jsObject);
+
+ void set extensions(List<String> extensions) {
+ JS('void', '#.extensions = #', this._jsObject, extensions);
+ }
+}
+
+class FilesystemChooseEntryOptions extends ChromeObject {
+ /*
+ * Public constructor
+ */
+ FilesystemChooseEntryOptions(
+ {String type,
+ String suggestedName,
+ List<FilesystemAcceptOption> accepts,
+ bool acceptsAllTypes}) {
+ if (type != null) this.type = type;
+ if (suggestedName != null) this.suggestedName = suggestedName;
+ if (accepts != null) this.accepts = accepts;
+ if (acceptsAllTypes != null) this.acceptsAllTypes = acceptsAllTypes;
+ }
+
+ /*
+ * Private constructor
+ */
+ FilesystemChooseEntryOptions._proxy(_jsObject) : super._proxy(_jsObject);
+
+ /*
+ * Public accessors
+ */
+ /// Type of the prompt to show. The default is 'openFile'.
+ String get type => JS('String', '#.type', this._jsObject);
+
+ void set type(String type) {
+ JS('void', '#.type = #', this._jsObject, type);
+ }
+
+ /// The suggested file name that will be presented to the user as the default
+ /// name to read or write. This is optional.
+ String get suggestedName => JS('String', '#.suggestedName', this._jsObject);
+
+ void set suggestedName(String suggestedName) {
+ JS('void', '#.suggestedName = #', this._jsObject, suggestedName);
+ }
+
+ /// The optional list of accept options for this file opener. Each option will
+ /// be presented as a unique group to the end-user.
+ List<FilesystemAcceptOption> get accepts {
+ List<FilesystemAcceptOption> __proxy_accepts =
+ new List<FilesystemAcceptOption>();
+ int count = JS('int', '#.accepts.length', this._jsObject);
+ for (int i = 0; i < count; i++) {
+ var item = JS('', '#.accepts[#]', this._jsObject, i);
+ __proxy_accepts.add(new FilesystemAcceptOption._proxy(item));
+ }
+ return __proxy_accepts;
+ }
+
+ void set accepts(List<FilesystemAcceptOption> accepts) {
+ JS('void', '#.accepts = #', this._jsObject, convertArgument(accepts));
+ }
+
+ /// Whether to accept all file types, in addition to the options specified in
+ /// the accepts argument. The default is true. If the accepts field is unset or
+ /// contains no valid entries, this will always be reset to true.
+ bool get acceptsAllTypes => JS('bool', '#.acceptsAllTypes', this._jsObject);
+
+ void set acceptsAllTypes(bool acceptsAllTypes) {
+ JS('void', '#.acceptsAllTypes = #', this._jsObject, acceptsAllTypes);
+ }
+}
+
+/**
+ * Functions
+ */
+
+class API_file_system {
+ /*
+ * API connection
+ */
+ Object _jsObject;
+
+ /*
+ * Functions
+ */
+ /// Get the display path of a FileEntry object. The display path is based on
+ /// the full path of the file on the local file system, but may be made more
+ /// readable for display purposes.
+ void getDisplayPath(FileEntry fileEntry, void callback(String displayPath)) =>
+ JS('void', '#.getDisplayPath(#, #)', this._jsObject,
+ convertArgument(fileEntry), convertDartClosureToJS(callback, 1));
+
+ /// Get a writable FileEntry from another FileEntry. This call will fail if the
+ /// application does not have the 'write' permission under 'fileSystem'.
+ void getWritableEntry(
+ FileEntry fileEntry, void callback(FileEntry fileEntry)) {
+ void __proxy_callback(fileEntry) {
+ if (callback != null) {
+ callback(fileEntry);
+ }
+ }
+
+ JS(
+ 'void',
+ '#.getWritableEntry(#, #)',
+ this._jsObject,
+ convertArgument(fileEntry),
+ convertDartClosureToJS(__proxy_callback, 1));
+ }
+
+ /// Gets whether this FileEntry is writable or not.
+ void isWritableEntry(FileEntry fileEntry, void callback(bool isWritable)) =>
+ JS('void', '#.isWritableEntry(#, #)', this._jsObject,
+ convertArgument(fileEntry), convertDartClosureToJS(callback, 1));
+
+ /// Ask the user to choose a file.
+ void chooseEntry(void callback(FileEntry fileEntry),
+ [FilesystemChooseEntryOptions options]) {
+ void __proxy_callback(fileEntry) {
+ if (callback != null) {
+ callback(fileEntry);
+ }
+ }
+
+ JS('void', '#.chooseEntry(#, #)', this._jsObject, convertArgument(options),
+ convertDartClosureToJS(__proxy_callback, 1));
+ }
+
+ /// Returns the file entry with the given id if it can be restored. This call
+ /// will fail otherwise.
+ void restoreEntry(String id, void callback(FileEntry fileEntry)) {
+ void __proxy_callback(fileEntry) {
+ if (callback != null) {
+ callback(fileEntry);
+ }
+ }
+
+ JS('void', '#.restoreEntry(#, #)', this._jsObject, id,
+ convertDartClosureToJS(__proxy_callback, 1));
+ }
+
+ /// Returns whether a file entry for the given id can be restored, i.e. whether
+ /// restoreEntry would succeed with this id now.
+ void isRestorable(String id, void callback(bool isRestorable)) => JS(
+ 'void',
+ '#.isRestorable(#, #)',
+ this._jsObject,
+ id,
+ convertDartClosureToJS(callback, 1));
+
+ /// Returns an id that can be passed to restoreEntry to regain access to a
+ /// given file entry. Only the 500 most recently used entries are retained,
+ /// where calls to retainEntry and restoreEntry count as use. If the app has
+ /// the 'retainEntries' permission under 'fileSystem', entries are retained
+ /// indefinitely. Otherwise, entries are retained only while the app is running
+ /// and across restarts.
+ String retainEntry(FileEntry fileEntry) => JS(
+ 'String', '#.retainEntry(#)', this._jsObject, convertArgument(fileEntry));
+
+ API_file_system(this._jsObject) {}
+}
diff --git a/sdk_nnbd/lib/_http/crypto.dart b/sdk_nnbd/lib/_http/crypto.dart
new file mode 100644
index 0000000..28b65ee
--- /dev/null
+++ b/sdk_nnbd/lib/_http/crypto.dart
@@ -0,0 +1,458 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+class _CryptoUtils {
+ static const int PAD = 61; // '='
+ static const int CR = 13; // '\r'
+ static const int LF = 10; // '\n'
+ static const int LINE_LENGTH = 76;
+
+ static const String _encodeTable =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ static const String _encodeTableUrlSafe =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+ // Lookup table used for finding Base 64 alphabet index of a given byte.
+ // -2 : Outside Base 64 alphabet.
+ // -1 : '\r' or '\n'
+ // 0 : = (Padding character).
+ // >0 : Base 64 alphabet index of given byte.
+ static const List<int> _decodeTable = const [
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -1, -2, -2, //
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, 62, -2, 63, //
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, 00, -2, -2, //
+ -2, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, //
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, 63, //
+ -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2, //
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
+ ];
+
+ static Random _rng = new Random.secure();
+
+ static Uint8List getRandomBytes(int count) {
+ final Uint8List result = new Uint8List(count);
+ for (int i = 0; i < count; i++) {
+ result[i] = _rng.nextInt(0xff);
+ }
+ return result;
+ }
+
+ static String bytesToHex(List<int> bytes) {
+ var result = new StringBuffer();
+ for (var part in bytes) {
+ result.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}');
+ }
+ return result.toString();
+ }
+
+ static String bytesToBase64(List<int> bytes,
+ [bool urlSafe = false, bool addLineSeparator = false]) {
+ int len = bytes.length;
+ if (len == 0) {
+ return "";
+ }
+ final String lookup = urlSafe ? _encodeTableUrlSafe : _encodeTable;
+ // Size of 24 bit chunks.
+ final int remainderLength = len.remainder(3);
+ final int chunkLength = len - remainderLength;
+ // Size of base output.
+ int outputLen = ((len ~/ 3) * 4) + ((remainderLength > 0) ? 4 : 0);
+ // Add extra for line separators.
+ if (addLineSeparator) {
+ outputLen += ((outputLen - 1) ~/ LINE_LENGTH) << 1;
+ }
+ List<int> out = new List<int>(outputLen);
+
+ // Encode 24 bit chunks.
+ int j = 0, i = 0, c = 0;
+ while (i < chunkLength) {
+ int x = ((bytes[i++] << 16) & 0xFFFFFF) |
+ ((bytes[i++] << 8) & 0xFFFFFF) |
+ bytes[i++];
+ out[j++] = lookup.codeUnitAt(x >> 18);
+ out[j++] = lookup.codeUnitAt((x >> 12) & 0x3F);
+ out[j++] = lookup.codeUnitAt((x >> 6) & 0x3F);
+ out[j++] = lookup.codeUnitAt(x & 0x3f);
+ // Add optional line separator for each 76 char output.
+ if (addLineSeparator && ++c == 19 && j < outputLen - 2) {
+ out[j++] = CR;
+ out[j++] = LF;
+ c = 0;
+ }
+ }
+
+ // If input length if not a multiple of 3, encode remaining bytes and
+ // add padding.
+ if (remainderLength == 1) {
+ int x = bytes[i];
+ out[j++] = lookup.codeUnitAt(x >> 2);
+ out[j++] = lookup.codeUnitAt((x << 4) & 0x3F);
+ out[j++] = PAD;
+ out[j++] = PAD;
+ } else if (remainderLength == 2) {
+ int x = bytes[i];
+ int y = bytes[i + 1];
+ out[j++] = lookup.codeUnitAt(x >> 2);
+ out[j++] = lookup.codeUnitAt(((x << 4) | (y >> 4)) & 0x3F);
+ out[j++] = lookup.codeUnitAt((y << 2) & 0x3F);
+ out[j++] = PAD;
+ }
+
+ return new String.fromCharCodes(out);
+ }
+
+ static List<int> base64StringToBytes(String input,
+ [bool ignoreInvalidCharacters = true]) {
+ int len = input.length;
+ if (len == 0) {
+ return new List<int>(0);
+ }
+
+ // Count '\r', '\n' and illegal characters, For illegal characters,
+ // if [ignoreInvalidCharacters] is false, throw an exception.
+ int extrasLen = 0;
+ for (int i = 0; i < len; i++) {
+ int c = _decodeTable[input.codeUnitAt(i)];
+ if (c < 0) {
+ extrasLen++;
+ if (c == -2 && !ignoreInvalidCharacters) {
+ throw new FormatException('Invalid character: ${input[i]}');
+ }
+ }
+ }
+
+ if ((len - extrasLen) % 4 != 0) {
+ throw new FormatException('''Size of Base 64 characters in Input
+ must be a multiple of 4. Input: $input''');
+ }
+
+ // Count pad characters, ignore illegal characters at the end.
+ int padLength = 0;
+ for (int i = len - 1; i >= 0; i--) {
+ int currentCodeUnit = input.codeUnitAt(i);
+ if (_decodeTable[currentCodeUnit] > 0) break;
+ if (currentCodeUnit == PAD) padLength++;
+ }
+ int outputLen = (((len - extrasLen) * 6) >> 3) - padLength;
+ List<int> out = new List<int>(outputLen);
+
+ for (int i = 0, o = 0; o < outputLen;) {
+ // Accumulate 4 valid 6 bit Base 64 characters into an int.
+ int x = 0;
+ for (int j = 4; j > 0;) {
+ int c = _decodeTable[input.codeUnitAt(i++)];
+ if (c >= 0) {
+ x = ((x << 6) & 0xFFFFFF) | c;
+ j--;
+ }
+ }
+ out[o++] = x >> 16;
+ if (o < outputLen) {
+ out[o++] = (x >> 8) & 0xFF;
+ if (o < outputLen) out[o++] = x & 0xFF;
+ }
+ }
+ return out;
+ }
+}
+
+// Constants.
+const _MASK_8 = 0xff;
+const _MASK_32 = 0xffffffff;
+const _BITS_PER_BYTE = 8;
+const _BYTES_PER_WORD = 4;
+
+// Base class encapsulating common behavior for cryptographic hash
+// functions.
+abstract class _HashBase {
+ // Hasher state.
+ final int _chunkSizeInWords;
+ final int _digestSizeInWords;
+ final bool _bigEndianWords;
+ int _lengthInBytes = 0;
+ List<int> _pendingData;
+ List<int> _currentChunk;
+ List<int> _h;
+ bool _digestCalled = false;
+
+ _HashBase(
+ this._chunkSizeInWords, this._digestSizeInWords, this._bigEndianWords)
+ : _pendingData = [] {
+ _currentChunk = new List(_chunkSizeInWords);
+ _h = new List(_digestSizeInWords);
+ }
+
+ // Update the hasher with more data.
+ add(List<int> data) {
+ if (_digestCalled) {
+ throw new StateError(
+ 'Hash update method called after digest was retrieved');
+ }
+ _lengthInBytes += data.length;
+ _pendingData.addAll(data);
+ _iterate();
+ }
+
+ // Finish the hash computation and return the digest string.
+ List<int> close() {
+ if (_digestCalled) {
+ return _resultAsBytes();
+ }
+ _digestCalled = true;
+ _finalizeData();
+ _iterate();
+ assert(_pendingData.length == 0);
+ return _resultAsBytes();
+ }
+
+ // Returns the block size of the hash in bytes.
+ int get blockSize {
+ return _chunkSizeInWords * _BYTES_PER_WORD;
+ }
+
+ // Create a fresh instance of this Hash.
+ newInstance();
+
+ // One round of the hash computation.
+ _updateHash(List<int> m);
+
+ // Helper methods.
+ _add32(x, y) => (x + y) & _MASK_32;
+ _roundUp(val, n) => (val + n - 1) & -n;
+
+ // Rotate left limiting to unsigned 32-bit values.
+ int _rotl32(int val, int shift) {
+ var mod_shift = shift & 31;
+ return ((val << mod_shift) & _MASK_32) |
+ ((val & _MASK_32) >> (32 - mod_shift));
+ }
+
+ // Compute the final result as a list of bytes from the hash words.
+ List<int> _resultAsBytes() {
+ var result = <int>[];
+ for (var i = 0; i < _h.length; i++) {
+ result.addAll(_wordToBytes(_h[i]));
+ }
+ return result;
+ }
+
+ // Converts a list of bytes to a chunk of 32-bit words.
+ _bytesToChunk(List<int> data, int dataIndex) {
+ assert((data.length - dataIndex) >= (_chunkSizeInWords * _BYTES_PER_WORD));
+
+ for (var wordIndex = 0; wordIndex < _chunkSizeInWords; wordIndex++) {
+ var w3 = _bigEndianWords ? data[dataIndex] : data[dataIndex + 3];
+ var w2 = _bigEndianWords ? data[dataIndex + 1] : data[dataIndex + 2];
+ var w1 = _bigEndianWords ? data[dataIndex + 2] : data[dataIndex + 1];
+ var w0 = _bigEndianWords ? data[dataIndex + 3] : data[dataIndex];
+ dataIndex += 4;
+ var word = (w3 & 0xff) << 24;
+ word |= (w2 & _MASK_8) << 16;
+ word |= (w1 & _MASK_8) << 8;
+ word |= (w0 & _MASK_8);
+ _currentChunk[wordIndex] = word;
+ }
+ }
+
+ // Convert a 32-bit word to four bytes.
+ List<int> _wordToBytes(int word) {
+ List<int> bytes = new List(_BYTES_PER_WORD);
+ bytes[0] = (word >> (_bigEndianWords ? 24 : 0)) & _MASK_8;
+ bytes[1] = (word >> (_bigEndianWords ? 16 : 8)) & _MASK_8;
+ bytes[2] = (word >> (_bigEndianWords ? 8 : 16)) & _MASK_8;
+ bytes[3] = (word >> (_bigEndianWords ? 0 : 24)) & _MASK_8;
+ return bytes;
+ }
+
+ // Iterate through data updating the hash computation for each
+ // chunk.
+ _iterate() {
+ var len = _pendingData.length;
+ var chunkSizeInBytes = _chunkSizeInWords * _BYTES_PER_WORD;
+ if (len >= chunkSizeInBytes) {
+ var index = 0;
+ for (; (len - index) >= chunkSizeInBytes; index += chunkSizeInBytes) {
+ _bytesToChunk(_pendingData, index);
+ _updateHash(_currentChunk);
+ }
+ _pendingData = _pendingData.sublist(index, len);
+ }
+ }
+
+ // Finalize the data. Add a 1 bit to the end of the message. Expand with
+ // 0 bits and add the length of the message.
+ _finalizeData() {
+ _pendingData.add(0x80);
+ var contentsLength = _lengthInBytes + 9;
+ var chunkSizeInBytes = _chunkSizeInWords * _BYTES_PER_WORD;
+ var finalizedLength = _roundUp(contentsLength, chunkSizeInBytes);
+ var zeroPadding = finalizedLength - contentsLength;
+ for (var i = 0; i < zeroPadding; i++) {
+ _pendingData.add(0);
+ }
+ var lengthInBits = _lengthInBytes * _BITS_PER_BYTE;
+ assert(lengthInBits < pow(2, 32));
+ if (_bigEndianWords) {
+ _pendingData.addAll(_wordToBytes(0));
+ _pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32));
+ } else {
+ _pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32));
+ _pendingData.addAll(_wordToBytes(0));
+ }
+ }
+}
+
+// The MD5 hasher is used to compute an MD5 message digest.
+class _MD5 extends _HashBase {
+ _MD5() : super(16, 4, false) {
+ _h[0] = 0x67452301;
+ _h[1] = 0xefcdab89;
+ _h[2] = 0x98badcfe;
+ _h[3] = 0x10325476;
+ }
+
+ // Returns a new instance of this Hash.
+ _MD5 newInstance() {
+ return new _MD5();
+ }
+
+ static const _k = const [
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, //
+ 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, //
+ 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, //
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, //
+ 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, //
+ 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, //
+ 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+ ];
+
+ static const _r = const [
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, //
+ 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, //
+ 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, //
+ 10, 15, 21, 6, 10, 15, 21
+ ];
+
+ // Compute one iteration of the MD5 algorithm with a chunk of
+ // 16 32-bit pieces.
+ void _updateHash(List<int> m) {
+ assert(m.length == 16);
+
+ var a = _h[0];
+ var b = _h[1];
+ var c = _h[2];
+ var d = _h[3];
+
+ var t0;
+ var t1;
+
+ for (var i = 0; i < 64; i++) {
+ if (i < 16) {
+ t0 = (b & c) | ((~b & _MASK_32) & d);
+ t1 = i;
+ } else if (i < 32) {
+ t0 = (d & b) | ((~d & _MASK_32) & c);
+ t1 = ((5 * i) + 1) % 16;
+ } else if (i < 48) {
+ t0 = b ^ c ^ d;
+ t1 = ((3 * i) + 5) % 16;
+ } else {
+ t0 = c ^ (b | (~d & _MASK_32));
+ t1 = (7 * i) % 16;
+ }
+
+ var temp = d;
+ d = c;
+ c = b;
+ b = _add32(
+ b, _rotl32(_add32(_add32(a, t0), _add32(_k[i], m[t1])), _r[i]));
+ a = temp;
+ }
+
+ _h[0] = _add32(a, _h[0]);
+ _h[1] = _add32(b, _h[1]);
+ _h[2] = _add32(c, _h[2]);
+ _h[3] = _add32(d, _h[3]);
+ }
+}
+
+// The SHA1 hasher is used to compute an SHA1 message digest.
+class _SHA1 extends _HashBase {
+ // Construct a SHA1 hasher object.
+ _SHA1()
+ : _w = new List(80),
+ super(16, 5, true) {
+ _h[0] = 0x67452301;
+ _h[1] = 0xEFCDAB89;
+ _h[2] = 0x98BADCFE;
+ _h[3] = 0x10325476;
+ _h[4] = 0xC3D2E1F0;
+ }
+
+ // Returns a new instance of this Hash.
+ _SHA1 newInstance() {
+ return new _SHA1();
+ }
+
+ // Compute one iteration of the SHA1 algorithm with a chunk of
+ // 16 32-bit pieces.
+ void _updateHash(List<int> m) {
+ assert(m.length == 16);
+
+ var a = _h[0];
+ var b = _h[1];
+ var c = _h[2];
+ var d = _h[3];
+ var e = _h[4];
+
+ for (var i = 0; i < 80; i++) {
+ if (i < 16) {
+ _w[i] = m[i];
+ } else {
+ var n = _w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16];
+ _w[i] = _rotl32(n, 1);
+ }
+ var t = _add32(_add32(_rotl32(a, 5), e), _w[i]);
+ if (i < 20) {
+ t = _add32(_add32(t, (b & c) | (~b & d)), 0x5A827999);
+ } else if (i < 40) {
+ t = _add32(_add32(t, (b ^ c ^ d)), 0x6ED9EBA1);
+ } else if (i < 60) {
+ t = _add32(_add32(t, (b & c) | (b & d) | (c & d)), 0x8F1BBCDC);
+ } else {
+ t = _add32(_add32(t, b ^ c ^ d), 0xCA62C1D6);
+ }
+
+ e = d;
+ d = c;
+ c = _rotl32(b, 30);
+ b = a;
+ a = t & _MASK_32;
+ }
+
+ _h[0] = _add32(a, _h[0]);
+ _h[1] = _add32(b, _h[1]);
+ _h[2] = _add32(c, _h[2]);
+ _h[3] = _add32(d, _h[3]);
+ _h[4] = _add32(e, _h[4]);
+ }
+
+ List<int> _w;
+}
diff --git a/sdk_nnbd/lib/_http/http.dart b/sdk_nnbd/lib/_http/http.dart
new file mode 100644
index 0000000..2fc751f
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http.dart
@@ -0,0 +1,2196 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._http;
+
+import 'dart:async';
+import 'dart:collection'
+ show
+ HashMap,
+ HashSet,
+ Queue,
+ ListQueue,
+ LinkedList,
+ LinkedListEntry,
+ UnmodifiableMapView;
+import 'dart:convert';
+import 'dart:developer' hide log;
+import 'dart:_internal' show Since, HttpStatus;
+import 'dart:math';
+import 'dart:io';
+import 'dart:typed_data';
+
+part 'crypto.dart';
+part 'http_date.dart';
+part 'http_headers.dart';
+part 'http_impl.dart';
+part 'http_parser.dart';
+part 'http_session.dart';
+part 'overrides.dart';
+part 'websocket.dart';
+part 'websocket_impl.dart';
+
+/**
+ * A server that delivers content, such as web pages, using the HTTP protocol.
+ *
+ * The HttpServer is a [Stream] that provides [HttpRequest] objects. Each
+ * HttpRequest has an associated [HttpResponse] object.
+ * The server responds to a request by writing to that HttpResponse object.
+ * The following example shows how to bind an HttpServer to an IPv6
+ * [InternetAddress] on port 80 (the standard port for HTTP servers)
+ * and how to listen for requests.
+ * Port 80 is the default HTTP port. However, on most systems accessing
+ * this requires super-user privileges. For local testing consider
+ * using a non-reserved port (1024 and above).
+ *
+ * import 'dart:io';
+ *
+ * main() {
+ * HttpServer
+ * .bind(InternetAddress.anyIPv6, 80)
+ * .then((server) {
+ * server.listen((HttpRequest request) {
+ * request.response.write('Hello, world!');
+ * request.response.close();
+ * });
+ * });
+ * }
+ *
+ * Incomplete requests, in which all or part of the header is missing, are
+ * ignored, and no exceptions or HttpRequest objects are generated for them.
+ * Likewise, when writing to an HttpResponse, any [Socket] exceptions are
+ * ignored and any future writes are ignored.
+ *
+ * The HttpRequest exposes the request headers and provides the request body,
+ * if it exists, as a Stream of data. If the body is unread, it is drained
+ * when the server writes to the HttpResponse or closes it.
+ *
+ * ## Bind with a secure HTTPS connection
+ *
+ * Use [bindSecure] to create an HTTPS server.
+ *
+ * The server presents a certificate to the client. The certificate
+ * chain and the private key are set in the [SecurityContext]
+ * object that is passed to [bindSecure].
+ *
+ * import 'dart:io';
+ * import "dart:isolate";
+ *
+ * main() {
+ * SecurityContext context = new SecurityContext();
+ * var chain =
+ * Platform.script.resolve('certificates/server_chain.pem')
+ * .toFilePath();
+ * var key =
+ * Platform.script.resolve('certificates/server_key.pem')
+ * .toFilePath();
+ * context.useCertificateChain(chain);
+ * context.usePrivateKey(key, password: 'dartdart');
+ *
+ * HttpServer
+ * .bindSecure(InternetAddress.anyIPv6,
+ * 443,
+ * context)
+ * .then((server) {
+ * server.listen((HttpRequest request) {
+ * request.response.write('Hello, world!');
+ * request.response.close();
+ * });
+ * });
+ * }
+ *
+ * The certificates and keys are PEM files, which can be created and
+ * managed with the tools in OpenSSL.
+ *
+ * ## Connect to a server socket
+ *
+ * You can use the [listenOn] constructor to attach an HTTP server to
+ * a [ServerSocket].
+ *
+ * import 'dart:io';
+ *
+ * main() {
+ * ServerSocket.bind(InternetAddress.anyIPv6, 80)
+ * .then((serverSocket) {
+ * HttpServer httpserver = new HttpServer.listenOn(serverSocket);
+ * serverSocket.listen((Socket socket) {
+ * socket.write('Hello, client.');
+ * });
+ * });
+ * }
+ *
+ * ## Other resources
+ *
+ * * HttpServer is a Stream. Refer to the [Stream] class for information
+ * about the streaming qualities of an HttpServer.
+ * Pausing the subscription of the stream, pauses at the OS level.
+ *
+ * * The [shelf](https://pub.dartlang.org/packages/shelf)
+ * package on pub.dartlang.org contains a set of high-level classes that,
+ * together with this class, makes it easy to provide content through HTTP
+ * servers.
+ */
+abstract class HttpServer implements Stream<HttpRequest> {
+ /**
+ * Gets and sets the default value of the `Server` header for all responses
+ * generated by this [HttpServer].
+ *
+ * If [serverHeader] is `null`, no `Server` header will be added to each
+ * response.
+ *
+ * The default value is `null`.
+ */
+ String serverHeader;
+
+ /**
+ * Default set of headers added to all response objects.
+ *
+ * By default the following headers are in this set:
+ *
+ * Content-Type: text/plain; charset=utf-8
+ * X-Frame-Options: SAMEORIGIN
+ * X-Content-Type-Options: nosniff
+ * X-XSS-Protection: 1; mode=block
+ *
+ * If the `Server` header is added here and the `serverHeader` is set as
+ * well then the value of `serverHeader` takes precedence.
+ */
+ HttpHeaders get defaultResponseHeaders;
+
+ /**
+ * Whether the [HttpServer] should compress the content, if possible.
+ *
+ * The content can only be compressed when the response is using
+ * chunked Transfer-Encoding and the incoming request has `gzip`
+ * as an accepted encoding in the Accept-Encoding header.
+ *
+ * The default value is `false` (compression disabled).
+ * To enable, set `autoCompress` to `true`.
+ */
+ bool autoCompress;
+
+ /**
+ * Gets or sets the timeout used for idle keep-alive connections. If no
+ * further request is seen within [idleTimeout] after the previous request was
+ * completed, the connection is dropped.
+ *
+ * Default is 120 seconds.
+ *
+ * Note that it may take up to `2 * idleTimeout` before a idle connection is
+ * aborted.
+ *
+ * To disable, set [idleTimeout] to `null`.
+ */
+ Duration idleTimeout;
+
+ /**
+ * Starts listening for HTTP requests on the specified [address] and
+ * [port].
+ *
+ * The [address] can either be a [String] or an
+ * [InternetAddress]. If [address] is a [String], [bind] will
+ * perform a [InternetAddress.lookup] and use the first value in the
+ * list. To listen on the loopback adapter, which will allow only
+ * incoming connections from the local host, use the value
+ * [InternetAddress.loopbackIPv4] or
+ * [InternetAddress.loopbackIPv6]. To allow for incoming
+ * connection from the network use either one of the values
+ * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+ * bind to all interfaces or the IP address of a specific interface.
+ *
+ * If an IP version 6 (IPv6) address is used, both IP version 6
+ * (IPv6) and version 4 (IPv4) connections will be accepted. To
+ * restrict this to version 6 (IPv6) only, use [v6Only] to set
+ * version 6 only. However, if the address is
+ * [InternetAddress.loopbackIPv6], only IP version 6 (IPv6) connections
+ * will be accepted.
+ *
+ * If [port] has the value [:0:] an ephemeral port will be chosen by
+ * the system. The actual port used can be retrieved using the
+ * [port] getter.
+ *
+ * The optional argument [backlog] can be used to specify the listen
+ * backlog for the underlying OS listen setup. If [backlog] has the
+ * value of [:0:] (the default) a reasonable value will be chosen by
+ * the system.
+ *
+ * The optional argument [shared] specifies whether additional HttpServer
+ * objects can bind to the same combination of `address`, `port` and `v6Only`.
+ * If `shared` is `true` and more `HttpServer`s from this isolate or other
+ * isolates are bound to the port, then the incoming connections will be
+ * distributed among all the bound `HttpServer`s. Connections can be
+ * distributed over multiple isolates this way.
+ */
+ static Future<HttpServer> bind(address, int port,
+ {int backlog: 0, bool v6Only: false, bool shared: false}) =>
+ _HttpServer.bind(address, port, backlog, v6Only, shared);
+
+ /**
+ * The [address] can either be a [String] or an
+ * [InternetAddress]. If [address] is a [String], [bind] will
+ * perform a [InternetAddress.lookup] and use the first value in the
+ * list. To listen on the loopback adapter, which will allow only
+ * incoming connections from the local host, use the value
+ * [InternetAddress.loopbackIPv4] or
+ * [InternetAddress.loopbackIPv6]. To allow for incoming
+ * connection from the network use either one of the values
+ * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+ * bind to all interfaces or the IP address of a specific interface.
+ *
+ * If an IP version 6 (IPv6) address is used, both IP version 6
+ * (IPv6) and version 4 (IPv4) connections will be accepted. To
+ * restrict this to version 6 (IPv6) only, use [v6Only] to set
+ * version 6 only.
+ *
+ * If [port] has the value [:0:] an ephemeral port will be chosen by
+ * the system. The actual port used can be retrieved using the
+ * [port] getter.
+ *
+ * The optional argument [backlog] can be used to specify the listen
+ * backlog for the underlying OS listen setup. If [backlog] has the
+ * value of [:0:] (the default) a reasonable value will be chosen by
+ * the system.
+ *
+ * If [requestClientCertificate] is true, the server will
+ * request clients to authenticate with a client certificate.
+ * The server will advertise the names of trusted issuers of client
+ * certificates, getting them from a [SecurityContext], where they have been
+ * set using [SecurityContext.setClientAuthorities].
+ *
+ * The optional argument [shared] specifies whether additional HttpServer
+ * objects can bind to the same combination of `address`, `port` and `v6Only`.
+ * If `shared` is `true` and more `HttpServer`s from this isolate or other
+ * isolates are bound to the port, then the incoming connections will be
+ * distributed among all the bound `HttpServer`s. Connections can be
+ * distributed over multiple isolates this way.
+ */
+
+ static Future<HttpServer> bindSecure(
+ address, int port, SecurityContext context,
+ {int backlog: 0,
+ bool v6Only: false,
+ bool requestClientCertificate: false,
+ bool shared: false}) =>
+ _HttpServer.bindSecure(address, port, context, backlog, v6Only,
+ requestClientCertificate, shared);
+
+ /**
+ * Attaches the HTTP server to an existing [ServerSocket]. When the
+ * [HttpServer] is closed, the [HttpServer] will just detach itself,
+ * closing current connections but not closing [serverSocket].
+ */
+ factory HttpServer.listenOn(ServerSocket serverSocket) =>
+ new _HttpServer.listenOn(serverSocket);
+
+ /**
+ * Permanently stops this [HttpServer] from listening for new
+ * connections. This closes the [Stream] of [HttpRequest]s with a
+ * done event. The returned future completes when the server is
+ * stopped. For a server started using [bind] or [bindSecure] this
+ * means that the port listened on no longer in use.
+ *
+ * If [force] is `true`, active connections will be closed immediately.
+ */
+ Future close({bool force: false});
+
+ /**
+ * Returns the port that the server is listening on. This can be
+ * used to get the actual port used when a value of 0 for [:port:] is
+ * specified in the [bind] or [bindSecure] call.
+ */
+ int get port;
+
+ /**
+ * Returns the address that the server is listening on. This can be
+ * used to get the actual address used, when the address is fetched by
+ * a lookup from a hostname.
+ */
+ InternetAddress get address;
+
+ /**
+ * Sets the timeout, in seconds, for sessions of this [HttpServer].
+ * The default timeout is 20 minutes.
+ */
+ set sessionTimeout(int timeout);
+
+ /**
+ * Returns an [HttpConnectionsInfo] object summarizing the number of
+ * current connections handled by the server.
+ */
+ HttpConnectionsInfo connectionsInfo();
+}
+
+/**
+ * Summary statistics about an [HttpServer]s current socket connections.
+ */
+class HttpConnectionsInfo {
+ /**
+ * Total number of socket connections.
+ */
+ int total = 0;
+
+ /**
+ * Number of active connections where actual request/response
+ * processing is active.
+ */
+ int active = 0;
+
+ /**
+ * Number of idle connections held by clients as persistent connections.
+ */
+ int idle = 0;
+
+ /**
+ * Number of connections which are preparing to close. Note: These
+ * connections are also part of the [:active:] count as they might
+ * still be sending data to the client before finally closing.
+ */
+ int closing = 0;
+}
+
+/**
+ * Headers for HTTP requests and responses.
+ *
+ * In some situations, headers are immutable:
+ *
+ * * HttpRequest and HttpClientResponse always have immutable headers.
+ *
+ * * HttpResponse and HttpClientRequest have immutable headers
+ * from the moment the body is written to.
+ *
+ * In these situations, the mutating methods throw exceptions.
+ *
+ * For all operations on HTTP headers the header name is
+ * case-insensitive.
+ *
+ * To set the value of a header use the `set()` method:
+ *
+ * request.headers.set(HttpHeaders.cacheControlHeader,
+ * 'max-age=3600, must-revalidate');
+ *
+ * To retrieve the value of a header use the `value()` method:
+ *
+ * print(request.headers.value(HttpHeaders.userAgentHeader));
+ *
+ * An HttpHeaders object holds a list of values for each name
+ * as the standard allows. In most cases a name holds only a single value,
+ * The most common mode of operation is to use `set()` for setting a value,
+ * and `value()` for retrieving a value.
+ */
+abstract class HttpHeaders {
+ static const acceptHeader = "accept";
+ static const acceptCharsetHeader = "accept-charset";
+ static const acceptEncodingHeader = "accept-encoding";
+ static const acceptLanguageHeader = "accept-language";
+ static const acceptRangesHeader = "accept-ranges";
+ static const ageHeader = "age";
+ static const allowHeader = "allow";
+ static const authorizationHeader = "authorization";
+ static const cacheControlHeader = "cache-control";
+ static const connectionHeader = "connection";
+ static const contentEncodingHeader = "content-encoding";
+ static const contentLanguageHeader = "content-language";
+ static const contentLengthHeader = "content-length";
+ static const contentLocationHeader = "content-location";
+ static const contentMD5Header = "content-md5";
+ static const contentRangeHeader = "content-range";
+ static const contentTypeHeader = "content-type";
+ static const dateHeader = "date";
+ static const etagHeader = "etag";
+ static const expectHeader = "expect";
+ static const expiresHeader = "expires";
+ static const fromHeader = "from";
+ static const hostHeader = "host";
+ static const ifMatchHeader = "if-match";
+ static const ifModifiedSinceHeader = "if-modified-since";
+ static const ifNoneMatchHeader = "if-none-match";
+ static const ifRangeHeader = "if-range";
+ static const ifUnmodifiedSinceHeader = "if-unmodified-since";
+ static const lastModifiedHeader = "last-modified";
+ static const locationHeader = "location";
+ static const maxForwardsHeader = "max-forwards";
+ static const pragmaHeader = "pragma";
+ static const proxyAuthenticateHeader = "proxy-authenticate";
+ static const proxyAuthorizationHeader = "proxy-authorization";
+ static const rangeHeader = "range";
+ static const refererHeader = "referer";
+ static const retryAfterHeader = "retry-after";
+ static const serverHeader = "server";
+ static const teHeader = "te";
+ static const trailerHeader = "trailer";
+ static const transferEncodingHeader = "transfer-encoding";
+ static const upgradeHeader = "upgrade";
+ static const userAgentHeader = "user-agent";
+ static const varyHeader = "vary";
+ static const viaHeader = "via";
+ static const warningHeader = "warning";
+ static const wwwAuthenticateHeader = "www-authenticate";
+
+ @Deprecated("Use acceptHeader instead")
+ static const ACCEPT = acceptHeader;
+ @Deprecated("Use acceptCharsetHeader instead")
+ static const ACCEPT_CHARSET = acceptCharsetHeader;
+ @Deprecated("Use acceptEncodingHeader instead")
+ static const ACCEPT_ENCODING = acceptEncodingHeader;
+ @Deprecated("Use acceptLanguageHeader instead")
+ static const ACCEPT_LANGUAGE = acceptLanguageHeader;
+ @Deprecated("Use acceptRangesHeader instead")
+ static const ACCEPT_RANGES = acceptRangesHeader;
+ @Deprecated("Use ageHeader instead")
+ static const AGE = ageHeader;
+ @Deprecated("Use allowHeader instead")
+ static const ALLOW = allowHeader;
+ @Deprecated("Use authorizationHeader instead")
+ static const AUTHORIZATION = authorizationHeader;
+ @Deprecated("Use cacheControlHeader instead")
+ static const CACHE_CONTROL = cacheControlHeader;
+ @Deprecated("Use connectionHeader instead")
+ static const CONNECTION = connectionHeader;
+ @Deprecated("Use contentEncodingHeader instead")
+ static const CONTENT_ENCODING = contentEncodingHeader;
+ @Deprecated("Use contentLanguageHeader instead")
+ static const CONTENT_LANGUAGE = contentLanguageHeader;
+ @Deprecated("Use contentLengthHeader instead")
+ static const CONTENT_LENGTH = contentLengthHeader;
+ @Deprecated("Use contentLocationHeader instead")
+ static const CONTENT_LOCATION = contentLocationHeader;
+ @Deprecated("Use contentMD5Header instead")
+ static const CONTENT_MD5 = contentMD5Header;
+ @Deprecated("Use contentRangeHeader instead")
+ static const CONTENT_RANGE = contentRangeHeader;
+ @Deprecated("Use contentTypeHeader instead")
+ static const CONTENT_TYPE = contentTypeHeader;
+ @Deprecated("Use dateHeader instead")
+ static const DATE = dateHeader;
+ @Deprecated("Use etagHeader instead")
+ static const ETAG = etagHeader;
+ @Deprecated("Use expectHeader instead")
+ static const EXPECT = expectHeader;
+ @Deprecated("Use expiresHeader instead")
+ static const EXPIRES = expiresHeader;
+ @Deprecated("Use fromHeader instead")
+ static const FROM = fromHeader;
+ @Deprecated("Use hostHeader instead")
+ static const HOST = hostHeader;
+ @Deprecated("Use ifMatchHeader instead")
+ static const IF_MATCH = ifMatchHeader;
+ @Deprecated("Use ifModifiedSinceHeader instead")
+ static const IF_MODIFIED_SINCE = ifModifiedSinceHeader;
+ @Deprecated("Use ifNoneMatchHeader instead")
+ static const IF_NONE_MATCH = ifNoneMatchHeader;
+ @Deprecated("Use ifRangeHeader instead")
+ static const IF_RANGE = ifRangeHeader;
+ @Deprecated("Use ifUnmodifiedSinceHeader instead")
+ static const IF_UNMODIFIED_SINCE = ifUnmodifiedSinceHeader;
+ @Deprecated("Use lastModifiedHeader instead")
+ static const LAST_MODIFIED = lastModifiedHeader;
+ @Deprecated("Use locationHeader instead")
+ static const LOCATION = locationHeader;
+ @Deprecated("Use maxForwardsHeader instead")
+ static const MAX_FORWARDS = maxForwardsHeader;
+ @Deprecated("Use pragmaHeader instead")
+ static const PRAGMA = pragmaHeader;
+ @Deprecated("Use proxyAuthenticateHeader instead")
+ static const PROXY_AUTHENTICATE = proxyAuthenticateHeader;
+ @Deprecated("Use proxyAuthorizationHeader instead")
+ static const PROXY_AUTHORIZATION = proxyAuthorizationHeader;
+ @Deprecated("Use rangeHeader instead")
+ static const RANGE = rangeHeader;
+ @Deprecated("Use refererHeader instead")
+ static const REFERER = refererHeader;
+ @Deprecated("Use retryAfterHeader instead")
+ static const RETRY_AFTER = retryAfterHeader;
+ @Deprecated("Use serverHeader instead")
+ static const SERVER = serverHeader;
+ @Deprecated("Use teHeader instead")
+ static const TE = teHeader;
+ @Deprecated("Use trailerHeader instead")
+ static const TRAILER = trailerHeader;
+ @Deprecated("Use transferEncodingHeader instead")
+ static const TRANSFER_ENCODING = transferEncodingHeader;
+ @Deprecated("Use upgradeHeader instead")
+ static const UPGRADE = upgradeHeader;
+ @Deprecated("Use userAgentHeader instead")
+ static const USER_AGENT = userAgentHeader;
+ @Deprecated("Use varyHeader instead")
+ static const VARY = varyHeader;
+ @Deprecated("Use viaHeader instead")
+ static const VIA = viaHeader;
+ @Deprecated("Use warningHeader instead")
+ static const WARNING = warningHeader;
+ @Deprecated("Use wwwAuthenticateHeader instead")
+ static const WWW_AUTHENTICATE = wwwAuthenticateHeader;
+
+ // Cookie headers from RFC 6265.
+ static const cookieHeader = "cookie";
+ static const setCookieHeader = "set-cookie";
+
+ @Deprecated("Use cookieHeader instead")
+ static const COOKIE = cookieHeader;
+ @Deprecated("Use setCookieHeader instead")
+ static const SET_COOKIE = setCookieHeader;
+
+ static const generalHeaders = const [
+ cacheControlHeader,
+ connectionHeader,
+ dateHeader,
+ pragmaHeader,
+ trailerHeader,
+ transferEncodingHeader,
+ upgradeHeader,
+ viaHeader,
+ warningHeader
+ ];
+
+ @Deprecated("Use generalHeaders instead")
+ static const GENERAL_HEADERS = generalHeaders;
+
+ static const entityHeaders = const [
+ allowHeader,
+ contentEncodingHeader,
+ contentLanguageHeader,
+ contentLengthHeader,
+ contentLocationHeader,
+ contentMD5Header,
+ contentRangeHeader,
+ contentTypeHeader,
+ expiresHeader,
+ lastModifiedHeader
+ ];
+
+ @Deprecated("Use entityHeaders instead")
+ static const ENTITY_HEADERS = entityHeaders;
+
+ static const responseHeaders = const [
+ acceptRangesHeader,
+ ageHeader,
+ etagHeader,
+ locationHeader,
+ proxyAuthenticateHeader,
+ retryAfterHeader,
+ serverHeader,
+ varyHeader,
+ wwwAuthenticateHeader
+ ];
+
+ @Deprecated("Use responseHeaders instead")
+ static const RESPONSE_HEADERS = responseHeaders;
+
+ static const requestHeaders = const [
+ acceptHeader,
+ acceptCharsetHeader,
+ acceptEncodingHeader,
+ acceptLanguageHeader,
+ authorizationHeader,
+ expectHeader,
+ fromHeader,
+ hostHeader,
+ ifMatchHeader,
+ ifModifiedSinceHeader,
+ ifNoneMatchHeader,
+ ifRangeHeader,
+ ifUnmodifiedSinceHeader,
+ maxForwardsHeader,
+ proxyAuthorizationHeader,
+ rangeHeader,
+ refererHeader,
+ teHeader,
+ userAgentHeader
+ ];
+
+ @Deprecated("Use requestHeaders instead")
+ static const REQUEST_HEADERS = requestHeaders;
+
+ /**
+ * Gets and sets the date. The value of this property will
+ * reflect the 'date' header.
+ */
+ DateTime date;
+
+ /**
+ * Gets and sets the expiry date. The value of this property will
+ * reflect the 'expires' header.
+ */
+ DateTime expires;
+
+ /**
+ * Gets and sets the "if-modified-since" date. The value of this property will
+ * reflect the "if-modified-since" header.
+ */
+ DateTime ifModifiedSince;
+
+ /**
+ * Gets and sets the host part of the 'host' header for the
+ * connection.
+ */
+ String host;
+
+ /**
+ * Gets and sets the port part of the 'host' header for the
+ * connection.
+ */
+ int port;
+
+ /**
+ * Gets and sets the content type. Note that the content type in the
+ * header will only be updated if this field is set
+ * directly. Mutating the returned current value will have no
+ * effect.
+ */
+ ContentType contentType;
+
+ /**
+ * Gets and sets the content length header value.
+ */
+ int contentLength;
+
+ /**
+ * Gets and sets the persistent connection header value.
+ */
+ bool persistentConnection;
+
+ /**
+ * Gets and sets the chunked transfer encoding header value.
+ */
+ bool chunkedTransferEncoding;
+
+ /**
+ * Returns the list of values for the header named [name]. If there
+ * is no header with the provided name, [:null:] will be returned.
+ */
+ List<String> operator [](String name);
+
+ /**
+ * Convenience method for the value for a single valued header. If
+ * there is no header with the provided name, [:null:] will be
+ * returned. If the header has more than one value an exception is
+ * thrown.
+ */
+ String value(String name);
+
+ /**
+ * Adds a header value. The header named [name] will have the value
+ * [value] added to its list of values. Some headers are single
+ * valued, and for these adding a value will replace the previous
+ * value. If the value is of type DateTime a HTTP date format will be
+ * applied. If the value is a [:List:] each element of the list will
+ * be added separately. For all other types the default [:toString:]
+ * method will be used.
+ */
+ void add(String name, Object value);
+
+ /**
+ * Sets a header. The header named [name] will have all its values
+ * cleared before the value [value] is added as its value.
+ */
+ void set(String name, Object value);
+
+ /**
+ * Removes a specific value for a header name. Some headers have
+ * system supplied values and for these the system supplied values
+ * will still be added to the collection of values for the header.
+ */
+ void remove(String name, Object value);
+
+ /**
+ * Removes all values for the specified header name. Some headers
+ * have system supplied values and for these the system supplied
+ * values will still be added to the collection of values for the
+ * header.
+ */
+ void removeAll(String name);
+
+ /**
+ * Enumerates the headers, applying the function [f] to each
+ * header. The header name passed in [:name:] will be all lower
+ * case.
+ */
+ void forEach(void f(String name, List<String> values));
+
+ /**
+ * Disables folding for the header named [name] when sending the HTTP
+ * header. By default, multiple header values are folded into a
+ * single header line by separating the values with commas. The
+ * 'set-cookie' header has folding disabled by default.
+ */
+ void noFolding(String name);
+
+ /**
+ * Remove all headers. Some headers have system supplied values and
+ * for these the system supplied values will still be added to the
+ * collection of values for the header.
+ */
+ void clear();
+}
+
+/**
+ * Representation of a header value in the form:
+ *
+ * [:value; parameter1=value1; parameter2=value2:]
+ *
+ * [HeaderValue] can be used to conveniently build and parse header
+ * values on this form.
+ *
+ * To build an [:accepts:] header with the value
+ *
+ * text/plain; q=0.3, text/html
+ *
+ * use code like this:
+ *
+ * HttpClientRequest request = ...;
+ * var v = new HeaderValue("text/plain", {"q": "0.3"});
+ * request.headers.add(HttpHeaders.acceptHeader, v);
+ * request.headers.add(HttpHeaders.acceptHeader, "text/html");
+ *
+ * To parse the header values use the [:parse:] static method.
+ *
+ * HttpRequest request = ...;
+ * List<String> values = request.headers[HttpHeaders.acceptHeader];
+ * values.forEach((value) {
+ * HeaderValue v = HeaderValue.parse(value);
+ * // Use v.value and v.parameters
+ * });
+ *
+ * An instance of [HeaderValue] is immutable.
+ */
+abstract class HeaderValue {
+ /**
+ * Creates a new header value object setting the value and parameters.
+ */
+ factory HeaderValue([String value = "", Map<String, String> parameters]) {
+ return new _HeaderValue(value, parameters);
+ }
+
+ /**
+ * Creates a new header value object from parsing a header value
+ * string with both value and optional parameters.
+ */
+ static HeaderValue parse(String value,
+ {String parameterSeparator: ";",
+ String valueSeparator: null,
+ bool preserveBackslash: false}) {
+ return _HeaderValue.parse(value,
+ parameterSeparator: parameterSeparator,
+ valueSeparator: valueSeparator,
+ preserveBackslash: preserveBackslash);
+ }
+
+ /**
+ * Gets the header value.
+ */
+ String get value;
+
+ /**
+ * Gets the map of parameters.
+ *
+ * This map cannot be modified. Invoking any operation which would
+ * modify the map will throw [UnsupportedError].
+ */
+ Map<String, String> get parameters;
+
+ /**
+ * Returns the formatted string representation in the form:
+ *
+ * value; parameter1=value1; parameter2=value2
+ */
+ String toString();
+}
+
+abstract class HttpSession implements Map {
+ /**
+ * Gets the id for the current session.
+ */
+ String get id;
+
+ /**
+ * Destroys the session. This will terminate the session and any further
+ * connections with this id will be given a new id and session.
+ */
+ void destroy();
+
+ /**
+ * Sets a callback that will be called when the session is timed out.
+ */
+ void set onTimeout(void callback());
+
+ /**
+ * Is true if the session has not been sent to the client yet.
+ */
+ bool get isNew;
+}
+
+/**
+ * Representation of a content type. An instance of [ContentType] is
+ * immutable.
+ */
+abstract class ContentType implements HeaderValue {
+ /**
+ * Content type for plain text using UTF-8 encoding.
+ *
+ * text/plain; charset=utf-8
+ */
+ static final text = new ContentType("text", "plain", charset: "utf-8");
+ @Deprecated("Use text instead")
+ static final TEXT = text;
+
+ /**
+ * Content type for HTML using UTF-8 encoding.
+ *
+ * text/html; charset=utf-8
+ */
+ static final html = new ContentType("text", "html", charset: "utf-8");
+ @Deprecated("Use html instead")
+ static final HTML = html;
+
+ /**
+ * Content type for JSON using UTF-8 encoding.
+ *
+ * application/json; charset=utf-8
+ */
+ static final json = new ContentType("application", "json", charset: "utf-8");
+ @Deprecated("Use json instead")
+ static final JSON = json;
+
+ /**
+ * Content type for binary data.
+ *
+ * application/octet-stream
+ */
+ static final binary = new ContentType("application", "octet-stream");
+ @Deprecated("Use binary instead")
+ static final BINARY = binary;
+
+ /**
+ * Creates a new content type object setting the primary type and
+ * sub type. The charset and additional parameters can also be set
+ * using [charset] and [parameters]. If charset is passed and
+ * [parameters] contains charset as well the passed [charset] will
+ * override the value in parameters. Keys passed in parameters will be
+ * converted to lower case. The `charset` entry, whether passed as `charset`
+ * or in `parameters`, will have its value converted to lower-case.
+ */
+ factory ContentType(String primaryType, String subType,
+ {String charset, Map<String, String> parameters}) {
+ return new _ContentType(primaryType, subType, charset, parameters);
+ }
+
+ /**
+ * Creates a new content type object from parsing a Content-Type
+ * header value. As primary type, sub type and parameter names and
+ * values are not case sensitive all these values will be converted
+ * to lower case. Parsing this string
+ *
+ * text/html; charset=utf-8
+ *
+ * will create a content type object with primary type [:text:], sub
+ * type [:html:] and parameter [:charset:] with value [:utf-8:].
+ */
+ static ContentType parse(String value) {
+ return _ContentType.parse(value);
+ }
+
+ /**
+ * Gets the mime-type, without any parameters.
+ */
+ String get mimeType;
+
+ /**
+ * Gets the primary type.
+ */
+ String get primaryType;
+
+ /**
+ * Gets the sub type.
+ */
+ String get subType;
+
+ /**
+ * Gets the character set.
+ */
+ String get charset;
+}
+
+/**
+ * Representation of a cookie. For cookies received by the server as Cookie
+ * header values only [name] and [value] properties will be set. When building a
+ * cookie for the 'set-cookie' header in the server and when receiving cookies
+ * in the client as 'set-cookie' headers all fields can be used.
+ */
+abstract class Cookie {
+ /**
+ * The name of the cookie.
+ *
+ * Must be a `token` as specified in RFC 6265.
+ *
+ * The allowed characters in a `token` are the visible ASCII characters,
+ * U+0021 (`!`) through U+007E (`~`), except the separator characters:
+ * `(`, `)`, `<`, `>`, `@`, `,`, `;`, `:`, `\`, `"`, `/`, `[`, `]`, `?`, `=`,
+ * `{`, and `}`.
+ */
+ String name;
+
+ /**
+ * The value of the cookie.
+ *
+ * Must be a `cookie-value` as specified in RFC 6265.
+ *
+ * The allowed characters in a cookie value are the visible ASCII characters,
+ * U+0021 (`!`) through U+007E (`~`) except the characters:
+ * `"`, `,`, `;` and `\`.
+ * Cookie values may be wrapped in a single pair of double quotes
+ * (U+0022, `"`).
+ */
+ String value;
+
+ /**
+ * The time at which the cookie expires.
+ */
+ DateTime expires;
+
+ /**
+ * The number of seconds until the cookie expires. A zero or negative value
+ * means the cookie has expired.
+ */
+ int maxAge;
+
+ /**
+ * The domain the cookie applies to.
+ */
+ String domain;
+
+ /**
+ * The path within the [domain] the cookie applies to.
+ */
+ String path;
+
+ /**
+ * Whether to only send this cookie on secure connections.
+ */
+ bool secure;
+
+ /**
+ * Whether the cookie is only sent in the HTTP request and is not made
+ * available to client side scripts.
+ */
+ bool httpOnly;
+
+ /**
+ * Creates a new cookie setting the name and value.
+ *
+ * [name] and [value] must be composed of valid characters according to RFC
+ * 6265.
+ *
+ * By default the value of `httpOnly` will be set to `true`.
+ */
+ factory Cookie(String name, String value) => new _Cookie(name, value);
+
+ /**
+ * Creates a new cookie by parsing a header value from a 'set-cookie'
+ * header.
+ */
+ factory Cookie.fromSetCookieValue(String value) {
+ return new _Cookie.fromSetCookieValue(value);
+ }
+
+ /**
+ * Returns the formatted string representation of the cookie. The
+ * string representation can be used for for setting the Cookie or
+ * 'set-cookie' headers
+ */
+ String toString();
+}
+
+/**
+ * A server-side object
+ * that contains the content of and information about an HTTP request.
+ *
+ * __Note__: Check out the
+ * [http_server](https://pub.dartlang.org/packages/http_server)
+ * package, which makes working with the low-level
+ * dart:io HTTP server subsystem easier.
+ *
+ * `HttpRequest` objects are generated by an [HttpServer],
+ * which listens for HTTP requests on a specific host and port.
+ * For each request received, the HttpServer, which is a [Stream],
+ * generates an `HttpRequest` object and adds it to the stream.
+ *
+ * An `HttpRequest` object delivers the body content of the request
+ * as a stream of byte lists.
+ * The object also contains information about the request,
+ * such as the method, URI, and headers.
+ *
+ * In the following code, an HttpServer listens
+ * for HTTP requests. When the server receives a request,
+ * it uses the HttpRequest object's `method` property to dispatch requests.
+ *
+ * final HOST = InternetAddress.loopbackIPv4;
+ * final PORT = 80;
+ *
+ * HttpServer.bind(HOST, PORT).then((_server) {
+ * _server.listen((HttpRequest request) {
+ * switch (request.method) {
+ * case 'GET':
+ * handleGetRequest(request);
+ * break;
+ * case 'POST':
+ * ...
+ * }
+ * },
+ * onError: handleError); // listen() failed.
+ * }).catchError(handleError);
+ *
+ * An HttpRequest object provides access to the associated [HttpResponse]
+ * object through the response property.
+ * The server writes its response to the body of the HttpResponse object.
+ * For example, here's a function that responds to a request:
+ *
+ * void handleGetRequest(HttpRequest req) {
+ * HttpResponse res = req.response;
+ * res.write('Received request ${req.method}: ${req.uri.path}');
+ * res.close();
+ * }
+ */
+abstract class HttpRequest implements Stream<Uint8List> {
+ /**
+ * The content length of the request body.
+ *
+ * If the size of the request body is not known in advance,
+ * this value is -1.
+ */
+ int get contentLength;
+
+ /**
+ * The method, such as 'GET' or 'POST', for the request.
+ */
+ String get method;
+
+ /**
+ * The URI for the request.
+ *
+ * This provides access to the
+ * path and query string for the request.
+ */
+ Uri get uri;
+
+ /**
+ * The requested URI for the request.
+ *
+ * The returned URI is reconstructed by using http-header fields, to access
+ * otherwise lost information, e.g. host and scheme.
+ *
+ * To reconstruct the scheme, first 'X-Forwarded-Proto' is checked, and then
+ * falling back to server type.
+ *
+ * To reconstruct the host, first 'X-Forwarded-Host' is checked, then 'Host'
+ * and finally calling back to server.
+ */
+ Uri get requestedUri;
+
+ /**
+ * The request headers.
+ *
+ * The returned [HttpHeaders] are immutable.
+ */
+ HttpHeaders get headers;
+
+ /**
+ * The cookies in the request, from the Cookie headers.
+ */
+ List<Cookie> get cookies;
+
+ /**
+ * The persistent connection state signaled by the client.
+ */
+ bool get persistentConnection;
+
+ /**
+ * The client certificate of the client making the request.
+ *
+ * This value is null if the connection is not a secure TLS or SSL connection,
+ * or if the server does not request a client certificate, or if the client
+ * does not provide one.
+ */
+ X509Certificate get certificate;
+
+ /**
+ * The session for the given request.
+ *
+ * If the session is
+ * being initialized by this call, [:isNew:] is true for the returned
+ * session.
+ * See [HttpServer.sessionTimeout] on how to change default timeout.
+ */
+ HttpSession get session;
+
+ /**
+ * The HTTP protocol version used in the request,
+ * either "1.0" or "1.1".
+ */
+ String get protocolVersion;
+
+ /**
+ * Information about the client connection.
+ *
+ * Returns [:null:] if the socket is not available.
+ */
+ HttpConnectionInfo get connectionInfo;
+
+ /**
+ * The [HttpResponse] object, used for sending back the response to the
+ * client.
+ *
+ * If the [contentLength] of the body isn't 0, and the body isn't being read,
+ * any write calls on the [HttpResponse] automatically drain the request
+ * body.
+ */
+ HttpResponse get response;
+}
+
+/**
+ * An HTTP response, which returns the headers and data
+ * from the server to the client in response to an HTTP request.
+ *
+ * Every HttpRequest object provides access to the associated [HttpResponse]
+ * object through the `response` property.
+ * The server sends its response to the client by writing to the
+ * HttpResponse object.
+ *
+ * ## Writing the response
+ *
+ * This class implements [IOSink].
+ * After the header has been set up, the methods
+ * from IOSink, such as `writeln()`, can be used to write
+ * the body of the HTTP response.
+ * Use the `close()` method to close the response and send it to the client.
+ *
+ * server.listen((HttpRequest request) {
+ * request.response.write('Hello, world!');
+ * request.response.close();
+ * });
+ *
+ * When one of the IOSink methods is used for the
+ * first time, the request header is sent. Calling any methods that
+ * change the header after it is sent throws an exception.
+ *
+ * ## Setting the headers
+ *
+ * The HttpResponse object has a number of properties for setting up
+ * the HTTP headers of the response.
+ * When writing string data through the IOSink, the encoding used
+ * is determined from the "charset" parameter of the
+ * "Content-Type" header.
+ *
+ * HttpResponse response = ...
+ * response.headers.contentType
+ * = new ContentType("application", "json", charset: "utf-8");
+ * response.write(...); // Strings written will be UTF-8 encoded.
+ *
+ * If no charset is provided the default of ISO-8859-1 (Latin 1) will
+ * be used.
+ *
+ * HttpResponse response = ...
+ * response.headers.add(HttpHeaders.contentTypeHeader, "text/plain");
+ * response.write(...); // Strings written will be ISO-8859-1 encoded.
+ *
+ * An exception is thrown if you use the `write()` method
+ * while an unsupported content-type is set.
+ */
+abstract class HttpResponse implements IOSink {
+ // TODO(ajohnsen): Add documentation of how to pipe a file to the response.
+ /**
+ * Gets and sets the content length of the response. If the size of
+ * the response is not known in advance set the content length to
+ * -1, which is also the default if not set.
+ */
+ int contentLength;
+
+ /**
+ * Gets and sets the status code. Any integer value is accepted. For
+ * the official HTTP status codes use the fields from
+ * [HttpStatus]. If no status code is explicitly set the default
+ * value [HttpStatus.ok] is used.
+ *
+ * The status code must be set before the body is written
+ * to. Setting the status code after writing to the response body or
+ * closing the response will throw a `StateError`.
+ */
+ int statusCode;
+
+ /**
+ * Gets and sets the reason phrase. If no reason phrase is explicitly
+ * set a default reason phrase is provided.
+ *
+ * The reason phrase must be set before the body is written
+ * to. Setting the reason phrase after writing to the response body
+ * or closing the response will throw a `StateError`.
+ */
+ String reasonPhrase;
+
+ /**
+ * Gets and sets the persistent connection state. The initial value
+ * of this property is the persistent connection state from the
+ * request.
+ */
+ bool persistentConnection;
+
+ /**
+ * Set and get the [deadline] for the response. The deadline is timed from the
+ * time it's set. Setting a new deadline will override any previous deadline.
+ * When a deadline is exceeded, the response will be closed and any further
+ * data ignored.
+ *
+ * To disable a deadline, set the [deadline] to `null`.
+ *
+ * The [deadline] is `null` by default.
+ */
+ Duration deadline;
+
+ /**
+ * Gets or sets if the [HttpResponse] should buffer output.
+ *
+ * Default value is `true`.
+ *
+ * __Note__: Disabling buffering of the output can result in very poor
+ * performance, when writing many small chunks.
+ */
+ bool bufferOutput;
+
+ /**
+ * Returns the response headers.
+ *
+ * The response headers can be modified until the response body is
+ * written to or closed. After that they become immutable.
+ */
+ HttpHeaders get headers;
+
+ /**
+ * Cookies to set in the client (in the 'set-cookie' header).
+ */
+ List<Cookie> get cookies;
+
+ /**
+ * Respond with a redirect to [location].
+ *
+ * The URI in [location] should be absolute, but there are no checks
+ * to enforce that.
+ *
+ * By default the HTTP status code `HttpStatus.movedTemporarily`
+ * (`302`) is used for the redirect, but an alternative one can be
+ * specified using the [status] argument.
+ *
+ * This method will also call `close`, and the returned future is
+ * the future returned by `close`.
+ */
+ Future redirect(Uri location, {int status: HttpStatus.movedTemporarily});
+
+ /**
+ * Detaches the underlying socket from the HTTP server. When the
+ * socket is detached the HTTP server will no longer perform any
+ * operations on it.
+ *
+ * This is normally used when a HTTP upgrade request is received
+ * and the communication should continue with a different protocol.
+ *
+ * If [writeHeaders] is `true`, the status line and [headers] will be written
+ * to the socket before it's detached. If `false`, the socket is detached
+ * immediately, without any data written to the socket. Default is `true`.
+ */
+ Future<Socket> detachSocket({bool writeHeaders: true});
+
+ /**
+ * Gets information about the client connection. Returns [:null:] if the
+ * socket is not available.
+ */
+ HttpConnectionInfo get connectionInfo;
+}
+
+/**
+ * A client that receives content, such as web pages, from
+ * a server using the HTTP protocol.
+ *
+ * HttpClient contains a number of methods to send an [HttpClientRequest]
+ * to an Http server and receive an [HttpClientResponse] back.
+ * For example, you can use the [get], [getUrl], [post], and [postUrl] methods
+ * for GET and POST requests, respectively.
+ *
+ * ## Making a simple GET request: an example
+ *
+ * A `getUrl` request is a two-step process, triggered by two [Future]s.
+ * When the first future completes with a [HttpClientRequest], the underlying
+ * network connection has been established, but no data has been sent.
+ * In the callback function for the first future, the HTTP headers and body
+ * can be set on the request. Either the first write to the request object
+ * or a call to [close] sends the request to the server.
+ *
+ * When the HTTP response is received from the server,
+ * the second future, which is returned by close,
+ * completes with an [HttpClientResponse] object.
+ * This object provides access to the headers and body of the response.
+ * The body is available as a stream implemented by HttpClientResponse.
+ * If a body is present, it must be read. Otherwise, it leads to resource
+ * leaks. Consider using [HttpClientResponse.drain] if the body is unused.
+ *
+ * HttpClient client = new HttpClient();
+ * client.getUrl(Uri.parse("http://www.example.com/"))
+ * .then((HttpClientRequest request) {
+ * // Optionally set up headers...
+ * // Optionally write to the request object...
+ * // Then call close.
+ * ...
+ * return request.close();
+ * })
+ * .then((HttpClientResponse response) {
+ * // Process the response.
+ * ...
+ * });
+ *
+ * The future for [HttpClientRequest] is created by methods such as
+ * [getUrl] and [open].
+ *
+ * ## HTTPS connections
+ *
+ * An HttpClient can make HTTPS requests, connecting to a server using
+ * the TLS (SSL) secure networking protocol. Calling [getUrl] with an
+ * https: scheme will work automatically, if the server's certificate is
+ * signed by a root CA (certificate authority) on the default list of
+ * well-known trusted CAs, compiled by Mozilla.
+ *
+ * To add a custom trusted certificate authority, or to send a client
+ * certificate to servers that request one, pass a [SecurityContext] object
+ * as the optional `context` argument to the `HttpClient` constructor.
+ * The desired security options can be set on the [SecurityContext] object.
+ *
+ * ## Headers
+ *
+ * All HttpClient requests set the following header by default:
+ *
+ * Accept-Encoding: gzip
+ *
+ * This allows the HTTP server to use gzip compression for the body if
+ * possible. If this behavior is not desired set the
+ * `Accept-Encoding` header to something else.
+ * To turn off gzip compression of the response, clear this header:
+ *
+ * request.headers.removeAll(HttpHeaders.acceptEncodingHeader)
+ *
+ * ## Closing the HttpClient
+ *
+ * The HttpClient supports persistent connections and caches network
+ * connections to reuse them for multiple requests whenever
+ * possible. This means that network connections can be kept open for
+ * some time after a request has completed. Use HttpClient.close
+ * to force the HttpClient object to shut down and to close the idle
+ * network connections.
+ *
+ * ## Turning proxies on and off
+ *
+ * By default the HttpClient uses the proxy configuration available
+ * from the environment, see [findProxyFromEnvironment]. To turn off
+ * the use of proxies set the [findProxy] property to
+ * [:null:].
+ *
+ * HttpClient client = new HttpClient();
+ * client.findProxy = null;
+ */
+abstract class HttpClient {
+ static const int defaultHttpPort = 80;
+ @Deprecated("Use defaultHttpPort instead")
+ static const int DEFAULT_HTTP_PORT = defaultHttpPort;
+
+ static const int defaultHttpsPort = 443;
+ @Deprecated("Use defaultHttpsPort instead")
+ static const int DEFAULT_HTTPS_PORT = defaultHttpsPort;
+
+ /// Gets and sets the idle timeout of non-active persistent (keep-alive)
+ /// connections.
+ ///
+ /// The default value is 15 seconds.
+ Duration idleTimeout;
+
+ /// Gets and sets the connection timeout.
+ ///
+ /// When connecting to a new host exceeds this timeout, a [SocketException]
+ /// is thrown. The timeout applies only to connections initiated after the
+ /// timeout is set.
+ ///
+ /// When this is `null`, the OS default timeout is used. The default is
+ /// `null`.
+ Duration connectionTimeout;
+
+ /**
+ * Gets and sets the maximum number of live connections, to a single host.
+ *
+ * Increasing this number may lower performance and take up unwanted
+ * system resources.
+ *
+ * To disable, set to `null`.
+ *
+ * Default is `null`.
+ */
+ int maxConnectionsPerHost;
+
+ /**
+ * Gets and sets whether the body of a response will be automatically
+ * uncompressed.
+ *
+ * The body of an HTTP response can be compressed. In most
+ * situations providing the un-compressed body is most
+ * convenient. Therefore the default behavior is to un-compress the
+ * body. However in some situations (e.g. implementing a transparent
+ * proxy) keeping the uncompressed stream is required.
+ *
+ * NOTE: Headers in the response are never modified. This means
+ * that when automatic un-compression is turned on the value of the
+ * header `Content-Length` will reflect the length of the original
+ * compressed body. Likewise the header `Content-Encoding` will also
+ * have the original value indicating compression.
+ *
+ * NOTE: Automatic un-compression is only performed if the
+ * `Content-Encoding` header value is `gzip`.
+ *
+ * This value affects all responses produced by this client after the
+ * value is changed.
+ *
+ * To disable, set to `false`.
+ *
+ * Default is `true`.
+ */
+ bool autoUncompress;
+
+ /// Gets and sets the default value of the `User-Agent` header for all requests
+ /// generated by this [HttpClient].
+ ///
+ /// The default value is `Dart/<version> (dart:io)`.
+ ///
+ /// If the userAgent is set to `null`, no default `User-Agent` header will be
+ /// added to each request.
+ String userAgent;
+
+ factory HttpClient({SecurityContext context}) {
+ HttpOverrides overrides = HttpOverrides.current;
+ if (overrides == null) {
+ return new _HttpClient(context);
+ }
+ return overrides.createHttpClient(context);
+ }
+
+ /**
+ * Opens a HTTP connection.
+ *
+ * The HTTP method to use is specified in [method], the server is
+ * specified using [host] and [port], and the path (including
+ * a possible query) is specified using [path].
+ * The path may also contain a URI fragment, which will be ignored.
+ *
+ * The `Host` header for the request will be set to the value [host]:[port]
+ * (if [host] is an IP address, it will still be used in the `Host` header).
+ * This can be overridden through the [HttpClientRequest] interface before
+ * the request is sent.
+ *
+ * For additional information on the sequence of events during an
+ * HTTP transaction, and the objects returned by the futures, see
+ * the overall documentation for the class [HttpClient].
+ */
+ Future<HttpClientRequest> open(
+ String method, String host, int port, String path);
+
+ /**
+ * Opens a HTTP connection.
+ *
+ * The HTTP method is specified in [method] and the URL to use in
+ * [url].
+ *
+ * The `Host` header for the request will be set to the value
+ * [Uri.host]:[Uri.port] from [url] (if [url.host] is an IP address, it will
+ * still be used in the `Host` header). This can be overridden through the
+ * [HttpClientRequest] interface before the request is sent.
+ *
+ * For additional information on the sequence of events during an
+ * HTTP transaction, and the objects returned by the futures, see
+ * the overall documentation for the class [HttpClient].
+ */
+ Future<HttpClientRequest> openUrl(String method, Uri url);
+
+ /**
+ * Opens a HTTP connection using the GET method.
+ *
+ * The server is specified using [host] and [port], and the path
+ * (including a possible query) is specified using
+ * [path].
+ *
+ * See [open] for details.
+ */
+ Future<HttpClientRequest> get(String host, int port, String path);
+
+ /**
+ * Opens a HTTP connection using the GET method.
+ *
+ * The URL to use is specified in [url].
+ *
+ * See [openUrl] for details.
+ */
+ Future<HttpClientRequest> getUrl(Uri url);
+
+ /**
+ * Opens a HTTP connection using the POST method.
+ *
+ * The server is specified using [host] and [port], and the path
+ * (including a possible query) is specified using
+ * [path].
+ *
+ * See [open] for details.
+ */
+ Future<HttpClientRequest> post(String host, int port, String path);
+
+ /**
+ * Opens a HTTP connection using the POST method.
+ *
+ * The URL to use is specified in [url].
+ *
+ * See [openUrl] for details.
+ */
+ Future<HttpClientRequest> postUrl(Uri url);
+
+ /**
+ * Opens a HTTP connection using the PUT method.
+ *
+ * The server is specified using [host] and [port], and the path
+ * (including a possible query) is specified using [path].
+ *
+ * See [open] for details.
+ */
+ Future<HttpClientRequest> put(String host, int port, String path);
+
+ /**
+ * Opens a HTTP connection using the PUT method.
+ *
+ * The URL to use is specified in [url].
+ *
+ * See [openUrl] for details.
+ */
+ Future<HttpClientRequest> putUrl(Uri url);
+
+ /**
+ * Opens a HTTP connection using the DELETE method.
+ *
+ * The server is specified using [host] and [port], and the path
+ * (including a possible query) is specified using [path].
+ *
+ * See [open] for details.
+ */
+ Future<HttpClientRequest> delete(String host, int port, String path);
+
+ /**
+ * Opens a HTTP connection using the DELETE method.
+ *
+ * The URL to use is specified in [url].
+ *
+ * See [openUrl] for details.
+ */
+ Future<HttpClientRequest> deleteUrl(Uri url);
+
+ /**
+ * Opens a HTTP connection using the PATCH method.
+ *
+ * The server is specified using [host] and [port], and the path
+ * (including a possible query) is specified using [path].
+ *
+ * See [open] for details.
+ */
+ Future<HttpClientRequest> patch(String host, int port, String path);
+
+ /**
+ * Opens a HTTP connection using the PATCH method.
+ *
+ * The URL to use is specified in [url].
+ *
+ * See [openUrl] for details.
+ */
+ Future<HttpClientRequest> patchUrl(Uri url);
+
+ /**
+ * Opens a HTTP connection using the HEAD method.
+ *
+ * The server is specified using [host] and [port], and the path
+ * (including a possible query) is specified using [path].
+ *
+ * See [open] for details.
+ */
+ Future<HttpClientRequest> head(String host, int port, String path);
+
+ /**
+ * Opens a HTTP connection using the HEAD method.
+ *
+ * The URL to use is specified in [url].
+ *
+ * See [openUrl] for details.
+ */
+ Future<HttpClientRequest> headUrl(Uri url);
+
+ /**
+ * Sets the function to be called when a site is requesting
+ * authentication. The URL requested and the security realm from the
+ * server are passed in the arguments [url] and [realm].
+ *
+ * The function returns a [Future] which should complete when the
+ * authentication has been resolved. If credentials cannot be
+ * provided the [Future] should complete with [:false:]. If
+ * credentials are available the function should add these using
+ * [addCredentials] before completing the [Future] with the value
+ * [:true:].
+ *
+ * If the [Future] completes with [:true:] the request will be retried
+ * using the updated credentials, however, the retried request will not
+ * carry the original request payload. Otherwise response processing will
+ * continue normally.
+ *
+ * If it is known that the remote server requires authentication for all
+ * requests, it is advisable to use [addCredentials] directly, or manually
+ * set the `'authorization'` header on the request to avoid the overhead
+ * of a failed request, or issues due to missing request payload on retried
+ * request.
+ */
+ set authenticate(Future<bool> f(Uri url, String scheme, String realm));
+
+ /**
+ * Add credentials to be used for authorizing HTTP requests.
+ */
+ void addCredentials(Uri url, String realm, HttpClientCredentials credentials);
+
+ /**
+ * Sets the function used to resolve the proxy server to be used for
+ * opening a HTTP connection to the specified [url]. If this
+ * function is not set, direct connections will always be used.
+ *
+ * The string returned by [f] must be in the format used by browser
+ * PAC (proxy auto-config) scripts. That is either
+ *
+ * "DIRECT"
+ *
+ * for using a direct connection or
+ *
+ * "PROXY host:port"
+ *
+ * for using the proxy server [:host:] on port [:port:].
+ *
+ * A configuration can contain several configuration elements
+ * separated by semicolons, e.g.
+ *
+ * "PROXY host:port; PROXY host2:port2; DIRECT"
+ *
+ * The static function [findProxyFromEnvironment] on this class can
+ * be used to implement proxy server resolving based on environment
+ * variables.
+ */
+ set findProxy(String f(Uri url));
+
+ /**
+ * Function for resolving the proxy server to be used for a HTTP
+ * connection from the proxy configuration specified through
+ * environment variables.
+ *
+ * The following environment variables are taken into account:
+ *
+ * http_proxy
+ * https_proxy
+ * no_proxy
+ * HTTP_PROXY
+ * HTTPS_PROXY
+ * NO_PROXY
+ *
+ * [:http_proxy:] and [:HTTP_PROXY:] specify the proxy server to use for
+ * http:// urls. Use the format [:hostname:port:]. If no port is used a
+ * default of 1080 will be used. If both are set the lower case one takes
+ * precedence.
+ *
+ * [:https_proxy:] and [:HTTPS_PROXY:] specify the proxy server to use for
+ * https:// urls. Use the format [:hostname:port:]. If no port is used a
+ * default of 1080 will be used. If both are set the lower case one takes
+ * precedence.
+ *
+ * [:no_proxy:] and [:NO_PROXY:] specify a comma separated list of
+ * postfixes of hostnames for which not to use the proxy
+ * server. E.g. the value "localhost,127.0.0.1" will make requests
+ * to both "localhost" and "127.0.0.1" not use a proxy. If both are set
+ * the lower case one takes precedence.
+ *
+ * To activate this way of resolving proxies assign this function to
+ * the [findProxy] property on the [HttpClient].
+ *
+ * HttpClient client = new HttpClient();
+ * client.findProxy = HttpClient.findProxyFromEnvironment;
+ *
+ * If you don't want to use the system environment you can use a
+ * different one by wrapping the function.
+ *
+ * HttpClient client = new HttpClient();
+ * client.findProxy = (url) {
+ * return HttpClient.findProxyFromEnvironment(
+ * url, environment: {"http_proxy": ..., "no_proxy": ...});
+ * }
+ *
+ * If a proxy requires authentication it is possible to configure
+ * the username and password as well. Use the format
+ * [:username:password@hostname:port:] to include the username and
+ * password. Alternatively the API [addProxyCredentials] can be used
+ * to set credentials for proxies which require authentication.
+ */
+ static String findProxyFromEnvironment(Uri url,
+ {Map<String, String> environment}) {
+ HttpOverrides overrides = HttpOverrides.current;
+ if (overrides == null) {
+ return _HttpClient._findProxyFromEnvironment(url, environment);
+ }
+ return overrides.findProxyFromEnvironment(url, environment);
+ }
+
+ /**
+ * Sets the function to be called when a proxy is requesting
+ * authentication. Information on the proxy in use and the security
+ * realm for the authentication are passed in the arguments [host],
+ * [port] and [realm].
+ *
+ * The function returns a [Future] which should complete when the
+ * authentication has been resolved. If credentials cannot be
+ * provided the [Future] should complete with [:false:]. If
+ * credentials are available the function should add these using
+ * [addProxyCredentials] before completing the [Future] with the value
+ * [:true:].
+ *
+ * If the [Future] completes with [:true:] the request will be retried
+ * using the updated credentials. Otherwise response processing will
+ * continue normally.
+ */
+ set authenticateProxy(
+ Future<bool> f(String host, int port, String scheme, String realm));
+
+ /**
+ * Add credentials to be used for authorizing HTTP proxies.
+ */
+ void addProxyCredentials(
+ String host, int port, String realm, HttpClientCredentials credentials);
+
+ /**
+ * Sets a callback that will decide whether to accept a secure connection
+ * with a server certificate that cannot be authenticated by any of our
+ * trusted root certificates.
+ *
+ * When an secure HTTP request if made, using this HttpClient, and the
+ * server returns a server certificate that cannot be authenticated, the
+ * callback is called asynchronously with the [X509Certificate] object and
+ * the server's hostname and port. If the value of [badCertificateCallback]
+ * is [:null:], the bad certificate is rejected, as if the callback
+ * returned [:false:]
+ *
+ * If the callback returns true, the secure connection is accepted and the
+ * [:Future<HttpClientRequest>:] that was returned from the call making the
+ * request completes with a valid HttpRequest object. If the callback returns
+ * false, the [:Future<HttpClientRequest>:] completes with an exception.
+ *
+ * If a bad certificate is received on a connection attempt, the library calls
+ * the function that was the value of badCertificateCallback at the time
+ * the request is made, even if the value of badCertificateCallback
+ * has changed since then.
+ */
+ set badCertificateCallback(
+ bool callback(X509Certificate cert, String host, int port));
+
+ /// Shuts down the HTTP client.
+ ///
+ /// If [force] is `false` (the default) the [HttpClient] will be kept alive
+ /// until all active connections are done. If [force] is `true` any active
+ /// connections will be closed to immediately release all resources. These
+ /// closed connections will receive an error event to indicate that the client
+ /// was shut down. In both cases trying to establish a new connection after
+ /// calling [close] will throw an exception.
+ void close({bool force: false});
+}
+
+/**
+ * HTTP request for a client connection.
+ *
+ * To set up a request, set the headers using the headers property
+ * provided in this class and write the data to the body of the request.
+ * HttpClientRequest is an [IOSink]. Use the methods from IOSink,
+ * such as writeCharCode(), to write the body of the HTTP
+ * request. When one of the IOSink methods is used for the first
+ * time, the request header is sent. Calling any methods that
+ * change the header after it is sent throws an exception.
+ *
+ * When writing string data through the [IOSink] the
+ * encoding used is determined from the "charset" parameter of
+ * the "Content-Type" header.
+ *
+ * HttpClientRequest request = ...
+ * request.headers.contentType
+ * = new ContentType("application", "json", charset: "utf-8");
+ * request.write(...); // Strings written will be UTF-8 encoded.
+ *
+ * If no charset is provided the default of ISO-8859-1 (Latin 1) is
+ * be used.
+ *
+ * HttpClientRequest request = ...
+ * request.headers.add(HttpHeaders.contentTypeHeader, "text/plain");
+ * request.write(...); // Strings written will be ISO-8859-1 encoded.
+ *
+ * An exception is thrown if you use an unsupported encoding and the
+ * `write()` method being used takes a string parameter.
+ */
+abstract class HttpClientRequest implements IOSink {
+ /**
+ * Gets and sets the requested persistent connection state.
+ *
+ * The default value is [:true:].
+ */
+ bool persistentConnection;
+
+ /**
+ * Set this property to [:true:] if this request should
+ * automatically follow redirects. The default is [:true:].
+ *
+ * Automatic redirect will only happen for "GET" and "HEAD" requests
+ * and only for the status codes [:HttpStatus.movedPermanently:]
+ * (301), [:HttpStatus.found:] (302),
+ * [:HttpStatus.movedTemporarily:] (302, alias for
+ * [:HttpStatus.found:]), [:HttpStatus.seeOther:] (303) and
+ * [:HttpStatus.temporaryRedirect:] (307). For
+ * [:HttpStatus.seeOther:] (303) automatic redirect will also happen
+ * for "POST" requests with the method changed to "GET" when
+ * following the redirect.
+ *
+ * All headers added to the request will be added to the redirection
+ * request(s). However, any body send with the request will not be
+ * part of the redirection request(s).
+ */
+ bool followRedirects;
+
+ /**
+ * Set this property to the maximum number of redirects to follow
+ * when [followRedirects] is `true`. If this number is exceeded
+ * an error event will be added with a [RedirectException].
+ *
+ * The default value is 5.
+ */
+ int maxRedirects;
+
+ /**
+ * The method of the request.
+ */
+ String get method;
+
+ /**
+ * The uri of the request.
+ */
+ Uri get uri;
+
+ /// Gets and sets the content length of the request.
+ ///
+ /// If the size of the request is not known in advance set content length to
+ /// -1, which is also the default.
+ int contentLength;
+
+ /**
+ * Gets or sets if the [HttpClientRequest] should buffer output.
+ *
+ * Default value is `true`.
+ *
+ * __Note__: Disabling buffering of the output can result in very poor
+ * performance, when writing many small chunks.
+ */
+ bool bufferOutput;
+
+ /**
+ * Returns the client request headers.
+ *
+ * The client request headers can be modified until the client
+ * request body is written to or closed. After that they become
+ * immutable.
+ */
+ HttpHeaders get headers;
+
+ /**
+ * Cookies to present to the server (in the 'cookie' header).
+ */
+ List<Cookie> get cookies;
+
+ /// A [HttpClientResponse] future that will complete once the response is
+ /// available.
+ ///
+ /// If an error occurs before the response is available, this future will
+ /// complete with an error.
+ Future<HttpClientResponse> get done;
+
+ /**
+ * Close the request for input. Returns the value of [done].
+ */
+ Future<HttpClientResponse> close();
+
+ /// Gets information about the client connection.
+ ///
+ /// Returns [:null:] if the socket is not available.
+ HttpConnectionInfo get connectionInfo;
+}
+
+/**
+ * HTTP response for a client connection.
+ *
+ * The body of a [HttpClientResponse] object is a
+ * [Stream] of data from the server. Listen to the body to handle
+ * the data and be notified when the entire body is received.
+ *
+ * new HttpClient().get('localhost', 80, '/file.txt')
+ * .then((HttpClientRequest request) => request.close())
+ * .then((HttpClientResponse response) {
+ * response.transform(utf8.decoder).listen((contents) {
+ * // handle data
+ * });
+ * });
+ */
+abstract class HttpClientResponse implements Stream<List<int>> {
+ /**
+ * Returns the status code.
+ *
+ * The status code must be set before the body is written
+ * to. Setting the status code after writing to the body will throw
+ * a `StateError`.
+ */
+ int get statusCode;
+
+ /**
+ * Returns the reason phrase associated with the status code.
+ *
+ * The reason phrase must be set before the body is written
+ * to. Setting the reason phrase after writing to the body will throw
+ * a `StateError`.
+ */
+ String get reasonPhrase;
+
+ /**
+ * Returns the content length of the response body. Returns -1 if the size of
+ * the response body is not known in advance.
+ *
+ * If the content length needs to be set, it must be set before the
+ * body is written to. Setting the content length after writing to the body
+ * will throw a `StateError`.
+ */
+ int get contentLength;
+
+ /// The compression state of the response.
+ ///
+ /// This specifies whether the response bytes were compressed when they were
+ /// received across the wire and whether callers will receive compressed
+ /// or uncompressed bytes when they listed to this response's byte stream.
+ @Since("2.4")
+ HttpClientResponseCompressionState get compressionState;
+
+ /**
+ * Gets the persistent connection state returned by the server.
+ *
+ * If the persistent connection state needs to be set, it must be
+ * set before the body is written to. Setting the persistent connection state
+ * after writing to the body will throw a `StateError`.
+ */
+ bool get persistentConnection;
+
+ /**
+ * Returns whether the status code is one of the normal redirect
+ * codes [HttpStatus.movedPermanently], [HttpStatus.found],
+ * [HttpStatus.movedTemporarily], [HttpStatus.seeOther] and
+ * [HttpStatus.temporaryRedirect].
+ */
+ bool get isRedirect;
+
+ /**
+ * Returns the series of redirects this connection has been through. The
+ * list will be empty if no redirects were followed. [redirects] will be
+ * updated both in the case of an automatic and a manual redirect.
+ */
+ List<RedirectInfo> get redirects;
+
+ /**
+ * Redirects this connection to a new URL. The default value for
+ * [method] is the method for the current request. The default value
+ * for [url] is the value of the [HttpHeaders.locationHeader] header of
+ * the current response. All body data must have been read from the
+ * current response before calling [redirect].
+ *
+ * All headers added to the request will be added to the redirection
+ * request. However, any body sent with the request will not be
+ * part of the redirection request.
+ *
+ * If [followLoops] is set to [:true:], redirect will follow the redirect,
+ * even if the URL was already visited. The default value is [:false:].
+ *
+ * The method will ignore [HttpClientRequest.maxRedirects]
+ * and will always perform the redirect.
+ */
+ Future<HttpClientResponse> redirect(
+ [String method, Uri url, bool followLoops]);
+
+ /**
+ * Returns the client response headers.
+ *
+ * The client response headers are immutable.
+ */
+ HttpHeaders get headers;
+
+ /**
+ * Detach the underlying socket from the HTTP client. When the
+ * socket is detached the HTTP client will no longer perform any
+ * operations on it.
+ *
+ * This is normally used when a HTTP upgrade is negotiated and the
+ * communication should continue with a different protocol.
+ */
+ Future<Socket> detachSocket();
+
+ /**
+ * Cookies set by the server (from the 'set-cookie' header).
+ */
+ List<Cookie> get cookies;
+
+ /**
+ * Returns the certificate of the HTTPS server providing the response.
+ * Returns null if the connection is not a secure TLS or SSL connection.
+ */
+ X509Certificate get certificate;
+
+ /**
+ * Gets information about the client connection. Returns [:null:] if the socket
+ * is not available.
+ */
+ HttpConnectionInfo get connectionInfo;
+}
+
+/// Enum that specifies the compression state of the byte stream of an
+/// [HttpClientResponse].
+///
+/// The values herein allow callers to answer the following questions as they
+/// pertain to an [HttpClientResponse]:
+///
+/// * Can the value of the response's `Content-Length` HTTP header be trusted?
+/// * Does the caller need to manually decompress the response's byte stream?
+///
+/// This enum is accessed via the [HttpClientResponse.compressionState] value.
+@Since("2.4")
+enum HttpClientResponseCompressionState {
+ /// The body of the HTTP response was received and remains in an uncompressed
+ /// state.
+ ///
+ /// In this state, the value of the `Content-Length` HTTP header, if
+ /// specified (non-negative), should match the number of bytes produced by
+ /// the response's byte stream.
+ notCompressed,
+
+ /// The body of the HTTP response was originally compressed, but by virtue of
+ /// the [HttpClient.autoUncompress] configuration option, it has been
+ /// automatically uncompressed.
+ ///
+ /// HTTP headers are not modified, so when a response has been uncompressed
+ /// in this way, the value of the `Content-Length` HTTP header cannot be
+ /// trusted, as it will contain the compressed content length, whereas the
+ /// stream of bytes produced by the response will contain uncompressed bytes.
+ decompressed,
+
+ /// The body of the HTTP response contains compressed bytes.
+ ///
+ /// In this state, the value of the `Content-Length` HTTP header, if
+ /// specified (non-negative), should match the number of bytes produced by
+ /// the response's byte stream.
+ ///
+ /// If the caller wishes to manually uncompress the body of the response,
+ /// it should consult the value of the `Content-Encoding` HTTP header to see
+ /// what type of compression has been applied. See
+ /// <https://tools.ietf.org/html/rfc2616#section-14.11> for more information.
+ compressed,
+}
+
+abstract class HttpClientCredentials {}
+
+/**
+ * Represents credentials for basic authentication.
+ */
+abstract class HttpClientBasicCredentials extends HttpClientCredentials {
+ factory HttpClientBasicCredentials(String username, String password) =>
+ new _HttpClientBasicCredentials(username, password);
+}
+
+/**
+ * Represents credentials for digest authentication. Digest
+ * authentication is only supported for servers using the MD5
+ * algorithm and quality of protection (qop) of either "none" or
+ * "auth".
+ */
+abstract class HttpClientDigestCredentials extends HttpClientCredentials {
+ factory HttpClientDigestCredentials(String username, String password) =>
+ new _HttpClientDigestCredentials(username, password);
+}
+
+/**
+ * Information about an [HttpRequest], [HttpResponse], [HttpClientRequest], or
+ * [HttpClientResponse] connection.
+ */
+abstract class HttpConnectionInfo {
+ InternetAddress get remoteAddress;
+ int get remotePort;
+ int get localPort;
+}
+
+/**
+ * Redirect information.
+ */
+abstract class RedirectInfo {
+ /**
+ * Returns the status code used for the redirect.
+ */
+ int get statusCode;
+
+ /**
+ * Returns the method used for the redirect.
+ */
+ String get method;
+
+ /**
+ * Returns the location for the redirect.
+ */
+ Uri get location;
+}
+
+/**
+ * When detaching a socket from either the [:HttpServer:] or the
+ * [:HttpClient:] due to a HTTP connection upgrade there might be
+ * unparsed data already read from the socket. This unparsed data
+ * together with the detached socket is returned in an instance of
+ * this class.
+ */
+abstract class DetachedSocket {
+ Socket get socket;
+ List<int> get unparsedData;
+}
+
+class HttpException implements IOException {
+ final String message;
+ final Uri uri;
+
+ const HttpException(this.message, {this.uri});
+
+ String toString() {
+ var b = new StringBuffer()..write('HttpException: ')..write(message);
+ if (uri != null) {
+ b.write(', uri = $uri');
+ }
+ return b.toString();
+ }
+}
+
+class RedirectException implements HttpException {
+ final String message;
+ final List<RedirectInfo> redirects;
+
+ const RedirectException(this.message, this.redirects);
+
+ String toString() => "RedirectException: $message";
+
+ Uri get uri => redirects.last.location;
+}
diff --git a/sdk_nnbd/lib/_http/http_date.dart b/sdk_nnbd/lib/_http/http_date.dart
new file mode 100644
index 0000000..d9301b4
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http_date.dart
@@ -0,0 +1,388 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+/**
+ * Utility functions for working with dates with HTTP specific date
+ * formats.
+ */
+class HttpDate {
+ // From RFC-2616 section "3.3.1 Full Date",
+ // http://tools.ietf.org/html/rfc2616#section-3.3.1
+ //
+ // HTTP-date = rfc1123-date | rfc850-date | asctime-date
+ // rfc1123-date = wkday "," SP date1 SP time SP "GMT"
+ // rfc850-date = weekday "," SP date2 SP time SP "GMT"
+ // asctime-date = wkday SP date3 SP time SP 4DIGIT
+ // date1 = 2DIGIT SP month SP 4DIGIT
+ // ; day month year (e.g., 02 Jun 1982)
+ // date2 = 2DIGIT "-" month "-" 2DIGIT
+ // ; day-month-year (e.g., 02-Jun-82)
+ // date3 = month SP ( 2DIGIT | ( SP 1DIGIT ))
+ // ; month day (e.g., Jun 2)
+ // time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ // ; 00:00:00 - 23:59:59
+ // wkday = "Mon" | "Tue" | "Wed"
+ // | "Thu" | "Fri" | "Sat" | "Sun"
+ // weekday = "Monday" | "Tuesday" | "Wednesday"
+ // | "Thursday" | "Friday" | "Saturday" | "Sunday"
+ // month = "Jan" | "Feb" | "Mar" | "Apr"
+ // | "May" | "Jun" | "Jul" | "Aug"
+ // | "Sep" | "Oct" | "Nov" | "Dec"
+
+ /**
+ * Format a date according to
+ * [RFC-1123](http://tools.ietf.org/html/rfc1123 "RFC-1123"),
+ * e.g. `Thu, 1 Jan 1970 00:00:00 GMT`.
+ */
+ static String format(DateTime date) {
+ const List wkday = const ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
+ const List month = const [
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"
+ ];
+
+ DateTime d = date.toUtc();
+ StringBuffer sb = new StringBuffer()
+ ..write(wkday[d.weekday - 1])
+ ..write(", ")
+ ..write(d.day <= 9 ? "0" : "")
+ ..write(d.day.toString())
+ ..write(" ")
+ ..write(month[d.month - 1])
+ ..write(" ")
+ ..write(d.year.toString())
+ ..write(d.hour <= 9 ? " 0" : " ")
+ ..write(d.hour.toString())
+ ..write(d.minute <= 9 ? ":0" : ":")
+ ..write(d.minute.toString())
+ ..write(d.second <= 9 ? ":0" : ":")
+ ..write(d.second.toString())
+ ..write(" GMT");
+ return sb.toString();
+ }
+
+ /**
+ * Parse a date string in either of the formats
+ * [RFC-1123](http://tools.ietf.org/html/rfc1123 "RFC-1123"),
+ * [RFC-850](http://tools.ietf.org/html/rfc850 "RFC-850") or
+ * ANSI C's asctime() format. These formats are listed here.
+ *
+ * Thu, 1 Jan 1970 00:00:00 GMT
+ * Thursday, 1-Jan-1970 00:00:00 GMT
+ * Thu Jan 1 00:00:00 1970
+ *
+ * For more information see [RFC-2616 section
+ * 3.1.1](http://tools.ietf.org/html/rfc2616#section-3.3.1
+ * "RFC-2616 section 3.1.1").
+ */
+ static DateTime parse(String date) {
+ final int SP = 32;
+ const List wkdays = const ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
+ const List weekdays = const [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday"
+ ];
+ const List months = const [
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"
+ ];
+ const List wkdaysLowerCase = const [
+ "mon",
+ "tue",
+ "wed",
+ "thu",
+ "fri",
+ "sat",
+ "sun"
+ ];
+ const List weekdaysLowerCase = const [
+ "monday",
+ "tuesday",
+ "wednesday",
+ "thursday",
+ "friday",
+ "saturday",
+ "sunday"
+ ];
+ const List monthsLowerCase = const [
+ "jan",
+ "feb",
+ "mar",
+ "apr",
+ "may",
+ "jun",
+ "jul",
+ "aug",
+ "sep",
+ "oct",
+ "nov",
+ "dec"
+ ];
+
+ final int formatRfc1123 = 0;
+ final int formatRfc850 = 1;
+ final int formatAsctime = 2;
+
+ int index = 0;
+ String tmp;
+ int format;
+
+ void expect(String s) {
+ if (date.length - index < s.length) {
+ throw new HttpException("Invalid HTTP date $date");
+ }
+ String tmp = date.substring(index, index + s.length);
+ if (tmp != s) {
+ throw new HttpException("Invalid HTTP date $date");
+ }
+ index += s.length;
+ }
+
+ int expectWeekday() {
+ int weekday;
+ // The formatting of the weekday signals the format of the date string.
+ int pos = date.indexOf(",", index);
+ if (pos == -1) {
+ int pos = date.indexOf(" ", index);
+ if (pos == -1) throw new HttpException("Invalid HTTP date $date");
+ tmp = date.substring(index, pos);
+ index = pos + 1;
+ weekday = wkdays.indexOf(tmp);
+ if (weekday != -1) {
+ format = formatAsctime;
+ return weekday;
+ }
+ } else {
+ tmp = date.substring(index, pos);
+ index = pos + 1;
+ weekday = wkdays.indexOf(tmp);
+ if (weekday != -1) {
+ format = formatRfc1123;
+ return weekday;
+ }
+ weekday = weekdays.indexOf(tmp);
+ if (weekday != -1) {
+ format = formatRfc850;
+ return weekday;
+ }
+ }
+ throw new HttpException("Invalid HTTP date $date");
+ }
+
+ int expectMonth(String separator) {
+ int pos = date.indexOf(separator, index);
+ if (pos - index != 3) throw new HttpException("Invalid HTTP date $date");
+ tmp = date.substring(index, pos);
+ index = pos + 1;
+ int month = months.indexOf(tmp);
+ if (month != -1) return month;
+ throw new HttpException("Invalid HTTP date $date");
+ }
+
+ int expectNum(String separator) {
+ int pos;
+ if (separator.length > 0) {
+ pos = date.indexOf(separator, index);
+ } else {
+ pos = date.length;
+ }
+ String tmp = date.substring(index, pos);
+ index = pos + separator.length;
+ try {
+ int value = int.parse(tmp);
+ return value;
+ } on FormatException catch (e) {
+ throw new HttpException("Invalid HTTP date $date");
+ }
+ }
+
+ void expectEnd() {
+ if (index != date.length) {
+ throw new HttpException("Invalid HTTP date $date");
+ }
+ }
+
+ int weekday = expectWeekday();
+ int day;
+ int month;
+ int year;
+ int hours;
+ int minutes;
+ int seconds;
+ if (format == formatAsctime) {
+ month = expectMonth(" ");
+ if (date.codeUnitAt(index) == SP) index++;
+ day = expectNum(" ");
+ hours = expectNum(":");
+ minutes = expectNum(":");
+ seconds = expectNum(" ");
+ year = expectNum("");
+ } else {
+ expect(" ");
+ day = expectNum(format == formatRfc1123 ? " " : "-");
+ month = expectMonth(format == formatRfc1123 ? " " : "-");
+ year = expectNum(" ");
+ hours = expectNum(":");
+ minutes = expectNum(":");
+ seconds = expectNum(" ");
+ expect("GMT");
+ }
+ expectEnd();
+ return new DateTime.utc(year, month + 1, day, hours, minutes, seconds, 0);
+ }
+
+ // Parse a cookie date string.
+ static DateTime _parseCookieDate(String date) {
+ const List monthsLowerCase = const [
+ "jan",
+ "feb",
+ "mar",
+ "apr",
+ "may",
+ "jun",
+ "jul",
+ "aug",
+ "sep",
+ "oct",
+ "nov",
+ "dec"
+ ];
+
+ int position = 0;
+
+ void error() {
+ throw new HttpException("Invalid cookie date $date");
+ }
+
+ bool isEnd() => position == date.length;
+
+ bool isDelimiter(String s) {
+ int char = s.codeUnitAt(0);
+ if (char == 0x09) return true;
+ if (char >= 0x20 && char <= 0x2F) return true;
+ if (char >= 0x3B && char <= 0x40) return true;
+ if (char >= 0x5B && char <= 0x60) return true;
+ if (char >= 0x7B && char <= 0x7E) return true;
+ return false;
+ }
+
+ bool isNonDelimiter(String s) {
+ int char = s.codeUnitAt(0);
+ if (char >= 0x00 && char <= 0x08) return true;
+ if (char >= 0x0A && char <= 0x1F) return true;
+ if (char >= 0x30 && char <= 0x39) return true; // Digit
+ if (char == 0x3A) return true; // ':'
+ if (char >= 0x41 && char <= 0x5A) return true; // Alpha
+ if (char >= 0x61 && char <= 0x7A) return true; // Alpha
+ if (char >= 0x7F && char <= 0xFF) return true; // Alpha
+ return false;
+ }
+
+ bool isDigit(String s) {
+ int char = s.codeUnitAt(0);
+ if (char > 0x2F && char < 0x3A) return true;
+ return false;
+ }
+
+ int getMonth(String month) {
+ if (month.length < 3) return -1;
+ return monthsLowerCase.indexOf(month.substring(0, 3));
+ }
+
+ int toInt(String s) {
+ int index = 0;
+ for (; index < s.length && isDigit(s[index]); index++);
+ return int.parse(s.substring(0, index));
+ }
+
+ var tokens = [];
+ while (!isEnd()) {
+ while (!isEnd() && isDelimiter(date[position])) position++;
+ int start = position;
+ while (!isEnd() && isNonDelimiter(date[position])) position++;
+ tokens.add(date.substring(start, position).toLowerCase());
+ while (!isEnd() && isDelimiter(date[position])) position++;
+ }
+
+ String timeStr;
+ String dayOfMonthStr;
+ String monthStr;
+ String yearStr;
+
+ for (var token in tokens) {
+ if (token.length < 1) continue;
+ if (timeStr == null &&
+ token.length >= 5 &&
+ isDigit(token[0]) &&
+ (token[1] == ":" || (isDigit(token[1]) && token[2] == ":"))) {
+ timeStr = token;
+ } else if (dayOfMonthStr == null && isDigit(token[0])) {
+ dayOfMonthStr = token;
+ } else if (monthStr == null && getMonth(token) >= 0) {
+ monthStr = token;
+ } else if (yearStr == null &&
+ token.length >= 2 &&
+ isDigit(token[0]) &&
+ isDigit(token[1])) {
+ yearStr = token;
+ }
+ }
+
+ if (timeStr == null ||
+ dayOfMonthStr == null ||
+ monthStr == null ||
+ yearStr == null) {
+ error();
+ }
+
+ int year = toInt(yearStr);
+ if (year >= 70 && year <= 99)
+ year += 1900;
+ else if (year >= 0 && year <= 69) year += 2000;
+ if (year < 1601) error();
+
+ int dayOfMonth = toInt(dayOfMonthStr);
+ if (dayOfMonth < 1 || dayOfMonth > 31) error();
+
+ int month = getMonth(monthStr) + 1;
+
+ var timeList = timeStr.split(":");
+ if (timeList.length != 3) error();
+ int hour = toInt(timeList[0]);
+ int minute = toInt(timeList[1]);
+ int second = toInt(timeList[2]);
+ if (hour > 23) error();
+ if (minute > 59) error();
+ if (second > 59) error();
+
+ return new DateTime.utc(year, month, dayOfMonth, hour, minute, second, 0);
+ }
+}
diff --git a/sdk_nnbd/lib/_http/http_headers.dart b/sdk_nnbd/lib/_http/http_headers.dart
new file mode 100644
index 0000000..7601485
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http_headers.dart
@@ -0,0 +1,1033 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+class _HttpHeaders implements HttpHeaders {
+ final Map<String, List<String>> _headers;
+ final String protocolVersion;
+
+ bool _mutable = true; // Are the headers currently mutable?
+ List<String> _noFoldingHeaders;
+
+ int _contentLength = -1;
+ bool _persistentConnection = true;
+ bool _chunkedTransferEncoding = false;
+ String _host;
+ int _port;
+
+ final int _defaultPortForScheme;
+
+ _HttpHeaders(this.protocolVersion,
+ {int defaultPortForScheme: HttpClient.defaultHttpPort,
+ _HttpHeaders initialHeaders})
+ : _headers = new HashMap<String, List<String>>(),
+ _defaultPortForScheme = defaultPortForScheme {
+ if (initialHeaders != null) {
+ initialHeaders._headers.forEach((name, value) => _headers[name] = value);
+ _contentLength = initialHeaders._contentLength;
+ _persistentConnection = initialHeaders._persistentConnection;
+ _chunkedTransferEncoding = initialHeaders._chunkedTransferEncoding;
+ _host = initialHeaders._host;
+ _port = initialHeaders._port;
+ }
+ if (protocolVersion == "1.0") {
+ _persistentConnection = false;
+ _chunkedTransferEncoding = false;
+ }
+ }
+
+ List<String> operator [](String name) => _headers[name.toLowerCase()];
+
+ String value(String name) {
+ name = name.toLowerCase();
+ List<String> values = _headers[name];
+ if (values == null) return null;
+ if (values.length > 1) {
+ throw new HttpException("More than one value for header $name");
+ }
+ return values[0];
+ }
+
+ void add(String name, value) {
+ _checkMutable();
+ _addAll(_validateField(name), value);
+ }
+
+ void _addAll(String name, value) {
+ assert(name == _validateField(name));
+ if (value is Iterable) {
+ for (var v in value) {
+ _add(name, _validateValue(v));
+ }
+ } else {
+ _add(name, _validateValue(value));
+ }
+ }
+
+ void set(String name, Object value) {
+ _checkMutable();
+ name = _validateField(name);
+ _headers.remove(name);
+ if (name == HttpHeaders.transferEncodingHeader) {
+ _chunkedTransferEncoding = false;
+ }
+ _addAll(name, value);
+ }
+
+ void remove(String name, Object value) {
+ _checkMutable();
+ name = _validateField(name);
+ value = _validateValue(value);
+ List<String> values = _headers[name];
+ if (values != null) {
+ int index = values.indexOf(value);
+ if (index != -1) {
+ values.removeRange(index, index + 1);
+ }
+ if (values.length == 0) _headers.remove(name);
+ }
+ if (name == HttpHeaders.transferEncodingHeader && value == "chunked") {
+ _chunkedTransferEncoding = false;
+ }
+ }
+
+ void removeAll(String name) {
+ _checkMutable();
+ name = _validateField(name);
+ _headers.remove(name);
+ }
+
+ void forEach(void f(String name, List<String> values)) {
+ _headers.forEach(f);
+ }
+
+ void noFolding(String name) {
+ if (_noFoldingHeaders == null) _noFoldingHeaders = new List<String>();
+ _noFoldingHeaders.add(name);
+ }
+
+ bool get persistentConnection => _persistentConnection;
+
+ void set persistentConnection(bool persistentConnection) {
+ _checkMutable();
+ if (persistentConnection == _persistentConnection) return;
+ if (persistentConnection) {
+ if (protocolVersion == "1.1") {
+ remove(HttpHeaders.connectionHeader, "close");
+ } else {
+ if (_contentLength == -1) {
+ throw new HttpException(
+ "Trying to set 'Connection: Keep-Alive' on HTTP 1.0 headers with "
+ "no ContentLength");
+ }
+ add(HttpHeaders.connectionHeader, "keep-alive");
+ }
+ } else {
+ if (protocolVersion == "1.1") {
+ add(HttpHeaders.connectionHeader, "close");
+ } else {
+ remove(HttpHeaders.connectionHeader, "keep-alive");
+ }
+ }
+ _persistentConnection = persistentConnection;
+ }
+
+ int get contentLength => _contentLength;
+
+ void set contentLength(int contentLength) {
+ _checkMutable();
+ if (protocolVersion == "1.0" &&
+ persistentConnection &&
+ contentLength == -1) {
+ throw new HttpException(
+ "Trying to clear ContentLength on HTTP 1.0 headers with "
+ "'Connection: Keep-Alive' set");
+ }
+ if (_contentLength == contentLength) return;
+ _contentLength = contentLength;
+ if (_contentLength >= 0) {
+ if (chunkedTransferEncoding) chunkedTransferEncoding = false;
+ _set(HttpHeaders.contentLengthHeader, contentLength.toString());
+ } else {
+ removeAll(HttpHeaders.contentLengthHeader);
+ if (protocolVersion == "1.1") {
+ chunkedTransferEncoding = true;
+ }
+ }
+ }
+
+ bool get chunkedTransferEncoding => _chunkedTransferEncoding;
+
+ void set chunkedTransferEncoding(bool chunkedTransferEncoding) {
+ _checkMutable();
+ if (chunkedTransferEncoding && protocolVersion == "1.0") {
+ throw new HttpException(
+ "Trying to set 'Transfer-Encoding: Chunked' on HTTP 1.0 headers");
+ }
+ if (chunkedTransferEncoding == _chunkedTransferEncoding) return;
+ if (chunkedTransferEncoding) {
+ List<String> values = _headers[HttpHeaders.transferEncodingHeader];
+ if ((values == null || values.last != "chunked")) {
+ // Headers does not specify chunked encoding - add it if set.
+ _addValue(HttpHeaders.transferEncodingHeader, "chunked");
+ }
+ contentLength = -1;
+ } else {
+ // Headers does specify chunked encoding - remove it if not set.
+ remove(HttpHeaders.transferEncodingHeader, "chunked");
+ }
+ _chunkedTransferEncoding = chunkedTransferEncoding;
+ }
+
+ String get host => _host;
+
+ void set host(String host) {
+ _checkMutable();
+ _host = host;
+ _updateHostHeader();
+ }
+
+ int get port => _port;
+
+ void set port(int port) {
+ _checkMutable();
+ _port = port;
+ _updateHostHeader();
+ }
+
+ DateTime get ifModifiedSince {
+ List<String> values = _headers[HttpHeaders.ifModifiedSinceHeader];
+ if (values != null) {
+ try {
+ return HttpDate.parse(values[0]);
+ } on Exception catch (e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ void set ifModifiedSince(DateTime ifModifiedSince) {
+ _checkMutable();
+ // Format "ifModifiedSince" header with date in Greenwich Mean Time (GMT).
+ String formatted = HttpDate.format(ifModifiedSince.toUtc());
+ _set(HttpHeaders.ifModifiedSinceHeader, formatted);
+ }
+
+ DateTime get date {
+ List<String> values = _headers[HttpHeaders.dateHeader];
+ if (values != null) {
+ try {
+ return HttpDate.parse(values[0]);
+ } on Exception catch (e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ void set date(DateTime date) {
+ _checkMutable();
+ // Format "DateTime" header with date in Greenwich Mean Time (GMT).
+ String formatted = HttpDate.format(date.toUtc());
+ _set("date", formatted);
+ }
+
+ DateTime get expires {
+ List<String> values = _headers[HttpHeaders.expiresHeader];
+ if (values != null) {
+ try {
+ return HttpDate.parse(values[0]);
+ } on Exception catch (e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ void set expires(DateTime expires) {
+ _checkMutable();
+ // Format "Expires" header with date in Greenwich Mean Time (GMT).
+ String formatted = HttpDate.format(expires.toUtc());
+ _set(HttpHeaders.expiresHeader, formatted);
+ }
+
+ ContentType get contentType {
+ var values = _headers["content-type"];
+ if (values != null) {
+ return ContentType.parse(values[0]);
+ } else {
+ return null;
+ }
+ }
+
+ void set contentType(ContentType contentType) {
+ _checkMutable();
+ _set(HttpHeaders.contentTypeHeader, contentType.toString());
+ }
+
+ void clear() {
+ _checkMutable();
+ _headers.clear();
+ _contentLength = -1;
+ _persistentConnection = true;
+ _chunkedTransferEncoding = false;
+ _host = null;
+ _port = null;
+ }
+
+ // [name] must be a lower-case version of the name.
+ void _add(String name, value) {
+ assert(name == _validateField(name));
+ // Use the length as index on what method to call. This is notable
+ // faster than computing hash and looking up in a hash-map.
+ switch (name.length) {
+ case 4:
+ if (HttpHeaders.dateHeader == name) {
+ _addDate(name, value);
+ return;
+ }
+ if (HttpHeaders.hostHeader == name) {
+ _addHost(name, value);
+ return;
+ }
+ break;
+ case 7:
+ if (HttpHeaders.expiresHeader == name) {
+ _addExpires(name, value);
+ return;
+ }
+ break;
+ case 10:
+ if (HttpHeaders.connectionHeader == name) {
+ _addConnection(name, value);
+ return;
+ }
+ break;
+ case 12:
+ if (HttpHeaders.contentTypeHeader == name) {
+ _addContentType(name, value);
+ return;
+ }
+ break;
+ case 14:
+ if (HttpHeaders.contentLengthHeader == name) {
+ _addContentLength(name, value);
+ return;
+ }
+ break;
+ case 17:
+ if (HttpHeaders.transferEncodingHeader == name) {
+ _addTransferEncoding(name, value);
+ return;
+ }
+ if (HttpHeaders.ifModifiedSinceHeader == name) {
+ _addIfModifiedSince(name, value);
+ return;
+ }
+ }
+ _addValue(name, value);
+ }
+
+ void _addContentLength(String name, value) {
+ if (value is int) {
+ contentLength = value;
+ } else if (value is String) {
+ contentLength = int.parse(value);
+ } else {
+ throw new HttpException("Unexpected type for header named $name");
+ }
+ }
+
+ void _addTransferEncoding(String name, value) {
+ if (value == "chunked") {
+ chunkedTransferEncoding = true;
+ } else {
+ _addValue(HttpHeaders.transferEncodingHeader, value);
+ }
+ }
+
+ void _addDate(String name, value) {
+ if (value is DateTime) {
+ date = value;
+ } else if (value is String) {
+ _set(HttpHeaders.dateHeader, value);
+ } else {
+ throw new HttpException("Unexpected type for header named $name");
+ }
+ }
+
+ void _addExpires(String name, value) {
+ if (value is DateTime) {
+ expires = value;
+ } else if (value is String) {
+ _set(HttpHeaders.expiresHeader, value);
+ } else {
+ throw new HttpException("Unexpected type for header named $name");
+ }
+ }
+
+ void _addIfModifiedSince(String name, value) {
+ if (value is DateTime) {
+ ifModifiedSince = value;
+ } else if (value is String) {
+ _set(HttpHeaders.ifModifiedSinceHeader, value);
+ } else {
+ throw new HttpException("Unexpected type for header named $name");
+ }
+ }
+
+ void _addHost(String name, value) {
+ if (value is String) {
+ int pos = value.indexOf(":");
+ if (pos == -1) {
+ _host = value;
+ _port = HttpClient.defaultHttpPort;
+ } else {
+ if (pos > 0) {
+ _host = value.substring(0, pos);
+ } else {
+ _host = null;
+ }
+ if (pos + 1 == value.length) {
+ _port = HttpClient.defaultHttpPort;
+ } else {
+ try {
+ _port = int.parse(value.substring(pos + 1));
+ } on FormatException catch (e) {
+ _port = null;
+ }
+ }
+ }
+ _set(HttpHeaders.hostHeader, value);
+ } else {
+ throw new HttpException("Unexpected type for header named $name");
+ }
+ }
+
+ void _addConnection(String name, value) {
+ var lowerCaseValue = value.toLowerCase();
+ if (lowerCaseValue == 'close') {
+ _persistentConnection = false;
+ } else if (lowerCaseValue == 'keep-alive') {
+ _persistentConnection = true;
+ }
+ _addValue(name, value);
+ }
+
+ void _addContentType(String name, value) {
+ _set(HttpHeaders.contentTypeHeader, value);
+ }
+
+ void _addValue(String name, Object value) {
+ List<String> values = _headers[name];
+ if (values == null) {
+ values = new List<String>();
+ _headers[name] = values;
+ }
+ if (value is DateTime) {
+ values.add(HttpDate.format(value));
+ } else if (value is String) {
+ values.add(value);
+ } else {
+ values.add(_validateValue(value.toString()));
+ }
+ }
+
+ void _set(String name, String value) {
+ assert(name == _validateField(name));
+ List<String> values = new List<String>();
+ _headers[name] = values;
+ values.add(value);
+ }
+
+ _checkMutable() {
+ if (!_mutable) throw new HttpException("HTTP headers are not mutable");
+ }
+
+ _updateHostHeader() {
+ bool defaultPort = _port == null || _port == _defaultPortForScheme;
+ _set("host", defaultPort ? host : "$host:$_port");
+ }
+
+ _foldHeader(String name) {
+ if (name == HttpHeaders.setCookieHeader ||
+ (_noFoldingHeaders != null && _noFoldingHeaders.indexOf(name) != -1)) {
+ return false;
+ }
+ return true;
+ }
+
+ void _finalize() {
+ _mutable = false;
+ }
+
+ void _build(BytesBuilder builder) {
+ for (String name in _headers.keys) {
+ List<String> values = _headers[name];
+ bool fold = _foldHeader(name);
+ var nameData = name.codeUnits;
+ builder.add(nameData);
+ builder.addByte(_CharCode.COLON);
+ builder.addByte(_CharCode.SP);
+ for (int i = 0; i < values.length; i++) {
+ if (i > 0) {
+ if (fold) {
+ builder.addByte(_CharCode.COMMA);
+ builder.addByte(_CharCode.SP);
+ } else {
+ builder.addByte(_CharCode.CR);
+ builder.addByte(_CharCode.LF);
+ builder.add(nameData);
+ builder.addByte(_CharCode.COLON);
+ builder.addByte(_CharCode.SP);
+ }
+ }
+ builder.add(values[i].codeUnits);
+ }
+ builder.addByte(_CharCode.CR);
+ builder.addByte(_CharCode.LF);
+ }
+ }
+
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ _headers.forEach((String name, List<String> values) {
+ sb..write(name)..write(": ");
+ bool fold = _foldHeader(name);
+ for (int i = 0; i < values.length; i++) {
+ if (i > 0) {
+ if (fold) {
+ sb.write(", ");
+ } else {
+ sb..write("\n")..write(name)..write(": ");
+ }
+ }
+ sb.write(values[i]);
+ }
+ sb.write("\n");
+ });
+ return sb.toString();
+ }
+
+ List<Cookie> _parseCookies() {
+ // Parse a Cookie header value according to the rules in RFC 6265.
+ var cookies = new List<Cookie>();
+ void parseCookieString(String s) {
+ int index = 0;
+
+ bool done() => index == -1 || index == s.length;
+
+ void skipWS() {
+ while (!done()) {
+ if (s[index] != " " && s[index] != "\t") return;
+ index++;
+ }
+ }
+
+ String parseName() {
+ int start = index;
+ while (!done()) {
+ if (s[index] == " " || s[index] == "\t" || s[index] == "=") break;
+ index++;
+ }
+ return s.substring(start, index);
+ }
+
+ String parseValue() {
+ int start = index;
+ while (!done()) {
+ if (s[index] == " " || s[index] == "\t" || s[index] == ";") break;
+ index++;
+ }
+ return s.substring(start, index);
+ }
+
+ bool expect(String expected) {
+ if (done()) return false;
+ if (s[index] != expected) return false;
+ index++;
+ return true;
+ }
+
+ while (!done()) {
+ skipWS();
+ if (done()) return;
+ String name = parseName();
+ skipWS();
+ if (!expect("=")) {
+ index = s.indexOf(';', index);
+ continue;
+ }
+ skipWS();
+ String value = parseValue();
+ try {
+ cookies.add(new _Cookie(name, value));
+ } catch (_) {
+ // Skip it, invalid cookie data.
+ }
+ skipWS();
+ if (done()) return;
+ if (!expect(";")) {
+ index = s.indexOf(';', index);
+ continue;
+ }
+ }
+ }
+
+ List<String> values = _headers[HttpHeaders.cookieHeader];
+ if (values != null) {
+ values.forEach((headerValue) => parseCookieString(headerValue));
+ }
+ return cookies;
+ }
+
+ static String _validateField(String field) {
+ for (var i = 0; i < field.length; i++) {
+ if (!_HttpParser._isTokenChar(field.codeUnitAt(i))) {
+ throw new FormatException(
+ "Invalid HTTP header field name: ${json.encode(field)}");
+ }
+ }
+ return field.toLowerCase();
+ }
+
+ static _validateValue(value) {
+ if (value is! String) return value;
+ for (var i = 0; i < value.length; i++) {
+ if (!_HttpParser._isValueChar(value.codeUnitAt(i))) {
+ throw new FormatException(
+ "Invalid HTTP header field value: ${json.encode(value)}");
+ }
+ }
+ return value;
+ }
+}
+
+class _HeaderValue implements HeaderValue {
+ String _value;
+ Map<String, String> _parameters;
+ Map<String, String> _unmodifiableParameters;
+
+ _HeaderValue([this._value = "", Map<String, String> parameters]) {
+ if (parameters != null) {
+ _parameters = new HashMap<String, String>.from(parameters);
+ }
+ }
+
+ static _HeaderValue parse(String value,
+ {parameterSeparator: ";",
+ valueSeparator: null,
+ preserveBackslash: false}) {
+ // Parse the string.
+ var result = new _HeaderValue();
+ result._parse(value, parameterSeparator, valueSeparator, preserveBackslash);
+ return result;
+ }
+
+ String get value => _value;
+
+ void _ensureParameters() {
+ if (_parameters == null) {
+ _parameters = new HashMap<String, String>();
+ }
+ }
+
+ Map<String, String> get parameters {
+ _ensureParameters();
+ if (_unmodifiableParameters == null) {
+ _unmodifiableParameters = new UnmodifiableMapView(_parameters);
+ }
+ return _unmodifiableParameters;
+ }
+
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.write(_value);
+ if (parameters != null && parameters.length > 0) {
+ _parameters.forEach((String name, String value) {
+ sb..write("; ")..write(name)..write("=")..write(value);
+ });
+ }
+ return sb.toString();
+ }
+
+ void _parse(String s, String parameterSeparator, String valueSeparator,
+ bool preserveBackslash) {
+ int index = 0;
+
+ bool done() => index == s.length;
+
+ void skipWS() {
+ while (!done()) {
+ if (s[index] != " " && s[index] != "\t") return;
+ index++;
+ }
+ }
+
+ String parseValue() {
+ int start = index;
+ while (!done()) {
+ if (s[index] == " " ||
+ s[index] == "\t" ||
+ s[index] == valueSeparator ||
+ s[index] == parameterSeparator) break;
+ index++;
+ }
+ return s.substring(start, index);
+ }
+
+ void expect(String expected) {
+ if (done() || s[index] != expected) {
+ throw new HttpException("Failed to parse header value");
+ }
+ index++;
+ }
+
+ void maybeExpect(String expected) {
+ if (s[index] == expected) index++;
+ }
+
+ void parseParameters() {
+ var parameters = new HashMap<String, String>();
+ _parameters = new UnmodifiableMapView(parameters);
+
+ String parseParameterName() {
+ int start = index;
+ while (!done()) {
+ if (s[index] == " " ||
+ s[index] == "\t" ||
+ s[index] == "=" ||
+ s[index] == parameterSeparator ||
+ s[index] == valueSeparator) break;
+ index++;
+ }
+ return s.substring(start, index).toLowerCase();
+ }
+
+ String parseParameterValue() {
+ if (!done() && s[index] == "\"") {
+ // Parse quoted value.
+ StringBuffer sb = new StringBuffer();
+ index++;
+ while (!done()) {
+ if (s[index] == "\\") {
+ if (index + 1 == s.length) {
+ throw new HttpException("Failed to parse header value");
+ }
+ if (preserveBackslash && s[index + 1] != "\"") {
+ sb.write(s[index]);
+ }
+ index++;
+ } else if (s[index] == "\"") {
+ index++;
+ break;
+ }
+ sb.write(s[index]);
+ index++;
+ }
+ return sb.toString();
+ } else {
+ // Parse non-quoted value.
+ var val = parseValue();
+ return val == "" ? null : val;
+ }
+ }
+
+ while (!done()) {
+ skipWS();
+ if (done()) return;
+ String name = parseParameterName();
+ skipWS();
+ if (done()) {
+ parameters[name] = null;
+ return;
+ }
+ maybeExpect("=");
+ skipWS();
+ if (done()) {
+ parameters[name] = null;
+ return;
+ }
+ String value = parseParameterValue();
+ if (name == 'charset' && this is _ContentType && value != null) {
+ // Charset parameter of ContentTypes are always lower-case.
+ value = value.toLowerCase();
+ }
+ parameters[name] = value;
+ skipWS();
+ if (done()) return;
+ // TODO: Implement support for multi-valued parameters.
+ if (s[index] == valueSeparator) return;
+ expect(parameterSeparator);
+ }
+ }
+
+ skipWS();
+ _value = parseValue();
+ skipWS();
+ if (done()) return;
+ maybeExpect(parameterSeparator);
+ parseParameters();
+ }
+}
+
+class _ContentType extends _HeaderValue implements ContentType {
+ String _primaryType = "";
+ String _subType = "";
+
+ _ContentType(String primaryType, String subType, String charset,
+ Map<String, String> parameters)
+ : _primaryType = primaryType,
+ _subType = subType,
+ super("") {
+ if (_primaryType == null) _primaryType = "";
+ if (_subType == null) _subType = "";
+ _value = "$_primaryType/$_subType";
+ if (parameters != null) {
+ _ensureParameters();
+ parameters.forEach((String key, String value) {
+ String lowerCaseKey = key.toLowerCase();
+ if (lowerCaseKey == "charset") {
+ value = value.toLowerCase();
+ }
+ this._parameters[lowerCaseKey] = value;
+ });
+ }
+ if (charset != null) {
+ _ensureParameters();
+ this._parameters["charset"] = charset.toLowerCase();
+ }
+ }
+
+ _ContentType._();
+
+ static _ContentType parse(String value) {
+ var result = new _ContentType._();
+ result._parse(value, ";", null, false);
+ int index = result._value.indexOf("/");
+ if (index == -1 || index == (result._value.length - 1)) {
+ result._primaryType = result._value.trim().toLowerCase();
+ result._subType = "";
+ } else {
+ result._primaryType =
+ result._value.substring(0, index).trim().toLowerCase();
+ result._subType = result._value.substring(index + 1).trim().toLowerCase();
+ }
+ return result;
+ }
+
+ String get mimeType => '$primaryType/$subType';
+
+ String get primaryType => _primaryType;
+
+ String get subType => _subType;
+
+ String get charset => parameters["charset"];
+}
+
+class _Cookie implements Cookie {
+ String _name;
+ String _value;
+ DateTime expires;
+ int maxAge;
+ String domain;
+ String path;
+ bool httpOnly = false;
+ bool secure = false;
+
+ _Cookie(String name, String value)
+ : _name = _validateName(name),
+ _value = _validateValue(value),
+ httpOnly = true;
+
+ String get name => _name;
+ String get value => _value;
+
+ set name(String newName) {
+ _validateName(newName);
+ _name = newName;
+ }
+
+ set value(String newValue) {
+ _validateValue(newValue);
+ _value = newValue;
+ }
+
+ _Cookie.fromSetCookieValue(String value) {
+ // Parse the 'set-cookie' header value.
+ _parseSetCookieValue(value);
+ }
+
+ // Parse a 'set-cookie' header value according to the rules in RFC 6265.
+ void _parseSetCookieValue(String s) {
+ int index = 0;
+
+ bool done() => index == s.length;
+
+ String parseName() {
+ int start = index;
+ while (!done()) {
+ if (s[index] == "=") break;
+ index++;
+ }
+ return s.substring(start, index).trim();
+ }
+
+ String parseValue() {
+ int start = index;
+ while (!done()) {
+ if (s[index] == ";") break;
+ index++;
+ }
+ return s.substring(start, index).trim();
+ }
+
+ void expect(String expected) {
+ if (done()) throw new HttpException("Failed to parse header value [$s]");
+ if (s[index] != expected) {
+ throw new HttpException("Failed to parse header value [$s]");
+ }
+ index++;
+ }
+
+ void parseAttributes() {
+ String parseAttributeName() {
+ int start = index;
+ while (!done()) {
+ if (s[index] == "=" || s[index] == ";") break;
+ index++;
+ }
+ return s.substring(start, index).trim().toLowerCase();
+ }
+
+ String parseAttributeValue() {
+ int start = index;
+ while (!done()) {
+ if (s[index] == ";") break;
+ index++;
+ }
+ return s.substring(start, index).trim().toLowerCase();
+ }
+
+ while (!done()) {
+ String name = parseAttributeName();
+ String value = "";
+ if (!done() && s[index] == "=") {
+ index++; // Skip the = character.
+ value = parseAttributeValue();
+ }
+ if (name == "expires") {
+ expires = HttpDate._parseCookieDate(value);
+ } else if (name == "max-age") {
+ maxAge = int.parse(value);
+ } else if (name == "domain") {
+ domain = value;
+ } else if (name == "path") {
+ path = value;
+ } else if (name == "httponly") {
+ httpOnly = true;
+ } else if (name == "secure") {
+ secure = true;
+ }
+ if (!done()) index++; // Skip the ; character
+ }
+ }
+
+ _name = _validateName(parseName());
+ if (done() || _name.length == 0) {
+ throw new HttpException("Failed to parse header value [$s]");
+ }
+ index++; // Skip the = character.
+ _value = _validateValue(parseValue());
+ if (done()) return;
+ index++; // Skip the ; character.
+ parseAttributes();
+ }
+
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb..write(_name)..write("=")..write(_value);
+ if (expires != null) {
+ sb..write("; Expires=")..write(HttpDate.format(expires));
+ }
+ if (maxAge != null) {
+ sb..write("; Max-Age=")..write(maxAge);
+ }
+ if (domain != null) {
+ sb..write("; Domain=")..write(domain);
+ }
+ if (path != null) {
+ sb..write("; Path=")..write(path);
+ }
+ if (secure) sb.write("; Secure");
+ if (httpOnly) sb.write("; HttpOnly");
+ return sb.toString();
+ }
+
+ static String _validateName(String newName) {
+ const separators = const [
+ "(",
+ ")",
+ "<",
+ ">",
+ "@",
+ ",",
+ ";",
+ ":",
+ "\\",
+ '"',
+ "/",
+ "[",
+ "]",
+ "?",
+ "=",
+ "{",
+ "}"
+ ];
+ if (newName == null) throw new ArgumentError.notNull("name");
+ for (int i = 0; i < newName.length; i++) {
+ int codeUnit = newName.codeUnits[i];
+ if (codeUnit <= 32 ||
+ codeUnit >= 127 ||
+ separators.indexOf(newName[i]) >= 0) {
+ throw new FormatException(
+ "Invalid character in cookie name, code unit: '$codeUnit'",
+ newName,
+ i);
+ }
+ }
+ return newName;
+ }
+
+ static String _validateValue(String newValue) {
+ if (newValue == null) throw new ArgumentError.notNull("value");
+ // Per RFC 6265, consider surrounding "" as part of the value, but otherwise
+ // double quotes are not allowed.
+ int start = 0;
+ int end = newValue.length;
+ if (2 <= newValue.length &&
+ newValue.codeUnits[start] == 0x22 &&
+ newValue.codeUnits[end - 1] == 0x22) {
+ start++;
+ end--;
+ }
+
+ for (int i = start; i < end; i++) {
+ int codeUnit = newValue.codeUnits[i];
+ if (!(codeUnit == 0x21 ||
+ (codeUnit >= 0x23 && codeUnit <= 0x2B) ||
+ (codeUnit >= 0x2D && codeUnit <= 0x3A) ||
+ (codeUnit >= 0x3C && codeUnit <= 0x5B) ||
+ (codeUnit >= 0x5D && codeUnit <= 0x7E))) {
+ throw new FormatException(
+ "Invalid character in cookie value, code unit: '$codeUnit'",
+ newValue,
+ i);
+ }
+ }
+ return newValue;
+ }
+}
diff --git a/sdk_nnbd/lib/_http/http_impl.dart b/sdk_nnbd/lib/_http/http_impl.dart
new file mode 100644
index 0000000..cdf2412
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http_impl.dart
@@ -0,0 +1,3237 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+int _nextServiceId = 1;
+
+// TODO(ajohnsen): Use other way of getting a unique id.
+abstract class _ServiceObject {
+ int __serviceId = 0;
+ int get _serviceId {
+ if (__serviceId == 0) __serviceId = _nextServiceId++;
+ return __serviceId;
+ }
+
+ Map _toJSON(bool ref);
+
+ String get _servicePath => "$_serviceTypePath/$_serviceId";
+
+ String get _serviceTypePath;
+
+ String get _serviceTypeName;
+
+ String _serviceType(bool ref) {
+ if (ref) return "@$_serviceTypeName";
+ return _serviceTypeName;
+ }
+}
+
+class _CopyingBytesBuilder implements BytesBuilder {
+ // Start with 1024 bytes.
+ static const int _INIT_SIZE = 1024;
+
+ static final _emptyList = new Uint8List(0);
+
+ int _length = 0;
+ Uint8List _buffer;
+
+ _CopyingBytesBuilder([int initialCapacity = 0])
+ : _buffer = (initialCapacity <= 0)
+ ? _emptyList
+ : new Uint8List(_pow2roundup(initialCapacity));
+
+ void add(List<int> bytes) {
+ int bytesLength = bytes.length;
+ if (bytesLength == 0) return;
+ int required = _length + bytesLength;
+ if (_buffer.length < required) {
+ _grow(required);
+ }
+ assert(_buffer.length >= required);
+ if (bytes is Uint8List) {
+ _buffer.setRange(_length, required, bytes);
+ } else {
+ for (int i = 0; i < bytesLength; i++) {
+ _buffer[_length + i] = bytes[i];
+ }
+ }
+ _length = required;
+ }
+
+ void addByte(int byte) {
+ if (_buffer.length == _length) {
+ // The grow algorithm always at least doubles.
+ // If we added one to _length it would quadruple unnecessarily.
+ _grow(_length);
+ }
+ assert(_buffer.length > _length);
+ _buffer[_length] = byte;
+ _length++;
+ }
+
+ void _grow(int required) {
+ // We will create a list in the range of 2-4 times larger than
+ // required.
+ int newSize = required * 2;
+ if (newSize < _INIT_SIZE) {
+ newSize = _INIT_SIZE;
+ } else {
+ newSize = _pow2roundup(newSize);
+ }
+ var newBuffer = new Uint8List(newSize);
+ newBuffer.setRange(0, _buffer.length, _buffer);
+ _buffer = newBuffer;
+ }
+
+ Uint8List takeBytes() {
+ if (_length == 0) return _emptyList;
+ var buffer = new Uint8List.view(_buffer.buffer, 0, _length);
+ clear();
+ return buffer;
+ }
+
+ Uint8List toBytes() {
+ if (_length == 0) return _emptyList;
+ return new Uint8List.fromList(
+ new Uint8List.view(_buffer.buffer, 0, _length));
+ }
+
+ int get length => _length;
+
+ bool get isEmpty => _length == 0;
+
+ bool get isNotEmpty => _length != 0;
+
+ void clear() {
+ _length = 0;
+ _buffer = _emptyList;
+ }
+
+ static int _pow2roundup(int x) {
+ assert(x > 0);
+ --x;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ return x + 1;
+ }
+}
+
+const int _OUTGOING_BUFFER_SIZE = 8 * 1024;
+
+typedef void _BytesConsumer(List<int> bytes);
+
+class _HttpIncoming extends Stream<Uint8List> {
+ final int _transferLength;
+ final Completer _dataCompleter = new Completer();
+ Stream<Uint8List> _stream;
+
+ bool fullBodyRead = false;
+
+ // Common properties.
+ final _HttpHeaders headers;
+ bool upgraded = false;
+
+ // ClientResponse properties.
+ int statusCode;
+ String reasonPhrase;
+
+ // Request properties.
+ String method;
+ Uri uri;
+
+ bool hasSubscriber = false;
+
+ // The transfer length if the length of the message body as it
+ // appears in the message (RFC 2616 section 4.4). This can be -1 if
+ // the length of the massage body is not known due to transfer
+ // codings.
+ int get transferLength => _transferLength;
+
+ _HttpIncoming(this.headers, this._transferLength, this._stream);
+
+ StreamSubscription<Uint8List> listen(void onData(Uint8List event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ hasSubscriber = true;
+ return _stream.handleError((error) {
+ throw new HttpException(error.message, uri: uri);
+ }).listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ // Is completed once all data have been received.
+ Future get dataDone => _dataCompleter.future;
+
+ void close(bool closing) {
+ fullBodyRead = true;
+ hasSubscriber = true;
+ _dataCompleter.complete(closing);
+ }
+}
+
+abstract class _HttpInboundMessageListInt extends Stream<List<int>> {
+ final _HttpIncoming _incoming;
+ List<Cookie> _cookies;
+
+ _HttpInboundMessageListInt(this._incoming);
+
+ List<Cookie> get cookies {
+ if (_cookies != null) return _cookies;
+ return _cookies = headers._parseCookies();
+ }
+
+ _HttpHeaders get headers => _incoming.headers;
+ String get protocolVersion => headers.protocolVersion;
+ int get contentLength => headers.contentLength;
+ bool get persistentConnection => headers.persistentConnection;
+}
+
+abstract class _HttpInboundMessage extends Stream<Uint8List> {
+ final _HttpIncoming _incoming;
+ List<Cookie> _cookies;
+
+ _HttpInboundMessage(this._incoming);
+
+ List<Cookie> get cookies {
+ if (_cookies != null) return _cookies;
+ return _cookies = headers._parseCookies();
+ }
+
+ _HttpHeaders get headers => _incoming.headers;
+ String get protocolVersion => headers.protocolVersion;
+ int get contentLength => headers.contentLength;
+ bool get persistentConnection => headers.persistentConnection;
+}
+
+class _HttpRequest extends _HttpInboundMessage implements HttpRequest {
+ final HttpResponse response;
+
+ final _HttpServer _httpServer;
+
+ final _HttpConnection _httpConnection;
+
+ _HttpSession _session;
+
+ Uri _requestedUri;
+
+ _HttpRequest(this.response, _HttpIncoming _incoming, this._httpServer,
+ this._httpConnection)
+ : super(_incoming) {
+ if (headers.protocolVersion == "1.1") {
+ response.headers
+ ..chunkedTransferEncoding = true
+ ..persistentConnection = headers.persistentConnection;
+ }
+
+ if (_httpServer._sessionManagerInstance != null) {
+ // Map to session if exists.
+ var sessionIds = cookies
+ .where((cookie) => cookie.name.toUpperCase() == _DART_SESSION_ID)
+ .map((cookie) => cookie.value);
+ for (var sessionId in sessionIds) {
+ _session = _httpServer._sessionManager.getSession(sessionId);
+ if (_session != null) {
+ _session._markSeen();
+ break;
+ }
+ }
+ }
+ }
+
+ StreamSubscription<Uint8List> listen(void onData(Uint8List event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ return _incoming.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ Uri get uri => _incoming.uri;
+
+ Uri get requestedUri {
+ if (_requestedUri == null) {
+ var proto = headers['x-forwarded-proto'];
+ var scheme = proto != null
+ ? proto.first
+ : _httpConnection._socket is SecureSocket ? "https" : "http";
+ var hostList = headers['x-forwarded-host'];
+ String host;
+ if (hostList != null) {
+ host = hostList.first;
+ } else {
+ hostList = headers['host'];
+ if (hostList != null) {
+ host = hostList.first;
+ } else {
+ host = "${_httpServer.address.host}:${_httpServer.port}";
+ }
+ }
+ _requestedUri = Uri.parse("$scheme://$host$uri");
+ }
+ return _requestedUri;
+ }
+
+ String get method => _incoming.method;
+
+ HttpSession get session {
+ if (_session != null) {
+ if (_session._destroyed) {
+ // It's destroyed, clear it.
+ _session = null;
+ // Create new session object by calling recursive.
+ return session;
+ }
+ // It's already mapped, use it.
+ return _session;
+ }
+ // Create session, store it in connection, and return.
+ return _session = _httpServer._sessionManager.createSession();
+ }
+
+ HttpConnectionInfo get connectionInfo => _httpConnection.connectionInfo;
+
+ X509Certificate get certificate {
+ var socket = _httpConnection._socket;
+ if (socket is SecureSocket) return socket.peerCertificate;
+ return null;
+ }
+}
+
+class _HttpClientResponse extends _HttpInboundMessageListInt
+ implements HttpClientResponse {
+ List<RedirectInfo> get redirects => _httpRequest._responseRedirects;
+
+ // The HttpClient this response belongs to.
+ final _HttpClient _httpClient;
+
+ // The HttpClientRequest of this response.
+ final _HttpClientRequest _httpRequest;
+
+ // The compression state of this response.
+ final HttpClientResponseCompressionState compressionState;
+
+ _HttpClientResponse(
+ _HttpIncoming _incoming, this._httpRequest, this._httpClient)
+ : compressionState = _getCompressionState(_httpClient, _incoming.headers),
+ super(_incoming) {
+ // Set uri for potential exceptions.
+ _incoming.uri = _httpRequest.uri;
+ }
+
+ static HttpClientResponseCompressionState _getCompressionState(
+ _HttpClient httpClient, _HttpHeaders headers) {
+ if (headers.value(HttpHeaders.contentEncodingHeader) == "gzip") {
+ return httpClient.autoUncompress
+ ? HttpClientResponseCompressionState.decompressed
+ : HttpClientResponseCompressionState.compressed;
+ } else {
+ return HttpClientResponseCompressionState.notCompressed;
+ }
+ }
+
+ int get statusCode => _incoming.statusCode;
+ String get reasonPhrase => _incoming.reasonPhrase;
+
+ X509Certificate get certificate {
+ var socket = _httpRequest._httpClientConnection._socket;
+ if (socket is SecureSocket) return socket.peerCertificate;
+ return null;
+ }
+
+ List<Cookie> get cookies {
+ if (_cookies != null) return _cookies;
+ _cookies = new List<Cookie>();
+ List<String> values = headers[HttpHeaders.setCookieHeader];
+ if (values != null) {
+ values.forEach((value) {
+ _cookies.add(new Cookie.fromSetCookieValue(value));
+ });
+ }
+ return _cookies;
+ }
+
+ bool get isRedirect {
+ if (_httpRequest.method == "GET" || _httpRequest.method == "HEAD") {
+ return statusCode == HttpStatus.movedPermanently ||
+ statusCode == HttpStatus.found ||
+ statusCode == HttpStatus.seeOther ||
+ statusCode == HttpStatus.temporaryRedirect;
+ } else if (_httpRequest.method == "POST") {
+ return statusCode == HttpStatus.seeOther;
+ }
+ return false;
+ }
+
+ Future<HttpClientResponse> redirect(
+ [String method, Uri url, bool followLoops]) {
+ if (method == null) {
+ // Set method as defined by RFC 2616 section 10.3.4.
+ if (statusCode == HttpStatus.seeOther && _httpRequest.method == "POST") {
+ method = "GET";
+ } else {
+ method = _httpRequest.method;
+ }
+ }
+ if (url == null) {
+ String location = headers.value(HttpHeaders.locationHeader);
+ if (location == null) {
+ throw new StateError("Response has no Location header for redirect");
+ }
+ url = Uri.parse(location);
+ }
+ if (followLoops != true) {
+ for (var redirect in redirects) {
+ if (redirect.location == url) {
+ return new Future.error(
+ new RedirectException("Redirect loop detected", redirects));
+ }
+ }
+ }
+ return _httpClient
+ ._openUrlFromRequest(method, url, _httpRequest)
+ .then((request) {
+ request._responseRedirects
+ ..addAll(this.redirects)
+ ..add(new _RedirectInfo(statusCode, method, url));
+ return request.close();
+ });
+ }
+
+ StreamSubscription<Uint8List> listen(void onData(Uint8List event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ if (_incoming.upgraded) {
+ // If upgraded, the connection is already 'removed' form the client.
+ // Since listening to upgraded data is 'bogus', simply close and
+ // return empty stream subscription.
+ _httpRequest._httpClientConnection.destroy();
+ return new Stream<Uint8List>.empty().listen(null, onDone: onDone);
+ }
+ Stream<Uint8List> stream = _incoming;
+ if (compressionState == HttpClientResponseCompressionState.decompressed) {
+ stream = stream
+ .cast<List<int>>()
+ .transform(gzip.decoder)
+ .transform(const _ToUint8List());
+ }
+ return stream.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ Future<Socket> detachSocket() {
+ _httpClient._connectionClosed(_httpRequest._httpClientConnection);
+ return _httpRequest._httpClientConnection.detachSocket();
+ }
+
+ HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo;
+
+ bool get _shouldAuthenticateProxy {
+ // Only try to authenticate if there is a challenge in the response.
+ List<String> challenge = headers[HttpHeaders.proxyAuthenticateHeader];
+ return statusCode == HttpStatus.proxyAuthenticationRequired &&
+ challenge != null &&
+ challenge.length == 1;
+ }
+
+ bool get _shouldAuthenticate {
+ // Only try to authenticate if there is a challenge in the response.
+ List<String> challenge = headers[HttpHeaders.wwwAuthenticateHeader];
+ return statusCode == HttpStatus.unauthorized &&
+ challenge != null &&
+ challenge.length == 1;
+ }
+
+ Future<HttpClientResponse> _authenticate(bool proxyAuth) {
+ Future<HttpClientResponse> retry() {
+ // Drain body and retry.
+ return drain().then((_) {
+ return _httpClient
+ ._openUrlFromRequest(
+ _httpRequest.method, _httpRequest.uri, _httpRequest)
+ .then((request) => request.close());
+ });
+ }
+
+ List<String> authChallenge() {
+ return proxyAuth
+ ? headers[HttpHeaders.proxyAuthenticateHeader]
+ : headers[HttpHeaders.wwwAuthenticateHeader];
+ }
+
+ _Credentials findCredentials(_AuthenticationScheme scheme) {
+ return proxyAuth
+ ? _httpClient._findProxyCredentials(_httpRequest._proxy, scheme)
+ : _httpClient._findCredentials(_httpRequest.uri, scheme);
+ }
+
+ void removeCredentials(_Credentials cr) {
+ if (proxyAuth) {
+ _httpClient._removeProxyCredentials(cr);
+ } else {
+ _httpClient._removeCredentials(cr);
+ }
+ }
+
+ Future requestAuthentication(_AuthenticationScheme scheme, String realm) {
+ if (proxyAuth) {
+ if (_httpClient._authenticateProxy == null) {
+ return new Future.value(false);
+ }
+ var proxy = _httpRequest._proxy;
+ return _httpClient._authenticateProxy(
+ proxy.host, proxy.port, scheme.toString(), realm);
+ } else {
+ if (_httpClient._authenticate == null) {
+ return new Future.value(false);
+ }
+ return _httpClient._authenticate(
+ _httpRequest.uri, scheme.toString(), realm);
+ }
+ }
+
+ List<String> challenge = authChallenge();
+ assert(challenge != null || challenge.length == 1);
+ _HeaderValue header =
+ _HeaderValue.parse(challenge[0], parameterSeparator: ",");
+ _AuthenticationScheme scheme =
+ new _AuthenticationScheme.fromString(header.value);
+ String realm = header.parameters["realm"];
+
+ // See if any matching credentials are available.
+ _Credentials cr = findCredentials(scheme);
+ if (cr != null) {
+ // For basic authentication don't retry already used credentials
+ // as they must have already been added to the request causing
+ // this authenticate response.
+ if (cr.scheme == _AuthenticationScheme.BASIC && !cr.used) {
+ // Credentials where found, prepare for retrying the request.
+ return retry();
+ }
+
+ // Digest authentication only supports the MD5 algorithm.
+ if (cr.scheme == _AuthenticationScheme.DIGEST &&
+ (header.parameters["algorithm"] == null ||
+ header.parameters["algorithm"].toLowerCase() == "md5")) {
+ if (cr.nonce == null || cr.nonce == header.parameters["nonce"]) {
+ // If the nonce is not set then this is the first authenticate
+ // response for these credentials. Set up authentication state.
+ if (cr.nonce == null) {
+ cr
+ ..nonce = header.parameters["nonce"]
+ ..algorithm = "MD5"
+ ..qop = header.parameters["qop"]
+ ..nonceCount = 0;
+ }
+ // Credentials where found, prepare for retrying the request.
+ return retry();
+ } else if (header.parameters["stale"] != null &&
+ header.parameters["stale"].toLowerCase() == "true") {
+ // If stale is true retry with new nonce.
+ cr.nonce = header.parameters["nonce"];
+ // Credentials where found, prepare for retrying the request.
+ return retry();
+ }
+ }
+ }
+
+ // Ask for more credentials if none found or the one found has
+ // already been used. If it has already been used it must now be
+ // invalid and is removed.
+ if (cr != null) {
+ removeCredentials(cr);
+ cr = null;
+ }
+ return requestAuthentication(scheme, realm).then((credsAvailable) {
+ if (credsAvailable) {
+ cr = _httpClient._findCredentials(_httpRequest.uri, scheme);
+ return retry();
+ } else {
+ // No credentials available, complete with original response.
+ return this;
+ }
+ });
+ }
+}
+
+class _ToUint8List extends Converter<List<int>, Uint8List> {
+ const _ToUint8List();
+
+ Uint8List convert(List<int> input) => Uint8List.fromList(input);
+
+ Sink<List<int>> startChunkedConversion(Sink<Uint8List> sink) {
+ return _Uint8ListConversionSink(sink);
+ }
+}
+
+class _Uint8ListConversionSink implements Sink<List<int>> {
+ const _Uint8ListConversionSink(this._target);
+
+ final Sink<Uint8List> _target;
+
+ void add(List<int> data) {
+ _target.add(Uint8List.fromList(data));
+ }
+
+ void close() {
+ _target.close();
+ }
+}
+
+class _StreamSinkImpl<T> implements StreamSink<T> {
+ final StreamConsumer<T> _target;
+ final Completer _doneCompleter = new Completer();
+ StreamController<T> _controllerInstance;
+ Completer _controllerCompleter;
+ bool _isClosed = false;
+ bool _isBound = false;
+ bool _hasError = false;
+
+ _StreamSinkImpl(this._target);
+
+ void add(T data) {
+ if (_isClosed) {
+ throw StateError("StreamSink is closed");
+ }
+ _controller.add(data);
+ }
+
+ void addError(error, [StackTrace stackTrace]) {
+ if (_isClosed) {
+ throw StateError("StreamSink is closed");
+ }
+ _controller.addError(error, stackTrace);
+ }
+
+ Future addStream(Stream<T> stream) {
+ if (_isBound) {
+ throw new StateError("StreamSink is already bound to a stream");
+ }
+ _isBound = true;
+ if (_hasError) return done;
+ // Wait for any sync operations to complete.
+ Future targetAddStream() {
+ return _target.addStream(stream).whenComplete(() {
+ _isBound = false;
+ });
+ }
+
+ if (_controllerInstance == null) return targetAddStream();
+ var future = _controllerCompleter.future;
+ _controllerInstance.close();
+ return future.then((_) => targetAddStream());
+ }
+
+ Future flush() {
+ if (_isBound) {
+ throw new StateError("StreamSink is bound to a stream");
+ }
+ if (_controllerInstance == null) return new Future.value(this);
+ // Adding an empty stream-controller will return a future that will complete
+ // when all data is done.
+ _isBound = true;
+ var future = _controllerCompleter.future;
+ _controllerInstance.close();
+ return future.whenComplete(() {
+ _isBound = false;
+ });
+ }
+
+ Future close() {
+ if (_isBound) {
+ throw new StateError("StreamSink is bound to a stream");
+ }
+ if (!_isClosed) {
+ _isClosed = true;
+ if (_controllerInstance != null) {
+ _controllerInstance.close();
+ } else {
+ _closeTarget();
+ }
+ }
+ return done;
+ }
+
+ void _closeTarget() {
+ _target.close().then(_completeDoneValue, onError: _completeDoneError);
+ }
+
+ Future get done => _doneCompleter.future;
+
+ void _completeDoneValue(value) {
+ if (!_doneCompleter.isCompleted) {
+ _doneCompleter.complete(value);
+ }
+ }
+
+ void _completeDoneError(error, StackTrace stackTrace) {
+ if (!_doneCompleter.isCompleted) {
+ _hasError = true;
+ _doneCompleter.completeError(error, stackTrace);
+ }
+ }
+
+ StreamController<T> get _controller {
+ if (_isBound) {
+ throw new StateError("StreamSink is bound to a stream");
+ }
+ if (_isClosed) {
+ throw new StateError("StreamSink is closed");
+ }
+ if (_controllerInstance == null) {
+ _controllerInstance = new StreamController<T>(sync: true);
+ _controllerCompleter = new Completer();
+ _target.addStream(_controller.stream).then((_) {
+ if (_isBound) {
+ // A new stream takes over - forward values to that stream.
+ _controllerCompleter.complete(this);
+ _controllerCompleter = null;
+ _controllerInstance = null;
+ } else {
+ // No new stream, .close was called. Close _target.
+ _closeTarget();
+ }
+ }, onError: (error, stackTrace) {
+ if (_isBound) {
+ // A new stream takes over - forward errors to that stream.
+ _controllerCompleter.completeError(error, stackTrace);
+ _controllerCompleter = null;
+ _controllerInstance = null;
+ } else {
+ // No new stream. No need to close target, as it has already
+ // failed.
+ _completeDoneError(error, stackTrace);
+ }
+ });
+ }
+ return _controllerInstance;
+ }
+}
+
+class _IOSinkImpl extends _StreamSinkImpl<List<int>> implements IOSink {
+ Encoding _encoding;
+ bool _encodingMutable = true;
+
+ _IOSinkImpl(StreamConsumer<List<int>> target, this._encoding) : super(target);
+
+ Encoding get encoding => _encoding;
+
+ void set encoding(Encoding value) {
+ if (!_encodingMutable) {
+ throw new StateError("IOSink encoding is not mutable");
+ }
+ _encoding = value;
+ }
+
+ void write(Object obj) {
+ String string = '$obj';
+ if (string.isEmpty) return;
+ add(_encoding.encode(string));
+ }
+
+ void writeAll(Iterable objects, [String separator = ""]) {
+ Iterator iterator = objects.iterator;
+ if (!iterator.moveNext()) return;
+ if (separator.isEmpty) {
+ do {
+ write(iterator.current);
+ } while (iterator.moveNext());
+ } else {
+ write(iterator.current);
+ while (iterator.moveNext()) {
+ write(separator);
+ write(iterator.current);
+ }
+ }
+ }
+
+ void writeln([Object object = ""]) {
+ write(object);
+ write("\n");
+ }
+
+ void writeCharCode(int charCode) {
+ write(new String.fromCharCode(charCode));
+ }
+}
+
+abstract class _HttpOutboundMessage<T> extends _IOSinkImpl {
+ // Used to mark when the body should be written. This is used for HEAD
+ // requests and in error handling.
+ bool _encodingSet = false;
+
+ bool _bufferOutput = true;
+
+ final Uri _uri;
+ final _HttpOutgoing _outgoing;
+
+ final _HttpHeaders headers;
+
+ _HttpOutboundMessage(Uri uri, String protocolVersion, _HttpOutgoing outgoing,
+ {_HttpHeaders initialHeaders})
+ : _uri = uri,
+ headers = new _HttpHeaders(protocolVersion,
+ defaultPortForScheme: uri.scheme == 'https'
+ ? HttpClient.defaultHttpsPort
+ : HttpClient.defaultHttpPort,
+ initialHeaders: initialHeaders),
+ _outgoing = outgoing,
+ super(outgoing, null) {
+ _outgoing.outbound = this;
+ _encodingMutable = false;
+ }
+
+ int get contentLength => headers.contentLength;
+ void set contentLength(int contentLength) {
+ headers.contentLength = contentLength;
+ }
+
+ bool get persistentConnection => headers.persistentConnection;
+ void set persistentConnection(bool p) {
+ headers.persistentConnection = p;
+ }
+
+ bool get bufferOutput => _bufferOutput;
+ void set bufferOutput(bool bufferOutput) {
+ if (_outgoing.headersWritten) throw new StateError("Header already sent");
+ _bufferOutput = bufferOutput;
+ }
+
+ Encoding get encoding {
+ if (_encodingSet && _outgoing.headersWritten) {
+ return _encoding;
+ }
+ var charset;
+ if (headers.contentType != null && headers.contentType.charset != null) {
+ charset = headers.contentType.charset;
+ } else {
+ charset = "iso-8859-1";
+ }
+ return Encoding.getByName(charset);
+ }
+
+ void add(List<int> data) {
+ if (data.length == 0) return;
+ super.add(data);
+ }
+
+ void write(Object obj) {
+ if (!_encodingSet) {
+ _encoding = encoding;
+ _encodingSet = true;
+ }
+ super.write(obj);
+ }
+
+ void _writeHeader();
+
+ bool get _isConnectionClosed => false;
+}
+
+class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
+ implements HttpResponse {
+ int _statusCode = 200;
+ String _reasonPhrase;
+ List<Cookie> _cookies;
+ _HttpRequest _httpRequest;
+ Duration _deadline;
+ Timer _deadlineTimer;
+
+ _HttpResponse(Uri uri, String protocolVersion, _HttpOutgoing outgoing,
+ HttpHeaders defaultHeaders, String serverHeader)
+ : super(uri, protocolVersion, outgoing, initialHeaders: defaultHeaders) {
+ if (serverHeader != null) headers.set('server', serverHeader);
+ }
+
+ bool get _isConnectionClosed => _httpRequest._httpConnection._isClosing;
+
+ List<Cookie> get cookies {
+ if (_cookies == null) _cookies = new List<Cookie>();
+ return _cookies;
+ }
+
+ int get statusCode => _statusCode;
+ void set statusCode(int statusCode) {
+ if (_outgoing.headersWritten) throw new StateError("Header already sent");
+ _statusCode = statusCode;
+ }
+
+ String get reasonPhrase => _findReasonPhrase(statusCode);
+ void set reasonPhrase(String reasonPhrase) {
+ if (_outgoing.headersWritten) throw new StateError("Header already sent");
+ _reasonPhrase = reasonPhrase;
+ }
+
+ Future redirect(Uri location, {int status: HttpStatus.movedTemporarily}) {
+ if (_outgoing.headersWritten) throw new StateError("Header already sent");
+ statusCode = status;
+ headers.set("location", location.toString());
+ return close();
+ }
+
+ Future<Socket> detachSocket({bool writeHeaders: true}) {
+ if (_outgoing.headersWritten) throw new StateError("Headers already sent");
+ deadline = null; // Be sure to stop any deadline.
+ var future = _httpRequest._httpConnection.detachSocket();
+ if (writeHeaders) {
+ var headersFuture =
+ _outgoing.writeHeaders(drainRequest: false, setOutgoing: false);
+ assert(headersFuture == null);
+ } else {
+ // Imitate having written the headers.
+ _outgoing.headersWritten = true;
+ }
+ // Close connection so the socket is 'free'.
+ close();
+ done.catchError((_) {
+ // Catch any error on done, as they automatically will be
+ // propagated to the websocket.
+ });
+ return future;
+ }
+
+ HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo;
+
+ Duration get deadline => _deadline;
+
+ void set deadline(Duration d) {
+ if (_deadlineTimer != null) _deadlineTimer.cancel();
+ _deadline = d;
+
+ if (_deadline == null) return;
+ _deadlineTimer = new Timer(_deadline, () {
+ _httpRequest._httpConnection.destroy();
+ });
+ }
+
+ void _writeHeader() {
+ BytesBuilder buffer = new _CopyingBytesBuilder(_OUTGOING_BUFFER_SIZE);
+
+ // Write status line.
+ if (headers.protocolVersion == "1.1") {
+ buffer.add(_Const.HTTP11);
+ } else {
+ buffer.add(_Const.HTTP10);
+ }
+ buffer.addByte(_CharCode.SP);
+ buffer.add(statusCode.toString().codeUnits);
+ buffer.addByte(_CharCode.SP);
+ buffer.add(reasonPhrase.codeUnits);
+ buffer.addByte(_CharCode.CR);
+ buffer.addByte(_CharCode.LF);
+
+ var session = _httpRequest._session;
+ if (session != null && !session._destroyed) {
+ // Mark as not new.
+ session._isNew = false;
+ // Make sure we only send the current session id.
+ bool found = false;
+ for (int i = 0; i < cookies.length; i++) {
+ if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) {
+ cookies[i]
+ ..value = session.id
+ ..httpOnly = true
+ ..path = "/";
+ found = true;
+ }
+ }
+ if (!found) {
+ var cookie = new Cookie(_DART_SESSION_ID, session.id);
+ cookies.add(cookie
+ ..httpOnly = true
+ ..path = "/");
+ }
+ }
+ // Add all the cookies set to the headers.
+ if (_cookies != null) {
+ _cookies.forEach((cookie) {
+ headers.add(HttpHeaders.setCookieHeader, cookie);
+ });
+ }
+
+ headers._finalize();
+
+ // Write headers.
+ headers._build(buffer);
+ buffer.addByte(_CharCode.CR);
+ buffer.addByte(_CharCode.LF);
+ Uint8List headerBytes = buffer.takeBytes();
+ _outgoing.setHeader(headerBytes, headerBytes.length);
+ }
+
+ String _findReasonPhrase(int statusCode) {
+ if (_reasonPhrase != null) {
+ return _reasonPhrase;
+ }
+
+ switch (statusCode) {
+ case HttpStatus.continue_:
+ return "Continue";
+ case HttpStatus.switchingProtocols:
+ return "Switching Protocols";
+ case HttpStatus.ok:
+ return "OK";
+ case HttpStatus.created:
+ return "Created";
+ case HttpStatus.accepted:
+ return "Accepted";
+ case HttpStatus.nonAuthoritativeInformation:
+ return "Non-Authoritative Information";
+ case HttpStatus.noContent:
+ return "No Content";
+ case HttpStatus.resetContent:
+ return "Reset Content";
+ case HttpStatus.partialContent:
+ return "Partial Content";
+ case HttpStatus.multipleChoices:
+ return "Multiple Choices";
+ case HttpStatus.movedPermanently:
+ return "Moved Permanently";
+ case HttpStatus.found:
+ return "Found";
+ case HttpStatus.seeOther:
+ return "See Other";
+ case HttpStatus.notModified:
+ return "Not Modified";
+ case HttpStatus.useProxy:
+ return "Use Proxy";
+ case HttpStatus.temporaryRedirect:
+ return "Temporary Redirect";
+ case HttpStatus.badRequest:
+ return "Bad Request";
+ case HttpStatus.unauthorized:
+ return "Unauthorized";
+ case HttpStatus.paymentRequired:
+ return "Payment Required";
+ case HttpStatus.forbidden:
+ return "Forbidden";
+ case HttpStatus.notFound:
+ return "Not Found";
+ case HttpStatus.methodNotAllowed:
+ return "Method Not Allowed";
+ case HttpStatus.notAcceptable:
+ return "Not Acceptable";
+ case HttpStatus.proxyAuthenticationRequired:
+ return "Proxy Authentication Required";
+ case HttpStatus.requestTimeout:
+ return "Request Time-out";
+ case HttpStatus.conflict:
+ return "Conflict";
+ case HttpStatus.gone:
+ return "Gone";
+ case HttpStatus.lengthRequired:
+ return "Length Required";
+ case HttpStatus.preconditionFailed:
+ return "Precondition Failed";
+ case HttpStatus.requestEntityTooLarge:
+ return "Request Entity Too Large";
+ case HttpStatus.requestUriTooLong:
+ return "Request-URI Too Long";
+ case HttpStatus.unsupportedMediaType:
+ return "Unsupported Media Type";
+ case HttpStatus.requestedRangeNotSatisfiable:
+ return "Requested range not satisfiable";
+ case HttpStatus.expectationFailed:
+ return "Expectation Failed";
+ case HttpStatus.internalServerError:
+ return "Internal Server Error";
+ case HttpStatus.notImplemented:
+ return "Not Implemented";
+ case HttpStatus.badGateway:
+ return "Bad Gateway";
+ case HttpStatus.serviceUnavailable:
+ return "Service Unavailable";
+ case HttpStatus.gatewayTimeout:
+ return "Gateway Time-out";
+ case HttpStatus.httpVersionNotSupported:
+ return "Http Version not supported";
+ default:
+ return "Status $statusCode";
+ }
+ }
+}
+
+class _HttpClientRequest extends _HttpOutboundMessage<HttpClientResponse>
+ implements HttpClientRequest {
+ final String method;
+ final Uri uri;
+ final List<Cookie> cookies = new List<Cookie>();
+
+ // The HttpClient this request belongs to.
+ final _HttpClient _httpClient;
+ final _HttpClientConnection _httpClientConnection;
+
+ final Completer<HttpClientResponse> _responseCompleter =
+ new Completer<HttpClientResponse>();
+
+ final _Proxy _proxy;
+
+ Future<HttpClientResponse> _response;
+
+ // TODO(ajohnsen): Get default value from client?
+ bool _followRedirects = true;
+
+ int _maxRedirects = 5;
+
+ List<RedirectInfo> _responseRedirects = [];
+
+ _HttpClientRequest(_HttpOutgoing outgoing, Uri uri, this.method, this._proxy,
+ this._httpClient, this._httpClientConnection)
+ : uri = uri,
+ super(uri, "1.1", outgoing) {
+ // GET and HEAD have 'content-length: 0' by default.
+ if (method == "GET" || method == "HEAD") {
+ contentLength = 0;
+ } else {
+ headers.chunkedTransferEncoding = true;
+ }
+ }
+
+ Future<HttpClientResponse> get done {
+ if (_response == null) {
+ _response =
+ Future.wait([_responseCompleter.future, super.done], eagerError: true)
+ .then((list) => list[0]);
+ }
+ return _response;
+ }
+
+ Future<HttpClientResponse> close() {
+ super.close();
+ return done;
+ }
+
+ int get maxRedirects => _maxRedirects;
+ void set maxRedirects(int maxRedirects) {
+ if (_outgoing.headersWritten) throw new StateError("Request already sent");
+ _maxRedirects = maxRedirects;
+ }
+
+ bool get followRedirects => _followRedirects;
+ void set followRedirects(bool followRedirects) {
+ if (_outgoing.headersWritten) throw new StateError("Request already sent");
+ _followRedirects = followRedirects;
+ }
+
+ HttpConnectionInfo get connectionInfo => _httpClientConnection.connectionInfo;
+
+ void _onIncoming(_HttpIncoming incoming) {
+ var response = new _HttpClientResponse(incoming, this, _httpClient);
+ Future<HttpClientResponse> future;
+ if (followRedirects && response.isRedirect) {
+ if (response.redirects.length < maxRedirects) {
+ // Redirect and drain response.
+ future = response
+ .drain()
+ .then<HttpClientResponse>((_) => response.redirect());
+ } else {
+ // End with exception, too many redirects.
+ future = response.drain().then<HttpClientResponse>((_) {
+ return new Future<HttpClientResponse>.error(new RedirectException(
+ "Redirect limit exceeded", response.redirects));
+ });
+ }
+ } else if (response._shouldAuthenticateProxy) {
+ future = response._authenticate(true);
+ } else if (response._shouldAuthenticate) {
+ future = response._authenticate(false);
+ } else {
+ future = new Future<HttpClientResponse>.value(response);
+ }
+ future.then((v) => _responseCompleter.complete(v),
+ onError: _responseCompleter.completeError);
+ }
+
+ void _onError(error, StackTrace stackTrace) {
+ _responseCompleter.completeError(error, stackTrace);
+ }
+
+ // Generate the request URI based on the method and proxy.
+ String _requestUri() {
+ // Generate the request URI starting from the path component.
+ String uriStartingFromPath() {
+ String result = uri.path;
+ if (result.isEmpty) result = "/";
+ if (uri.hasQuery) {
+ result = "${result}?${uri.query}";
+ }
+ return result;
+ }
+
+ if (_proxy.isDirect) {
+ return uriStartingFromPath();
+ } else {
+ if (method == "CONNECT") {
+ // For the connect method the request URI is the host:port of
+ // the requested destination of the tunnel (see RFC 2817
+ // section 5.2)
+ return "${uri.host}:${uri.port}";
+ } else {
+ if (_httpClientConnection._proxyTunnel) {
+ return uriStartingFromPath();
+ } else {
+ return uri.removeFragment().toString();
+ }
+ }
+ }
+ }
+
+ void _writeHeader() {
+ BytesBuilder buffer = new _CopyingBytesBuilder(_OUTGOING_BUFFER_SIZE);
+
+ // Write the request method.
+ buffer.add(method.codeUnits);
+ buffer.addByte(_CharCode.SP);
+ // Write the request URI.
+ buffer.add(_requestUri().codeUnits);
+ buffer.addByte(_CharCode.SP);
+ // Write HTTP/1.1.
+ buffer.add(_Const.HTTP11);
+ buffer.addByte(_CharCode.CR);
+ buffer.addByte(_CharCode.LF);
+
+ // Add the cookies to the headers.
+ if (!cookies.isEmpty) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < cookies.length; i++) {
+ if (i > 0) sb.write("; ");
+ sb..write(cookies[i].name)..write("=")..write(cookies[i].value);
+ }
+ headers.add(HttpHeaders.cookieHeader, sb.toString());
+ }
+
+ headers._finalize();
+
+ // Write headers.
+ headers._build(buffer);
+ buffer.addByte(_CharCode.CR);
+ buffer.addByte(_CharCode.LF);
+ Uint8List headerBytes = buffer.takeBytes();
+ _outgoing.setHeader(headerBytes, headerBytes.length);
+ }
+}
+
+// Used by _HttpOutgoing as a target of a chunked converter for gzip
+// compression.
+class _HttpGZipSink extends ByteConversionSink {
+ final _BytesConsumer _consume;
+ _HttpGZipSink(this._consume);
+
+ void add(List<int> chunk) {
+ _consume(chunk);
+ }
+
+ void addSlice(List<int> chunk, int start, int end, bool isLast) {
+ if (chunk is Uint8List) {
+ _consume(new Uint8List.view(chunk.buffer, start, end - start));
+ } else {
+ _consume(chunk.sublist(start, end - start));
+ }
+ }
+
+ void close() {}
+}
+
+// The _HttpOutgoing handles all of the following:
+// - Buffering
+// - GZip compression
+// - Content-Length validation.
+// - Errors.
+//
+// Most notable is the GZip compression, that uses a double-buffering system,
+// one before gzip (_gzipBuffer) and one after (_buffer).
+class _HttpOutgoing implements StreamConsumer<List<int>> {
+ static const List<int> _footerAndChunk0Length = const [
+ _CharCode.CR,
+ _CharCode.LF,
+ 0x30,
+ _CharCode.CR,
+ _CharCode.LF,
+ _CharCode.CR,
+ _CharCode.LF
+ ];
+
+ static const List<int> _chunk0Length = const [
+ 0x30,
+ _CharCode.CR,
+ _CharCode.LF,
+ _CharCode.CR,
+ _CharCode.LF
+ ];
+
+ final Completer<Socket> _doneCompleter = new Completer<Socket>();
+ final Socket socket;
+
+ bool ignoreBody = false;
+ bool headersWritten = false;
+
+ Uint8List _buffer;
+ int _length = 0;
+
+ Future _closeFuture;
+
+ bool chunked = false;
+ int _pendingChunkedFooter = 0;
+
+ int contentLength;
+ int _bytesWritten = 0;
+
+ bool _gzip = false;
+ ByteConversionSink _gzipSink;
+ // _gzipAdd is set iff the sink is being added to. It's used to specify where
+ // gzipped data should be taken (sometimes a controller, sometimes a socket).
+ _BytesConsumer _gzipAdd;
+ Uint8List _gzipBuffer;
+ int _gzipBufferLength = 0;
+
+ bool _socketError = false;
+
+ _HttpOutboundMessage outbound;
+
+ _HttpOutgoing(this.socket);
+
+ // Returns either a future or 'null', if it was able to write headers
+ // immediately.
+ Future writeHeaders({bool drainRequest: true, bool setOutgoing: true}) {
+ if (headersWritten) return null;
+ headersWritten = true;
+ Future drainFuture;
+ bool gzip = false;
+ if (outbound is _HttpResponse) {
+ // Server side.
+ _HttpResponse response = outbound;
+ if (response._httpRequest._httpServer.autoCompress &&
+ outbound.bufferOutput &&
+ outbound.headers.chunkedTransferEncoding) {
+ List acceptEncodings =
+ response._httpRequest.headers[HttpHeaders.acceptEncodingHeader];
+ List contentEncoding =
+ outbound.headers[HttpHeaders.contentEncodingHeader];
+ if (acceptEncodings != null &&
+ acceptEncodings
+ .expand((list) => list.split(","))
+ .any((encoding) => encoding.trim().toLowerCase() == "gzip") &&
+ contentEncoding == null) {
+ outbound.headers.set(HttpHeaders.contentEncodingHeader, "gzip");
+ gzip = true;
+ }
+ }
+ if (drainRequest && !response._httpRequest._incoming.hasSubscriber) {
+ drainFuture = response._httpRequest.drain().catchError((_) {});
+ }
+ } else {
+ drainRequest = false;
+ }
+ if (!ignoreBody) {
+ if (setOutgoing) {
+ int contentLength = outbound.headers.contentLength;
+ if (outbound.headers.chunkedTransferEncoding) {
+ chunked = true;
+ if (gzip) this.gzip = true;
+ } else if (contentLength >= 0) {
+ this.contentLength = contentLength;
+ }
+ }
+ if (drainFuture != null) {
+ return drainFuture.then((_) => outbound._writeHeader());
+ }
+ }
+ outbound._writeHeader();
+ return null;
+ }
+
+ Future addStream(Stream<List<int>> stream) {
+ if (_socketError) {
+ stream.listen(null).cancel();
+ return new Future.value(outbound);
+ }
+ if (ignoreBody) {
+ stream.drain().catchError((_) {});
+ var future = writeHeaders();
+ if (future != null) {
+ return future.then((_) => close());
+ }
+ return close();
+ }
+ StreamSubscription<List<int>> sub;
+ // Use new stream so we are able to pause (see below listen). The
+ // alternative is to use stream.extand, but that won't give us a way of
+ // pausing.
+ var controller = new StreamController<List<int>>(
+ onPause: () => sub.pause(), onResume: () => sub.resume(), sync: true);
+
+ void onData(List<int> data) {
+ if (_socketError) return;
+ if (data.length == 0) return;
+ if (chunked) {
+ if (_gzip) {
+ _gzipAdd = controller.add;
+ _addGZipChunk(data, _gzipSink.add);
+ _gzipAdd = null;
+ return;
+ }
+ _addChunk(_chunkHeader(data.length), controller.add);
+ _pendingChunkedFooter = 2;
+ } else {
+ if (contentLength != null) {
+ _bytesWritten += data.length;
+ if (_bytesWritten > contentLength) {
+ controller.addError(new HttpException(
+ "Content size exceeds specified contentLength. "
+ "$_bytesWritten bytes written while expected "
+ "$contentLength. "
+ "[${new String.fromCharCodes(data)}]"));
+ return;
+ }
+ }
+ }
+ _addChunk(data, controller.add);
+ }
+
+ sub = stream.listen(onData,
+ onError: controller.addError,
+ onDone: controller.close,
+ cancelOnError: true);
+ // Write headers now that we are listening to the stream.
+ if (!headersWritten) {
+ var future = writeHeaders();
+ if (future != null) {
+ // While incoming is being drained, the pauseFuture is non-null. Pause
+ // output until it's drained.
+ sub.pause(future);
+ }
+ }
+ return socket.addStream(controller.stream).then((_) {
+ return outbound;
+ }, onError: (error, stackTrace) {
+ // Be sure to close it in case of an error.
+ if (_gzip) _gzipSink.close();
+ _socketError = true;
+ _doneCompleter.completeError(error, stackTrace);
+ if (_ignoreError(error)) {
+ return outbound;
+ } else {
+ throw error;
+ }
+ });
+ }
+
+ Future close() {
+ // If we are already closed, return that future.
+ if (_closeFuture != null) return _closeFuture;
+ // If we earlier saw an error, return immediate. The notification to
+ // _Http*Connection is already done.
+ if (_socketError) return new Future.value(outbound);
+ if (outbound._isConnectionClosed) return new Future.value(outbound);
+ if (!headersWritten && !ignoreBody) {
+ if (outbound.headers.contentLength == -1) {
+ // If no body was written, ignoreBody is false (it's not a HEAD
+ // request) and the content-length is unspecified, set contentLength to
+ // 0.
+ outbound.headers.chunkedTransferEncoding = false;
+ outbound.headers.contentLength = 0;
+ } else if (outbound.headers.contentLength > 0) {
+ var error = new HttpException(
+ "No content even though contentLength was specified to be "
+ "greater than 0: ${outbound.headers.contentLength}.",
+ uri: outbound._uri);
+ _doneCompleter.completeError(error);
+ return _closeFuture = new Future.error(error);
+ }
+ }
+ // If contentLength was specified, validate it.
+ if (contentLength != null) {
+ if (_bytesWritten < contentLength) {
+ var error = new HttpException(
+ "Content size below specified contentLength. "
+ " $_bytesWritten bytes written but expected "
+ "$contentLength.",
+ uri: outbound._uri);
+ _doneCompleter.completeError(error);
+ return _closeFuture = new Future.error(error);
+ }
+ }
+
+ Future finalize() {
+ // In case of chunked encoding (and gzip), handle remaining gzip data and
+ // append the 'footer' for chunked encoding.
+ if (chunked) {
+ if (_gzip) {
+ _gzipAdd = socket.add;
+ if (_gzipBufferLength > 0) {
+ _gzipSink.add(
+ new Uint8List.view(_gzipBuffer.buffer, 0, _gzipBufferLength));
+ }
+ _gzipBuffer = null;
+ _gzipSink.close();
+ _gzipAdd = null;
+ }
+ _addChunk(_chunkHeader(0), socket.add);
+ }
+ // Add any remaining data in the buffer.
+ if (_length > 0) {
+ socket.add(new Uint8List.view(_buffer.buffer, 0, _length));
+ }
+ // Clear references, for better GC.
+ _buffer = null;
+ // And finally flush it. As we support keep-alive, never close it from
+ // here. Once the socket is flushed, we'll be able to reuse it (signaled
+ // by the 'done' future).
+ return socket.flush().then((_) {
+ _doneCompleter.complete(socket);
+ return outbound;
+ }, onError: (error, stackTrace) {
+ _doneCompleter.completeError(error, stackTrace);
+ if (_ignoreError(error)) {
+ return outbound;
+ } else {
+ throw error;
+ }
+ });
+ }
+
+ var future = writeHeaders();
+ if (future != null) {
+ return _closeFuture = future.whenComplete(finalize);
+ }
+ return _closeFuture = finalize();
+ }
+
+ Future<Socket> get done => _doneCompleter.future;
+
+ void setHeader(List<int> data, int length) {
+ assert(_length == 0);
+ _buffer = data;
+ _length = length;
+ }
+
+ void set gzip(bool value) {
+ _gzip = value;
+ if (_gzip) {
+ _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE);
+ assert(_gzipSink == null);
+ _gzipSink = new ZLibEncoder(gzip: true)
+ .startChunkedConversion(new _HttpGZipSink((data) {
+ // We are closing down prematurely, due to an error. Discard.
+ if (_gzipAdd == null) return;
+ _addChunk(_chunkHeader(data.length), _gzipAdd);
+ _pendingChunkedFooter = 2;
+ _addChunk(data, _gzipAdd);
+ }));
+ }
+ }
+
+ bool _ignoreError(error) =>
+ (error is SocketException || error is TlsException) &&
+ outbound is HttpResponse;
+
+ void _addGZipChunk(List<int> chunk, void add(List<int> data)) {
+ if (!outbound.bufferOutput) {
+ add(chunk);
+ return;
+ }
+ if (chunk.length > _gzipBuffer.length - _gzipBufferLength) {
+ add(new Uint8List.view(_gzipBuffer.buffer, 0, _gzipBufferLength));
+ _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE);
+ _gzipBufferLength = 0;
+ }
+ if (chunk.length > _OUTGOING_BUFFER_SIZE) {
+ add(chunk);
+ } else {
+ _gzipBuffer.setRange(
+ _gzipBufferLength, _gzipBufferLength + chunk.length, chunk);
+ _gzipBufferLength += chunk.length;
+ }
+ }
+
+ void _addChunk(List<int> chunk, void add(List<int> data)) {
+ if (!outbound.bufferOutput) {
+ if (_buffer != null) {
+ // If _buffer is not null, we have not written the header yet. Write
+ // it now.
+ add(new Uint8List.view(_buffer.buffer, 0, _length));
+ _buffer = null;
+ _length = 0;
+ }
+ add(chunk);
+ return;
+ }
+ if (chunk.length > _buffer.length - _length) {
+ add(new Uint8List.view(_buffer.buffer, 0, _length));
+ _buffer = new Uint8List(_OUTGOING_BUFFER_SIZE);
+ _length = 0;
+ }
+ if (chunk.length > _OUTGOING_BUFFER_SIZE) {
+ add(chunk);
+ } else {
+ _buffer.setRange(_length, _length + chunk.length, chunk);
+ _length += chunk.length;
+ }
+ }
+
+ List<int> _chunkHeader(int length) {
+ const hexDigits = const [
+ 0x30,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x41,
+ 0x42,
+ 0x43,
+ 0x44,
+ 0x45,
+ 0x46
+ ];
+ if (length == 0) {
+ if (_pendingChunkedFooter == 2) return _footerAndChunk0Length;
+ return _chunk0Length;
+ }
+ int size = _pendingChunkedFooter;
+ int len = length;
+ // Compute a fast integer version of (log(length + 1) / log(16)).ceil().
+ while (len > 0) {
+ size++;
+ len >>= 4;
+ }
+ var footerAndHeader = new Uint8List(size + 2);
+ if (_pendingChunkedFooter == 2) {
+ footerAndHeader[0] = _CharCode.CR;
+ footerAndHeader[1] = _CharCode.LF;
+ }
+ int index = size;
+ while (index > _pendingChunkedFooter) {
+ footerAndHeader[--index] = hexDigits[length & 15];
+ length = length >> 4;
+ }
+ footerAndHeader[size + 0] = _CharCode.CR;
+ footerAndHeader[size + 1] = _CharCode.LF;
+ return footerAndHeader;
+ }
+}
+
+class _HttpClientConnection {
+ final String key;
+ final Socket _socket;
+ final bool _proxyTunnel;
+ final SecurityContext _context;
+ final _HttpParser _httpParser;
+ StreamSubscription _subscription;
+ final _HttpClient _httpClient;
+ bool _dispose = false;
+ Timer _idleTimer;
+ bool closed = false;
+ Uri _currentUri;
+
+ Completer<_HttpIncoming> _nextResponseCompleter;
+ Future<Socket> _streamFuture;
+
+ _HttpClientConnection(this.key, this._socket, this._httpClient,
+ [this._proxyTunnel = false, this._context])
+ : _httpParser = new _HttpParser.responseParser() {
+ _httpParser.listenToStream(_socket);
+
+ // Set up handlers on the parser here, so we are sure to get 'onDone' from
+ // the parser.
+ _subscription = _httpParser.listen((incoming) {
+ // Only handle one incoming response at the time. Keep the
+ // stream paused until the response have been processed.
+ _subscription.pause();
+ // We assume the response is not here, until we have send the request.
+ if (_nextResponseCompleter == null) {
+ throw new HttpException(
+ "Unexpected response (unsolicited response without request).",
+ uri: _currentUri);
+ }
+
+ // Check for status code '100 Continue'. In that case just
+ // consume that response as the final response will follow
+ // it. There is currently no API for the client to wait for
+ // the '100 Continue' response.
+ if (incoming.statusCode == 100) {
+ incoming.drain().then((_) {
+ _subscription.resume();
+ }).catchError((error, [StackTrace stackTrace]) {
+ _nextResponseCompleter.completeError(
+ new HttpException(error.message, uri: _currentUri), stackTrace);
+ _nextResponseCompleter = null;
+ });
+ } else {
+ _nextResponseCompleter.complete(incoming);
+ _nextResponseCompleter = null;
+ }
+ }, onError: (error, [StackTrace stackTrace]) {
+ if (_nextResponseCompleter != null) {
+ _nextResponseCompleter.completeError(
+ new HttpException(error.message, uri: _currentUri), stackTrace);
+ _nextResponseCompleter = null;
+ }
+ }, onDone: () {
+ if (_nextResponseCompleter != null) {
+ _nextResponseCompleter.completeError(new HttpException(
+ "Connection closed before response was received",
+ uri: _currentUri));
+ _nextResponseCompleter = null;
+ }
+ close();
+ });
+ }
+
+ _HttpClientRequest send(Uri uri, int port, String method, _Proxy proxy) {
+ if (closed) {
+ throw new HttpException("Socket closed before request was sent",
+ uri: uri);
+ }
+ _currentUri = uri;
+ // Start with pausing the parser.
+ _subscription.pause();
+ _ProxyCredentials proxyCreds; // Credentials used to authorize proxy.
+ _SiteCredentials creds; // Credentials used to authorize this request.
+ var outgoing = new _HttpOutgoing(_socket);
+ // Create new request object, wrapping the outgoing connection.
+ var request =
+ new _HttpClientRequest(outgoing, uri, method, proxy, _httpClient, this);
+ // For the Host header an IPv6 address must be enclosed in []'s.
+ var host = uri.host;
+ if (host.contains(':')) host = "[$host]";
+ request.headers
+ ..host = host
+ ..port = port
+ .._add(HttpHeaders.acceptEncodingHeader, "gzip");
+ if (_httpClient.userAgent != null) {
+ request.headers._add('user-agent', _httpClient.userAgent);
+ }
+ if (proxy.isAuthenticated) {
+ // If the proxy configuration contains user information use that
+ // for proxy basic authorization.
+ String auth = _CryptoUtils.bytesToBase64(
+ utf8.encode("${proxy.username}:${proxy.password}"));
+ request.headers.set(HttpHeaders.proxyAuthorizationHeader, "Basic $auth");
+ } else if (!proxy.isDirect && _httpClient._proxyCredentials.length > 0) {
+ proxyCreds = _httpClient._findProxyCredentials(proxy);
+ if (proxyCreds != null) {
+ proxyCreds.authorize(request);
+ }
+ }
+ if (uri.userInfo != null && !uri.userInfo.isEmpty) {
+ // If the URL contains user information use that for basic
+ // authorization.
+ String auth = _CryptoUtils.bytesToBase64(utf8.encode(uri.userInfo));
+ request.headers.set(HttpHeaders.authorizationHeader, "Basic $auth");
+ } else {
+ // Look for credentials.
+ creds = _httpClient._findCredentials(uri);
+ if (creds != null) {
+ creds.authorize(request);
+ }
+ }
+ // Start sending the request (lazy, delayed until the user provides
+ // data).
+ _httpParser.isHead = method == "HEAD";
+ _streamFuture = outgoing.done.then<Socket>((Socket s) {
+ // Request sent, set up response completer.
+ _nextResponseCompleter = new Completer<_HttpIncoming>();
+
+ // Listen for response.
+ _nextResponseCompleter.future.then((incoming) {
+ _currentUri = null;
+ incoming.dataDone.then((closing) {
+ if (incoming.upgraded) {
+ _httpClient._connectionClosed(this);
+ startTimer();
+ return;
+ }
+ if (closed) return;
+ if (!closing &&
+ !_dispose &&
+ incoming.headers.persistentConnection &&
+ request.persistentConnection) {
+ // Return connection, now we are done.
+ _httpClient._returnConnection(this);
+ _subscription.resume();
+ } else {
+ destroy();
+ }
+ });
+ // For digest authentication if proxy check if the proxy
+ // requests the client to start using a new nonce for proxy
+ // authentication.
+ if (proxyCreds != null &&
+ proxyCreds.scheme == _AuthenticationScheme.DIGEST) {
+ var authInfo = incoming.headers["proxy-authentication-info"];
+ if (authInfo != null && authInfo.length == 1) {
+ var header =
+ _HeaderValue.parse(authInfo[0], parameterSeparator: ',');
+ var nextnonce = header.parameters["nextnonce"];
+ if (nextnonce != null) proxyCreds.nonce = nextnonce;
+ }
+ }
+ // For digest authentication check if the server requests the
+ // client to start using a new nonce.
+ if (creds != null && creds.scheme == _AuthenticationScheme.DIGEST) {
+ var authInfo = incoming.headers["authentication-info"];
+ if (authInfo != null && authInfo.length == 1) {
+ var header =
+ _HeaderValue.parse(authInfo[0], parameterSeparator: ',');
+ var nextnonce = header.parameters["nextnonce"];
+ if (nextnonce != null) creds.nonce = nextnonce;
+ }
+ }
+ request._onIncoming(incoming);
+ })
+ // If we see a state error, we failed to get the 'first'
+ // element.
+ .catchError((error) {
+ throw new HttpException("Connection closed before data was received",
+ uri: uri);
+ }, test: (error) => error is StateError).catchError((error, stackTrace) {
+ // We are done with the socket.
+ destroy();
+ request._onError(error, stackTrace);
+ });
+
+ // Resume the parser now we have a handler.
+ _subscription.resume();
+ return s;
+ }, onError: (e) {
+ destroy();
+ });
+ return request;
+ }
+
+ Future<Socket> detachSocket() {
+ return _streamFuture.then(
+ (_) => new _DetachedSocket(_socket, _httpParser.detachIncoming()));
+ }
+
+ void destroy() {
+ closed = true;
+ _httpClient._connectionClosed(this);
+ _socket.destroy();
+ }
+
+ void close() {
+ closed = true;
+ _httpClient._connectionClosed(this);
+ _streamFuture
+ .timeout(_httpClient.idleTimeout)
+ .then((_) => _socket.destroy());
+ }
+
+ Future<_HttpClientConnection> createProxyTunnel(String host, int port,
+ _Proxy proxy, bool callback(X509Certificate certificate)) {
+ _HttpClientRequest request =
+ send(new Uri(host: host, port: port), port, "CONNECT", proxy);
+ if (proxy.isAuthenticated) {
+ // If the proxy configuration contains user information use that
+ // for proxy basic authorization.
+ String auth = _CryptoUtils.bytesToBase64(
+ utf8.encode("${proxy.username}:${proxy.password}"));
+ request.headers.set(HttpHeaders.proxyAuthorizationHeader, "Basic $auth");
+ }
+ return request.close().then((response) {
+ if (response.statusCode != HttpStatus.ok) {
+ throw new HttpException(
+ "Proxy failed to establish tunnel "
+ "(${response.statusCode} ${response.reasonPhrase})",
+ uri: request.uri);
+ }
+ var socket = (response as _HttpClientResponse)
+ ._httpRequest
+ ._httpClientConnection
+ ._socket;
+ return SecureSocket.secure(socket,
+ host: host, context: _context, onBadCertificate: callback);
+ }).then((secureSocket) {
+ String key = _HttpClientConnection.makeKey(true, host, port);
+ return new _HttpClientConnection(
+ key, secureSocket, request._httpClient, true);
+ });
+ }
+
+ HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket);
+
+ static makeKey(bool isSecure, String host, int port) {
+ return isSecure ? "ssh:$host:$port" : "$host:$port";
+ }
+
+ void stopTimer() {
+ if (_idleTimer != null) {
+ _idleTimer.cancel();
+ _idleTimer = null;
+ }
+ }
+
+ void startTimer() {
+ assert(_idleTimer == null);
+ _idleTimer = new Timer(_httpClient.idleTimeout, () {
+ _idleTimer = null;
+ close();
+ });
+ }
+}
+
+class _ConnectionInfo {
+ final _HttpClientConnection connection;
+ final _Proxy proxy;
+
+ _ConnectionInfo(this.connection, this.proxy);
+}
+
+class _ConnectionTarget {
+ // Unique key for this connection target.
+ final String key;
+ final String host;
+ final int port;
+ final bool isSecure;
+ final SecurityContext context;
+ final Set<_HttpClientConnection> _idle = new HashSet();
+ final Set<_HttpClientConnection> _active = new HashSet();
+ final Set<ConnectionTask> _socketTasks = new HashSet();
+ final Queue _pending = new ListQueue();
+ int _connecting = 0;
+
+ _ConnectionTarget(
+ this.key, this.host, this.port, this.isSecure, this.context);
+
+ bool get isEmpty => _idle.isEmpty && _active.isEmpty && _connecting == 0;
+
+ bool get hasIdle => _idle.isNotEmpty;
+
+ bool get hasActive => _active.isNotEmpty || _connecting > 0;
+
+ _HttpClientConnection takeIdle() {
+ assert(hasIdle);
+ _HttpClientConnection connection = _idle.first;
+ _idle.remove(connection);
+ connection.stopTimer();
+ _active.add(connection);
+ return connection;
+ }
+
+ _checkPending() {
+ if (_pending.isNotEmpty) {
+ _pending.removeFirst()();
+ }
+ }
+
+ void addNewActive(_HttpClientConnection connection) {
+ _active.add(connection);
+ }
+
+ void returnConnection(_HttpClientConnection connection) {
+ assert(_active.contains(connection));
+ _active.remove(connection);
+ _idle.add(connection);
+ connection.startTimer();
+ _checkPending();
+ }
+
+ void connectionClosed(_HttpClientConnection connection) {
+ assert(!_active.contains(connection) || !_idle.contains(connection));
+ _active.remove(connection);
+ _idle.remove(connection);
+ _checkPending();
+ }
+
+ void close(bool force) {
+ // Always cancel pending socket connections.
+ for (var t in _socketTasks.toList()) {
+ // Make sure the socket is destroyed if the ConnectionTask is cancelled.
+ t.socket.then((s) {
+ s.destroy();
+ }, onError: (e) {});
+ t.cancel();
+ }
+ if (force) {
+ for (var c in _idle.toList()) {
+ c.destroy();
+ }
+ for (var c in _active.toList()) {
+ c.destroy();
+ }
+ } else {
+ for (var c in _idle.toList()) {
+ c.close();
+ }
+ }
+ }
+
+ Future<_ConnectionInfo> connect(
+ String uriHost, int uriPort, _Proxy proxy, _HttpClient client) {
+ if (hasIdle) {
+ var connection = takeIdle();
+ client._connectionsChanged();
+ return new Future.value(new _ConnectionInfo(connection, proxy));
+ }
+ if (client.maxConnectionsPerHost != null &&
+ _active.length + _connecting >= client.maxConnectionsPerHost) {
+ var completer = new Completer<_ConnectionInfo>();
+ _pending.add(() {
+ completer.complete(connect(uriHost, uriPort, proxy, client));
+ });
+ return completer.future;
+ }
+ var currentBadCertificateCallback = client._badCertificateCallback;
+
+ bool callback(X509Certificate certificate) {
+ if (currentBadCertificateCallback == null) return false;
+ return currentBadCertificateCallback(certificate, uriHost, uriPort);
+ }
+
+ Future<ConnectionTask> connectionTask = (isSecure && proxy.isDirect
+ ? SecureSocket.startConnect(host, port,
+ context: context, onBadCertificate: callback)
+ : Socket.startConnect(host, port));
+ _connecting++;
+ return connectionTask.then((ConnectionTask task) {
+ _socketTasks.add(task);
+ Future socketFuture = task.socket;
+ final Duration connectionTimeout = client.connectionTimeout;
+ if (connectionTimeout != null) {
+ socketFuture = socketFuture.timeout(connectionTimeout, onTimeout: () {
+ _socketTasks.remove(task);
+ task.cancel();
+ return null;
+ });
+ }
+ return socketFuture.then((socket) {
+ // When there is a timeout, there is a race in which the connectionTask
+ // Future won't be completed with an error before the socketFuture here
+ // is completed with 'null' by the onTimeout callback above. In this
+ // case, propagate a SocketException as specified by the
+ // HttpClient.connectionTimeout docs.
+ if (socket == null) {
+ assert(connectionTimeout != null);
+ throw new SocketException(
+ "HTTP connection timed out after ${connectionTimeout}, "
+ "host: ${host}, port: ${port}");
+ }
+ _connecting--;
+ socket.setOption(SocketOption.tcpNoDelay, true);
+ var connection =
+ new _HttpClientConnection(key, socket, client, false, context);
+ if (isSecure && !proxy.isDirect) {
+ connection._dispose = true;
+ return connection
+ .createProxyTunnel(uriHost, uriPort, proxy, callback)
+ .then((tunnel) {
+ client
+ ._getConnectionTarget(uriHost, uriPort, true)
+ .addNewActive(tunnel);
+ _socketTasks.remove(task);
+ return new _ConnectionInfo(tunnel, proxy);
+ });
+ } else {
+ addNewActive(connection);
+ _socketTasks.remove(task);
+ return new _ConnectionInfo(connection, proxy);
+ }
+ }, onError: (error) {
+ _connecting--;
+ _socketTasks.remove(task);
+ _checkPending();
+ throw error;
+ });
+ });
+ }
+}
+
+typedef bool BadCertificateCallback(X509Certificate cr, String host, int port);
+
+class _HttpClient implements HttpClient {
+ bool _closing = false;
+ bool _closingForcefully = false;
+ final Map<String, _ConnectionTarget> _connectionTargets =
+ new HashMap<String, _ConnectionTarget>();
+ final List<_Credentials> _credentials = [];
+ final List<_ProxyCredentials> _proxyCredentials = [];
+ final SecurityContext _context;
+ Function _authenticate;
+ Function _authenticateProxy;
+ Function _findProxy = HttpClient.findProxyFromEnvironment;
+ Duration _idleTimeout = const Duration(seconds: 15);
+ BadCertificateCallback _badCertificateCallback;
+
+ Duration get idleTimeout => _idleTimeout;
+
+ Duration connectionTimeout;
+
+ int maxConnectionsPerHost;
+
+ bool autoUncompress = true;
+
+ String userAgent = _getHttpVersion();
+
+ _HttpClient(this._context);
+
+ void set idleTimeout(Duration timeout) {
+ _idleTimeout = timeout;
+ for (var c in _connectionTargets.values) {
+ for (var idle in c._idle) {
+ // Reset timer. This is fine, as it's not happening often.
+ idle.stopTimer();
+ idle.startTimer();
+ }
+ }
+ }
+
+ set badCertificateCallback(
+ bool callback(X509Certificate cert, String host, int port)) {
+ _badCertificateCallback = callback;
+ }
+
+ Future<HttpClientRequest> open(
+ String method, String host, int port, String path) {
+ const int hashMark = 0x23;
+ const int questionMark = 0x3f;
+ int fragmentStart = path.length;
+ int queryStart = path.length;
+ for (int i = path.length - 1; i >= 0; i--) {
+ var char = path.codeUnitAt(i);
+ if (char == hashMark) {
+ fragmentStart = i;
+ queryStart = i;
+ } else if (char == questionMark) {
+ queryStart = i;
+ }
+ }
+ String query = null;
+ if (queryStart < fragmentStart) {
+ query = path.substring(queryStart + 1, fragmentStart);
+ path = path.substring(0, queryStart);
+ }
+ Uri uri = new Uri(
+ scheme: "http", host: host, port: port, path: path, query: query);
+ return _openUrl(method, uri);
+ }
+
+ Future<HttpClientRequest> openUrl(String method, Uri url) =>
+ _openUrl(method, url);
+
+ Future<HttpClientRequest> get(String host, int port, String path) =>
+ open("get", host, port, path);
+
+ Future<HttpClientRequest> getUrl(Uri url) => _openUrl("get", url);
+
+ Future<HttpClientRequest> post(String host, int port, String path) =>
+ open("post", host, port, path);
+
+ Future<HttpClientRequest> postUrl(Uri url) => _openUrl("post", url);
+
+ Future<HttpClientRequest> put(String host, int port, String path) =>
+ open("put", host, port, path);
+
+ Future<HttpClientRequest> putUrl(Uri url) => _openUrl("put", url);
+
+ Future<HttpClientRequest> delete(String host, int port, String path) =>
+ open("delete", host, port, path);
+
+ Future<HttpClientRequest> deleteUrl(Uri url) => _openUrl("delete", url);
+
+ Future<HttpClientRequest> head(String host, int port, String path) =>
+ open("head", host, port, path);
+
+ Future<HttpClientRequest> headUrl(Uri url) => _openUrl("head", url);
+
+ Future<HttpClientRequest> patch(String host, int port, String path) =>
+ open("patch", host, port, path);
+
+ Future<HttpClientRequest> patchUrl(Uri url) => _openUrl("patch", url);
+
+ void close({bool force: false}) {
+ _closing = true;
+ _closingForcefully = force;
+ _closeConnections(_closingForcefully);
+ assert(!_connectionTargets.values.any((s) => s.hasIdle));
+ assert(
+ !force || !_connectionTargets.values.any((s) => s._active.isNotEmpty));
+ }
+
+ set authenticate(Future<bool> f(Uri url, String scheme, String realm)) {
+ _authenticate = f;
+ }
+
+ void addCredentials(Uri url, String realm, HttpClientCredentials cr) {
+ _credentials.add(new _SiteCredentials(url, realm, cr));
+ }
+
+ set authenticateProxy(
+ Future<bool> f(String host, int port, String scheme, String realm)) {
+ _authenticateProxy = f;
+ }
+
+ void addProxyCredentials(
+ String host, int port, String realm, HttpClientCredentials cr) {
+ _proxyCredentials.add(new _ProxyCredentials(host, port, realm, cr));
+ }
+
+ set findProxy(String f(Uri uri)) => _findProxy = f;
+
+ Future<_HttpClientRequest> _openUrl(String method, Uri uri) {
+ if (_closing) {
+ throw new StateError("Client is closed");
+ }
+
+ // Ignore any fragments on the request URI.
+ uri = uri.removeFragment();
+
+ if (method == null) {
+ throw new ArgumentError(method);
+ }
+ if (method != "CONNECT") {
+ if (uri.host.isEmpty) {
+ throw new ArgumentError("No host specified in URI $uri");
+ } else if (uri.scheme != "http" && uri.scheme != "https") {
+ throw new ArgumentError(
+ "Unsupported scheme '${uri.scheme}' in URI $uri");
+ }
+ }
+
+ bool isSecure = (uri.scheme == "https");
+ int port = uri.port;
+ if (port == 0) {
+ port =
+ isSecure ? HttpClient.defaultHttpsPort : HttpClient.defaultHttpPort;
+ }
+ // Check to see if a proxy server should be used for this connection.
+ var proxyConf = const _ProxyConfiguration.direct();
+ if (_findProxy != null) {
+ // TODO(sgjesse): Keep a map of these as normally only a few
+ // configuration strings will be used.
+ try {
+ proxyConf = new _ProxyConfiguration(_findProxy(uri));
+ } catch (error, stackTrace) {
+ return new Future.error(error, stackTrace);
+ }
+ }
+ return _getConnection(uri.host, port, proxyConf, isSecure)
+ .then((_ConnectionInfo info) {
+ _HttpClientRequest send(_ConnectionInfo info) {
+ return info.connection
+ .send(uri, port, method.toUpperCase(), info.proxy);
+ }
+
+ // If the connection was closed before the request was sent, create
+ // and use another connection.
+ if (info.connection.closed) {
+ return _getConnection(uri.host, port, proxyConf, isSecure).then(send);
+ }
+ return send(info);
+ });
+ }
+
+ Future<_HttpClientRequest> _openUrlFromRequest(
+ String method, Uri uri, _HttpClientRequest previous) {
+ // If the new URI is relative (to either '/' or some sub-path),
+ // construct a full URI from the previous one.
+ Uri resolved = previous.uri.resolveUri(uri);
+ return _openUrl(method, resolved).then((_HttpClientRequest request) {
+ request
+ // Only follow redirects if initial request did.
+ ..followRedirects = previous.followRedirects
+ // Allow same number of redirects.
+ ..maxRedirects = previous.maxRedirects;
+ // Copy headers.
+ for (var header in previous.headers._headers.keys) {
+ if (request.headers[header] == null) {
+ request.headers.set(header, previous.headers[header]);
+ }
+ }
+ return request
+ ..headers.chunkedTransferEncoding = false
+ ..contentLength = 0;
+ });
+ }
+
+ // Return a live connection to the idle pool.
+ void _returnConnection(_HttpClientConnection connection) {
+ _connectionTargets[connection.key].returnConnection(connection);
+ _connectionsChanged();
+ }
+
+ // Remove a closed connection from the active set.
+ void _connectionClosed(_HttpClientConnection connection) {
+ connection.stopTimer();
+ var connectionTarget = _connectionTargets[connection.key];
+ if (connectionTarget != null) {
+ connectionTarget.connectionClosed(connection);
+ if (connectionTarget.isEmpty) {
+ _connectionTargets.remove(connection.key);
+ }
+ _connectionsChanged();
+ }
+ }
+
+ void _connectionsChanged() {
+ if (_closing) {
+ _closeConnections(_closingForcefully);
+ }
+ }
+
+ void _closeConnections(bool force) {
+ for (var connectionTarget in _connectionTargets.values.toList()) {
+ connectionTarget.close(force);
+ }
+ }
+
+ _ConnectionTarget _getConnectionTarget(String host, int port, bool isSecure) {
+ String key = _HttpClientConnection.makeKey(isSecure, host, port);
+ return _connectionTargets.putIfAbsent(key, () {
+ return new _ConnectionTarget(key, host, port, isSecure, _context);
+ });
+ }
+
+ // Get a new _HttpClientConnection, from the matching _ConnectionTarget.
+ Future<_ConnectionInfo> _getConnection(String uriHost, int uriPort,
+ _ProxyConfiguration proxyConf, bool isSecure) {
+ Iterator<_Proxy> proxies = proxyConf.proxies.iterator;
+
+ Future<_ConnectionInfo> connect(error) {
+ if (!proxies.moveNext()) return new Future.error(error);
+ _Proxy proxy = proxies.current;
+ String host = proxy.isDirect ? uriHost : proxy.host;
+ int port = proxy.isDirect ? uriPort : proxy.port;
+ return _getConnectionTarget(host, port, isSecure)
+ .connect(uriHost, uriPort, proxy, this)
+ // On error, continue with next proxy.
+ .catchError(connect);
+ }
+
+ return connect(new HttpException("No proxies given"));
+ }
+
+ _SiteCredentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) {
+ // Look for credentials.
+ _SiteCredentials cr =
+ _credentials.fold(null, (_SiteCredentials prev, value) {
+ var siteCredentials = value as _SiteCredentials;
+ if (siteCredentials.applies(url, scheme)) {
+ if (prev == null) return value;
+ return siteCredentials.uri.path.length > prev.uri.path.length
+ ? siteCredentials
+ : prev;
+ } else {
+ return prev;
+ }
+ });
+ return cr;
+ }
+
+ _ProxyCredentials _findProxyCredentials(_Proxy proxy,
+ [_AuthenticationScheme scheme]) {
+ // Look for credentials.
+ var it = _proxyCredentials.iterator;
+ while (it.moveNext()) {
+ if (it.current.applies(proxy, scheme)) {
+ return it.current;
+ }
+ }
+ return null;
+ }
+
+ void _removeCredentials(_Credentials cr) {
+ int index = _credentials.indexOf(cr);
+ if (index != -1) {
+ _credentials.removeAt(index);
+ }
+ }
+
+ void _removeProxyCredentials(_Credentials cr) {
+ int index = _proxyCredentials.indexOf(cr);
+ if (index != -1) {
+ _proxyCredentials.removeAt(index);
+ }
+ }
+
+ static String _findProxyFromEnvironment(
+ Uri url, Map<String, String> environment) {
+ checkNoProxy(String option) {
+ if (option == null) return null;
+ Iterator<String> names = option.split(",").map((s) => s.trim()).iterator;
+ while (names.moveNext()) {
+ var name = names.current;
+ if ((name.startsWith("[") &&
+ name.endsWith("]") &&
+ "[${url.host}]" == name) ||
+ (name.isNotEmpty && url.host.endsWith(name))) {
+ return "DIRECT";
+ }
+ }
+ return null;
+ }
+
+ checkProxy(String option) {
+ if (option == null) return null;
+ option = option.trim();
+ if (option.isEmpty) return null;
+ int pos = option.indexOf("://");
+ if (pos >= 0) {
+ option = option.substring(pos + 3);
+ }
+ pos = option.indexOf("/");
+ if (pos >= 0) {
+ option = option.substring(0, pos);
+ }
+ // Add default port if no port configured.
+ if (option.indexOf("[") == 0) {
+ var pos = option.lastIndexOf(":");
+ if (option.indexOf("]") > pos) option = "$option:1080";
+ } else {
+ if (option.indexOf(":") == -1) option = "$option:1080";
+ }
+ return "PROXY $option";
+ }
+
+ // Default to using the process current environment.
+ if (environment == null) environment = _platformEnvironmentCache;
+
+ String proxyCfg;
+
+ String noProxy = environment["no_proxy"];
+ if (noProxy == null) noProxy = environment["NO_PROXY"];
+ if ((proxyCfg = checkNoProxy(noProxy)) != null) {
+ return proxyCfg;
+ }
+
+ if (url.scheme == "http") {
+ String proxy = environment["http_proxy"];
+ if (proxy == null) proxy = environment["HTTP_PROXY"];
+ if ((proxyCfg = checkProxy(proxy)) != null) {
+ return proxyCfg;
+ }
+ } else if (url.scheme == "https") {
+ String proxy = environment["https_proxy"];
+ if (proxy == null) proxy = environment["HTTPS_PROXY"];
+ if ((proxyCfg = checkProxy(proxy)) != null) {
+ return proxyCfg;
+ }
+ }
+ return "DIRECT";
+ }
+
+ static Map<String, String> _platformEnvironmentCache = Platform.environment;
+}
+
+class _HttpConnection extends LinkedListEntry<_HttpConnection>
+ with _ServiceObject {
+ static const _ACTIVE = 0;
+ static const _IDLE = 1;
+ static const _CLOSING = 2;
+ static const _DETACHED = 3;
+
+ // Use HashMap, as we don't need to keep order.
+ static Map<int, _HttpConnection> _connections =
+ new HashMap<int, _HttpConnection>();
+
+ final /*_ServerSocket*/ _socket;
+ final _HttpServer _httpServer;
+ final _HttpParser _httpParser;
+ int _state = _IDLE;
+ StreamSubscription _subscription;
+ bool _idleMark = false;
+ Future _streamFuture;
+
+ _HttpConnection(this._socket, this._httpServer)
+ : _httpParser = new _HttpParser.requestParser() {
+ _connections[_serviceId] = this;
+ _httpParser.listenToStream(_socket);
+ _subscription = _httpParser.listen((incoming) {
+ _httpServer._markActive(this);
+ // If the incoming was closed, close the connection.
+ incoming.dataDone.then((closing) {
+ if (closing) destroy();
+ });
+ // Only handle one incoming request at the time. Keep the
+ // stream paused until the request has been send.
+ _subscription.pause();
+ _state = _ACTIVE;
+ var outgoing = new _HttpOutgoing(_socket);
+ var response = new _HttpResponse(
+ incoming.uri,
+ incoming.headers.protocolVersion,
+ outgoing,
+ _httpServer.defaultResponseHeaders,
+ _httpServer.serverHeader);
+ var request = new _HttpRequest(response, incoming, _httpServer, this);
+ _streamFuture = outgoing.done.then((_) {
+ response.deadline = null;
+ if (_state == _DETACHED) return;
+ if (response.persistentConnection &&
+ request.persistentConnection &&
+ incoming.fullBodyRead &&
+ !_httpParser.upgrade &&
+ !_httpServer.closed) {
+ _state = _IDLE;
+ _idleMark = false;
+ _httpServer._markIdle(this);
+ // Resume the subscription for incoming requests as the
+ // request is now processed.
+ _subscription.resume();
+ } else {
+ // Close socket, keep-alive not used or body sent before
+ // received data was handled.
+ destroy();
+ }
+ }, onError: (_) {
+ destroy();
+ });
+ outgoing.ignoreBody = request.method == "HEAD";
+ response._httpRequest = request;
+ _httpServer._handleRequest(request);
+ }, onDone: () {
+ destroy();
+ }, onError: (error) {
+ // Ignore failed requests that was closed before headers was received.
+ destroy();
+ });
+ }
+
+ void markIdle() {
+ _idleMark = true;
+ }
+
+ bool get isMarkedIdle => _idleMark;
+
+ void destroy() {
+ if (_state == _CLOSING || _state == _DETACHED) return;
+ _state = _CLOSING;
+ _socket.destroy();
+ _httpServer._connectionClosed(this);
+ _connections.remove(_serviceId);
+ }
+
+ Future<Socket> detachSocket() {
+ _state = _DETACHED;
+ // Remove connection from server.
+ _httpServer._connectionClosed(this);
+
+ _HttpDetachedIncoming detachedIncoming = _httpParser.detachIncoming();
+
+ return _streamFuture.then((_) {
+ _connections.remove(_serviceId);
+ return new _DetachedSocket(_socket, detachedIncoming);
+ });
+ }
+
+ HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket);
+
+ bool get _isActive => _state == _ACTIVE;
+ bool get _isIdle => _state == _IDLE;
+ bool get _isClosing => _state == _CLOSING;
+ bool get _isDetached => _state == _DETACHED;
+
+ String get _serviceTypePath => 'io/http/serverconnections';
+ String get _serviceTypeName => 'HttpServerConnection';
+
+ Map _toJSON(bool ref) {
+ var name = "${_socket.address.host}:${_socket.port} <-> "
+ "${_socket.remoteAddress.host}:${_socket.remotePort}";
+ var r = <String, dynamic>{
+ 'id': _servicePath,
+ 'type': _serviceType(ref),
+ 'name': name,
+ 'user_name': name,
+ };
+ if (ref) {
+ return r;
+ }
+ r['server'] = _httpServer._toJSON(true);
+ try {
+ r['socket'] = _socket._toJSON(true);
+ } catch (_) {
+ r['socket'] = {
+ 'id': _servicePath,
+ 'type': '@Socket',
+ 'name': 'UserSocket',
+ 'user_name': 'UserSocket',
+ };
+ }
+ switch (_state) {
+ case _ACTIVE:
+ r['state'] = "Active";
+ break;
+ case _IDLE:
+ r['state'] = "Idle";
+ break;
+ case _CLOSING:
+ r['state'] = "Closing";
+ break;
+ case _DETACHED:
+ r['state'] = "Detached";
+ break;
+ default:
+ r['state'] = 'Unknown';
+ break;
+ }
+ return r;
+ }
+}
+
+// HTTP server waiting for socket connections.
+class _HttpServer extends Stream<HttpRequest>
+ with _ServiceObject
+ implements HttpServer {
+ // Use default Map so we keep order.
+ static Map<int, _HttpServer> _servers = new Map<int, _HttpServer>();
+
+ String serverHeader;
+ final HttpHeaders defaultResponseHeaders = _initDefaultResponseHeaders();
+ bool autoCompress = false;
+
+ Duration _idleTimeout;
+ Timer _idleTimer;
+
+ static Future<HttpServer> bind(
+ address, int port, int backlog, bool v6Only, bool shared) {
+ return ServerSocket.bind(address, port,
+ backlog: backlog, v6Only: v6Only, shared: shared)
+ .then<HttpServer>((socket) {
+ return new _HttpServer._(socket, true);
+ });
+ }
+
+ static Future<HttpServer> bindSecure(
+ address,
+ int port,
+ SecurityContext context,
+ int backlog,
+ bool v6Only,
+ bool requestClientCertificate,
+ bool shared) {
+ return SecureServerSocket.bind(address, port, context,
+ backlog: backlog,
+ v6Only: v6Only,
+ requestClientCertificate: requestClientCertificate,
+ shared: shared)
+ .then<HttpServer>((socket) {
+ return new _HttpServer._(socket, true);
+ });
+ }
+
+ _HttpServer._(this._serverSocket, this._closeServer) {
+ _controller =
+ new StreamController<HttpRequest>(sync: true, onCancel: close);
+ idleTimeout = const Duration(seconds: 120);
+ _servers[_serviceId] = this;
+ }
+
+ _HttpServer.listenOn(this._serverSocket) : _closeServer = false {
+ _controller =
+ new StreamController<HttpRequest>(sync: true, onCancel: close);
+ idleTimeout = const Duration(seconds: 120);
+ _servers[_serviceId] = this;
+ }
+
+ static HttpHeaders _initDefaultResponseHeaders() {
+ var defaultResponseHeaders = new _HttpHeaders('1.1');
+ defaultResponseHeaders.contentType = ContentType.text;
+ defaultResponseHeaders.set('X-Frame-Options', 'SAMEORIGIN');
+ defaultResponseHeaders.set('X-Content-Type-Options', 'nosniff');
+ defaultResponseHeaders.set('X-XSS-Protection', '1; mode=block');
+ return defaultResponseHeaders;
+ }
+
+ Duration get idleTimeout => _idleTimeout;
+
+ void set idleTimeout(Duration duration) {
+ if (_idleTimer != null) {
+ _idleTimer.cancel();
+ _idleTimer = null;
+ }
+ _idleTimeout = duration;
+ if (_idleTimeout != null) {
+ _idleTimer = new Timer.periodic(_idleTimeout, (_) {
+ for (var idle in _idleConnections.toList()) {
+ if (idle.isMarkedIdle) {
+ idle.destroy();
+ } else {
+ idle.markIdle();
+ }
+ }
+ });
+ }
+ }
+
+ StreamSubscription<HttpRequest> listen(void onData(HttpRequest event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ _serverSocket.listen((Socket socket) {
+ socket.setOption(SocketOption.tcpNoDelay, true);
+ // Accept the client connection.
+ _HttpConnection connection = new _HttpConnection(socket, this);
+ _idleConnections.add(connection);
+ }, onError: (error, stackTrace) {
+ // Ignore HandshakeExceptions as they are bound to a single request,
+ // and are not fatal for the server.
+ if (error is! HandshakeException) {
+ _controller.addError(error, stackTrace);
+ }
+ }, onDone: _controller.close);
+ return _controller.stream.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ Future close({bool force: false}) {
+ closed = true;
+ Future result;
+ if (_serverSocket != null && _closeServer) {
+ result = _serverSocket.close();
+ } else {
+ result = new Future.value();
+ }
+ idleTimeout = null;
+ if (force) {
+ for (var c in _activeConnections.toList()) {
+ c.destroy();
+ }
+ assert(_activeConnections.isEmpty);
+ }
+ for (var c in _idleConnections.toList()) {
+ c.destroy();
+ }
+ _maybePerformCleanup();
+ return result;
+ }
+
+ void _maybePerformCleanup() {
+ if (closed &&
+ _idleConnections.isEmpty &&
+ _activeConnections.isEmpty &&
+ _sessionManagerInstance != null) {
+ _sessionManagerInstance.close();
+ _sessionManagerInstance = null;
+ _servers.remove(_serviceId);
+ }
+ }
+
+ int get port {
+ if (closed) throw new HttpException("HttpServer is not bound to a socket");
+ return _serverSocket.port;
+ }
+
+ InternetAddress get address {
+ if (closed) throw new HttpException("HttpServer is not bound to a socket");
+ return _serverSocket.address;
+ }
+
+ set sessionTimeout(int timeout) {
+ _sessionManager.sessionTimeout = timeout;
+ }
+
+ void _handleRequest(_HttpRequest request) {
+ if (!closed) {
+ _controller.add(request);
+ } else {
+ request._httpConnection.destroy();
+ }
+ }
+
+ void _connectionClosed(_HttpConnection connection) {
+ // Remove itself from either idle or active connections.
+ connection.unlink();
+ _maybePerformCleanup();
+ }
+
+ void _markIdle(_HttpConnection connection) {
+ _activeConnections.remove(connection);
+ _idleConnections.add(connection);
+ }
+
+ void _markActive(_HttpConnection connection) {
+ _idleConnections.remove(connection);
+ _activeConnections.add(connection);
+ }
+
+ _HttpSessionManager get _sessionManager {
+ // Lazy init.
+ if (_sessionManagerInstance == null) {
+ _sessionManagerInstance = new _HttpSessionManager();
+ }
+ return _sessionManagerInstance;
+ }
+
+ HttpConnectionsInfo connectionsInfo() {
+ HttpConnectionsInfo result = new HttpConnectionsInfo();
+ result.total = _activeConnections.length + _idleConnections.length;
+ _activeConnections.forEach((_HttpConnection conn) {
+ if (conn._isActive) {
+ result.active++;
+ } else {
+ assert(conn._isClosing);
+ result.closing++;
+ }
+ });
+ _idleConnections.forEach((_HttpConnection conn) {
+ result.idle++;
+ assert(conn._isIdle);
+ });
+ return result;
+ }
+
+ String get _serviceTypePath => 'io/http/servers';
+ String get _serviceTypeName => 'HttpServer';
+
+ Map<String, dynamic> _toJSON(bool ref) {
+ var r = <String, dynamic>{
+ 'id': _servicePath,
+ 'type': _serviceType(ref),
+ 'name': '${address.host}:$port',
+ 'user_name': '${address.host}:$port',
+ };
+ if (ref) {
+ return r;
+ }
+ try {
+ r['socket'] = _serverSocket._toJSON(true);
+ } catch (_) {
+ r['socket'] = {
+ 'id': _servicePath,
+ 'type': '@Socket',
+ 'name': 'UserSocket',
+ 'user_name': 'UserSocket',
+ };
+ }
+ r['port'] = port;
+ r['address'] = address.host;
+ r['active'] = _activeConnections.map((c) => c._toJSON(true)).toList();
+ r['idle'] = _idleConnections.map((c) => c._toJSON(true)).toList();
+ r['closed'] = closed;
+ return r;
+ }
+
+ _HttpSessionManager _sessionManagerInstance;
+
+ // Indicated if the http server has been closed.
+ bool closed = false;
+
+ // The server listen socket. Untyped as it can be both ServerSocket and
+ // SecureServerSocket.
+ final dynamic /*ServerSocket|SecureServerSocket*/ _serverSocket;
+ final bool _closeServer;
+
+ // Set of currently connected clients.
+ final LinkedList<_HttpConnection> _activeConnections =
+ new LinkedList<_HttpConnection>();
+ final LinkedList<_HttpConnection> _idleConnections =
+ new LinkedList<_HttpConnection>();
+ StreamController<HttpRequest> _controller;
+}
+
+class _ProxyConfiguration {
+ static const String PROXY_PREFIX = "PROXY ";
+ static const String DIRECT_PREFIX = "DIRECT";
+
+ _ProxyConfiguration(String configuration) : proxies = new List<_Proxy>() {
+ if (configuration == null) {
+ throw new HttpException("Invalid proxy configuration $configuration");
+ }
+ List<String> list = configuration.split(";");
+ list.forEach((String proxy) {
+ proxy = proxy.trim();
+ if (!proxy.isEmpty) {
+ if (proxy.startsWith(PROXY_PREFIX)) {
+ String username;
+ String password;
+ // Skip the "PROXY " prefix.
+ proxy = proxy.substring(PROXY_PREFIX.length).trim();
+ // Look for proxy authentication.
+ int at = proxy.indexOf("@");
+ if (at != -1) {
+ String userinfo = proxy.substring(0, at).trim();
+ proxy = proxy.substring(at + 1).trim();
+ int colon = userinfo.indexOf(":");
+ if (colon == -1 || colon == 0 || colon == proxy.length - 1) {
+ throw new HttpException(
+ "Invalid proxy configuration $configuration");
+ }
+ username = userinfo.substring(0, colon).trim();
+ password = userinfo.substring(colon + 1).trim();
+ }
+ // Look for proxy host and port.
+ int colon = proxy.lastIndexOf(":");
+ if (colon == -1 || colon == 0 || colon == proxy.length - 1) {
+ throw new HttpException(
+ "Invalid proxy configuration $configuration");
+ }
+ String host = proxy.substring(0, colon).trim();
+ if (host.startsWith("[") && host.endsWith("]")) {
+ host = host.substring(1, host.length - 1);
+ }
+ String portString = proxy.substring(colon + 1).trim();
+ int port;
+ try {
+ port = int.parse(portString);
+ } on FormatException catch (e) {
+ throw new HttpException(
+ "Invalid proxy configuration $configuration, "
+ "invalid port '$portString'");
+ }
+ proxies.add(new _Proxy(host, port, username, password));
+ } else if (proxy.trim() == DIRECT_PREFIX) {
+ proxies.add(new _Proxy.direct());
+ } else {
+ throw new HttpException("Invalid proxy configuration $configuration");
+ }
+ }
+ });
+ }
+
+ const _ProxyConfiguration.direct() : proxies = const [const _Proxy.direct()];
+
+ final List<_Proxy> proxies;
+}
+
+class _Proxy {
+ final String host;
+ final int port;
+ final String username;
+ final String password;
+ final bool isDirect;
+
+ const _Proxy(this.host, this.port, this.username, this.password)
+ : isDirect = false;
+ const _Proxy.direct()
+ : host = null,
+ port = null,
+ username = null,
+ password = null,
+ isDirect = true;
+
+ bool get isAuthenticated => username != null;
+}
+
+class _HttpConnectionInfo implements HttpConnectionInfo {
+ InternetAddress remoteAddress;
+ int remotePort;
+ int localPort;
+
+ static _HttpConnectionInfo create(Socket socket) {
+ if (socket == null) return null;
+ try {
+ _HttpConnectionInfo info = new _HttpConnectionInfo();
+ return info
+ ..remoteAddress = socket.remoteAddress
+ ..remotePort = socket.remotePort
+ ..localPort = socket.port;
+ } catch (e) {}
+ return null;
+ }
+}
+
+class _DetachedSocket extends Stream<Uint8List> implements Socket {
+ final Stream<Uint8List> _incoming;
+ final Socket _socket;
+
+ _DetachedSocket(this._socket, this._incoming);
+
+ StreamSubscription<Uint8List> listen(void onData(Uint8List event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ return _incoming.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ Encoding get encoding => _socket.encoding;
+
+ void set encoding(Encoding value) {
+ _socket.encoding = value;
+ }
+
+ void write(Object obj) {
+ _socket.write(obj);
+ }
+
+ void writeln([Object obj = ""]) {
+ _socket.writeln(obj);
+ }
+
+ void writeCharCode(int charCode) {
+ _socket.writeCharCode(charCode);
+ }
+
+ void writeAll(Iterable objects, [String separator = ""]) {
+ _socket.writeAll(objects, separator);
+ }
+
+ void add(List<int> bytes) {
+ _socket.add(bytes);
+ }
+
+ void addError(error, [StackTrace stackTrace]) =>
+ _socket.addError(error, stackTrace);
+
+ Future addStream(Stream<List<int>> stream) {
+ return _socket.addStream(stream);
+ }
+
+ void destroy() {
+ _socket.destroy();
+ }
+
+ Future flush() => _socket.flush();
+
+ Future close() => _socket.close();
+
+ Future get done => _socket.done;
+
+ int get port => _socket.port;
+
+ InternetAddress get address => _socket.address;
+
+ InternetAddress get remoteAddress => _socket.remoteAddress;
+
+ int get remotePort => _socket.remotePort;
+
+ bool setOption(SocketOption option, bool enabled) {
+ return _socket.setOption(option, enabled);
+ }
+
+ Uint8List getRawOption(RawSocketOption option) {
+ return _socket.getRawOption(option);
+ }
+
+ void setRawOption(RawSocketOption option) {
+ _socket.setRawOption(option);
+ }
+
+ Map _toJSON(bool ref) {
+ return (_socket as dynamic)._toJSON(ref);
+ }
+}
+
+class _AuthenticationScheme {
+ final int _scheme;
+
+ static const UNKNOWN = const _AuthenticationScheme(-1);
+ static const BASIC = const _AuthenticationScheme(0);
+ static const DIGEST = const _AuthenticationScheme(1);
+
+ const _AuthenticationScheme(this._scheme);
+
+ factory _AuthenticationScheme.fromString(String scheme) {
+ if (scheme.toLowerCase() == "basic") return BASIC;
+ if (scheme.toLowerCase() == "digest") return DIGEST;
+ return UNKNOWN;
+ }
+
+ String toString() {
+ if (this == BASIC) return "Basic";
+ if (this == DIGEST) return "Digest";
+ return "Unknown";
+ }
+}
+
+abstract class _Credentials {
+ _HttpClientCredentials credentials;
+ String realm;
+ bool used = false;
+
+ // Digest specific fields.
+ String ha1;
+ String nonce;
+ String algorithm;
+ String qop;
+ int nonceCount;
+
+ _Credentials(this.credentials, this.realm) {
+ if (credentials.scheme == _AuthenticationScheme.DIGEST) {
+ // Calculate the H(A1) value once. There is no mentioning of
+ // username/password encoding in RFC 2617. However there is an
+ // open draft for adding an additional accept-charset parameter to
+ // the WWW-Authenticate and Proxy-Authenticate headers, see
+ // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For
+ // now always use UTF-8 encoding.
+ _HttpClientDigestCredentials creds = credentials;
+ var hasher = new _MD5()
+ ..add(utf8.encode(creds.username))
+ ..add([_CharCode.COLON])
+ ..add(realm.codeUnits)
+ ..add([_CharCode.COLON])
+ ..add(utf8.encode(creds.password));
+ ha1 = _CryptoUtils.bytesToHex(hasher.close());
+ }
+ }
+
+ _AuthenticationScheme get scheme => credentials.scheme;
+
+ void authorize(HttpClientRequest request);
+}
+
+class _SiteCredentials extends _Credentials {
+ Uri uri;
+
+ _SiteCredentials(this.uri, realm, _HttpClientCredentials creds)
+ : super(creds, realm);
+
+ bool applies(Uri uri, _AuthenticationScheme scheme) {
+ if (scheme != null && credentials.scheme != scheme) return false;
+ if (uri.host != this.uri.host) return false;
+ int thisPort =
+ this.uri.port == 0 ? HttpClient.defaultHttpPort : this.uri.port;
+ int otherPort = uri.port == 0 ? HttpClient.defaultHttpPort : uri.port;
+ if (otherPort != thisPort) return false;
+ return uri.path.startsWith(this.uri.path);
+ }
+
+ void authorize(HttpClientRequest request) {
+ // Digest credentials cannot be used without a nonce from the
+ // server.
+ if (credentials.scheme == _AuthenticationScheme.DIGEST && nonce == null) {
+ return;
+ }
+ credentials.authorize(this, request);
+ used = true;
+ }
+}
+
+class _ProxyCredentials extends _Credentials {
+ String host;
+ int port;
+
+ _ProxyCredentials(this.host, this.port, realm, _HttpClientCredentials creds)
+ : super(creds, realm);
+
+ bool applies(_Proxy proxy, _AuthenticationScheme scheme) {
+ if (scheme != null && credentials.scheme != scheme) return false;
+ return proxy.host == host && proxy.port == port;
+ }
+
+ void authorize(HttpClientRequest request) {
+ // Digest credentials cannot be used without a nonce from the
+ // server.
+ if (credentials.scheme == _AuthenticationScheme.DIGEST && nonce == null) {
+ return;
+ }
+ credentials.authorizeProxy(this, request);
+ }
+}
+
+abstract class _HttpClientCredentials implements HttpClientCredentials {
+ _AuthenticationScheme get scheme;
+ void authorize(_Credentials credentials, HttpClientRequest request);
+ void authorizeProxy(_ProxyCredentials credentials, HttpClientRequest request);
+}
+
+class _HttpClientBasicCredentials extends _HttpClientCredentials
+ implements HttpClientBasicCredentials {
+ String username;
+ String password;
+
+ _HttpClientBasicCredentials(this.username, this.password);
+
+ _AuthenticationScheme get scheme => _AuthenticationScheme.BASIC;
+
+ String authorization() {
+ // There is no mentioning of username/password encoding in RFC
+ // 2617. However there is an open draft for adding an additional
+ // accept-charset parameter to the WWW-Authenticate and
+ // Proxy-Authenticate headers, see
+ // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For
+ // now always use UTF-8 encoding.
+ String auth =
+ _CryptoUtils.bytesToBase64(utf8.encode("$username:$password"));
+ return "Basic $auth";
+ }
+
+ void authorize(_Credentials _, HttpClientRequest request) {
+ request.headers.set(HttpHeaders.authorizationHeader, authorization());
+ }
+
+ void authorizeProxy(_ProxyCredentials _, HttpClientRequest request) {
+ request.headers.set(HttpHeaders.proxyAuthorizationHeader, authorization());
+ }
+}
+
+class _HttpClientDigestCredentials extends _HttpClientCredentials
+ implements HttpClientDigestCredentials {
+ String username;
+ String password;
+
+ _HttpClientDigestCredentials(this.username, this.password);
+
+ _AuthenticationScheme get scheme => _AuthenticationScheme.DIGEST;
+
+ String authorization(_Credentials credentials, _HttpClientRequest request) {
+ String requestUri = request._requestUri();
+ _MD5 hasher = new _MD5()
+ ..add(request.method.codeUnits)
+ ..add([_CharCode.COLON])
+ ..add(requestUri.codeUnits);
+ var ha2 = _CryptoUtils.bytesToHex(hasher.close());
+
+ String qop;
+ String cnonce;
+ String nc;
+ var x;
+ hasher = new _MD5()..add(credentials.ha1.codeUnits)..add([_CharCode.COLON]);
+ if (credentials.qop == "auth") {
+ qop = credentials.qop;
+ cnonce = _CryptoUtils.bytesToHex(_CryptoUtils.getRandomBytes(4));
+ ++credentials.nonceCount;
+ nc = credentials.nonceCount.toRadixString(16);
+ nc = "00000000".substring(0, 8 - nc.length + 1) + nc;
+ hasher
+ ..add(credentials.nonce.codeUnits)
+ ..add([_CharCode.COLON])
+ ..add(nc.codeUnits)
+ ..add([_CharCode.COLON])
+ ..add(cnonce.codeUnits)
+ ..add([_CharCode.COLON])
+ ..add(credentials.qop.codeUnits)
+ ..add([_CharCode.COLON])
+ ..add(ha2.codeUnits);
+ } else {
+ hasher
+ ..add(credentials.nonce.codeUnits)
+ ..add([_CharCode.COLON])
+ ..add(ha2.codeUnits);
+ }
+ var response = _CryptoUtils.bytesToHex(hasher.close());
+
+ StringBuffer buffer = new StringBuffer()
+ ..write('Digest ')
+ ..write('username="$username"')
+ ..write(', realm="${credentials.realm}"')
+ ..write(', nonce="${credentials.nonce}"')
+ ..write(', uri="$requestUri"')
+ ..write(', algorithm="${credentials.algorithm}"');
+ if (qop == "auth") {
+ buffer
+ ..write(', qop="$qop"')
+ ..write(', cnonce="$cnonce"')
+ ..write(', nc="$nc"');
+ }
+ buffer.write(', response="$response"');
+ return buffer.toString();
+ }
+
+ void authorize(_Credentials credentials, HttpClientRequest request) {
+ request.headers.set(
+ HttpHeaders.authorizationHeader, authorization(credentials, request));
+ }
+
+ void authorizeProxy(
+ _ProxyCredentials credentials, HttpClientRequest request) {
+ request.headers.set(HttpHeaders.proxyAuthorizationHeader,
+ authorization(credentials, request));
+ }
+}
+
+class _RedirectInfo implements RedirectInfo {
+ final int statusCode;
+ final String method;
+ final Uri location;
+ const _RedirectInfo(this.statusCode, this.method, this.location);
+}
+
+String _getHttpVersion() {
+ var version = Platform.version;
+ // Only include major and minor version numbers.
+ int index = version.indexOf('.', version.indexOf('.') + 1);
+ version = version.substring(0, index);
+ return 'Dart/$version (dart:io)';
+}
diff --git a/sdk_nnbd/lib/_http/http_parser.dart b/sdk_nnbd/lib/_http/http_parser.dart
new file mode 100644
index 0000000..bd85b2b
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http_parser.dart
@@ -0,0 +1,1062 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+// Global constants.
+class _Const {
+ // Bytes for "HTTP".
+ static const HTTP = const [72, 84, 84, 80];
+ // Bytes for "HTTP/1.".
+ static const HTTP1DOT = const [72, 84, 84, 80, 47, 49, 46];
+ // Bytes for "HTTP/1.0".
+ static const HTTP10 = const [72, 84, 84, 80, 47, 49, 46, 48];
+ // Bytes for "HTTP/1.1".
+ static const HTTP11 = const [72, 84, 84, 80, 47, 49, 46, 49];
+
+ static const bool T = true;
+ static const bool F = false;
+ // Loopup-map for the following characters: '()<>@,;:\\"/[]?={} \t'.
+ static const SEPARATOR_MAP = const [
+ F, F, F, F, F, F, F, F, F, T, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+ F, F, F, F, F, F, F, F, T, F, T, F, F, F, F, F, T, T, F, F, T, F, F, T, //
+ F, F, F, F, F, F, F, F, F, F, T, T, T, T, T, T, T, F, F, F, F, F, F, F, //
+ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, T, T, T, F, F, //
+ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+ F, F, F, T, F, T, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, //
+ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F
+ ];
+}
+
+// Frequently used character codes.
+class _CharCode {
+ static const int HT = 9;
+ static const int LF = 10;
+ static const int CR = 13;
+ static const int SP = 32;
+ static const int AMPERSAND = 38;
+ static const int COMMA = 44;
+ static const int DASH = 45;
+ static const int SLASH = 47;
+ static const int ZERO = 48;
+ static const int ONE = 49;
+ static const int COLON = 58;
+ static const int SEMI_COLON = 59;
+ static const int EQUAL = 61;
+}
+
+// States of the HTTP parser state machine.
+class _State {
+ static const int START = 0;
+ static const int METHOD_OR_RESPONSE_HTTP_VERSION = 1;
+ static const int RESPONSE_HTTP_VERSION = 2;
+ static const int REQUEST_LINE_METHOD = 3;
+ static const int REQUEST_LINE_URI = 4;
+ static const int REQUEST_LINE_HTTP_VERSION = 5;
+ static const int REQUEST_LINE_ENDING = 6;
+ static const int RESPONSE_LINE_STATUS_CODE = 7;
+ static const int RESPONSE_LINE_REASON_PHRASE = 8;
+ static const int RESPONSE_LINE_ENDING = 9;
+ static const int HEADER_START = 10;
+ static const int HEADER_FIELD = 11;
+ static const int HEADER_VALUE_START = 12;
+ static const int HEADER_VALUE = 13;
+ static const int HEADER_VALUE_FOLDING_OR_ENDING = 14;
+ static const int HEADER_VALUE_FOLD_OR_END = 15;
+ static const int HEADER_ENDING = 16;
+
+ static const int CHUNK_SIZE_STARTING_CR = 17;
+ static const int CHUNK_SIZE_STARTING_LF = 18;
+ static const int CHUNK_SIZE = 19;
+ static const int CHUNK_SIZE_EXTENSION = 20;
+ static const int CHUNK_SIZE_ENDING = 21;
+ static const int CHUNKED_BODY_DONE_CR = 22;
+ static const int CHUNKED_BODY_DONE_LF = 23;
+ static const int BODY = 24;
+ static const int CLOSED = 25;
+ static const int UPGRADED = 26;
+ static const int FAILURE = 27;
+
+ static const int FIRST_BODY_STATE = CHUNK_SIZE_STARTING_CR;
+}
+
+// HTTP version of the request or response being parsed.
+class _HttpVersion {
+ static const int UNDETERMINED = 0;
+ static const int HTTP10 = 1;
+ static const int HTTP11 = 2;
+}
+
+// States of the HTTP parser state machine.
+class _MessageType {
+ static const int UNDETERMINED = 0;
+ static const int REQUEST = 1;
+ static const int RESPONSE = 0;
+}
+
+/**
+ * The _HttpDetachedStreamSubscription takes a subscription and some extra data,
+ * and makes it possible to "inject" the data in from of other data events
+ * from the subscription.
+ *
+ * It does so by overriding pause/resume, so that once the
+ * _HttpDetachedStreamSubscription is resumed, it'll deliver the data before
+ * resuming the underlaying subscription.
+ */
+class _HttpDetachedStreamSubscription implements StreamSubscription<Uint8List> {
+ StreamSubscription<Uint8List> _subscription;
+ Uint8List _injectData;
+ bool _isCanceled = false;
+ int _pauseCount = 1;
+ Function _userOnData;
+ bool _scheduled = false;
+
+ _HttpDetachedStreamSubscription(
+ this._subscription, this._injectData, this._userOnData);
+
+ bool get isPaused => _subscription.isPaused;
+
+ Future<T> asFuture<T>([T futureValue]) =>
+ _subscription.asFuture<T>(futureValue);
+
+ Future cancel() {
+ _isCanceled = true;
+ _injectData = null;
+ return _subscription.cancel();
+ }
+
+ void onData(void handleData(Uint8List data)) {
+ _userOnData = handleData;
+ _subscription.onData(handleData);
+ }
+
+ void onDone(void handleDone()) {
+ _subscription.onDone(handleDone);
+ }
+
+ void onError(Function handleError) {
+ _subscription.onError(handleError);
+ }
+
+ void pause([Future resumeSignal]) {
+ if (_injectData == null) {
+ _subscription.pause(resumeSignal);
+ } else {
+ _pauseCount++;
+ if (resumeSignal != null) {
+ resumeSignal.whenComplete(resume);
+ }
+ }
+ }
+
+ void resume() {
+ if (_injectData == null) {
+ _subscription.resume();
+ } else {
+ _pauseCount--;
+ _maybeScheduleData();
+ }
+ }
+
+ void _maybeScheduleData() {
+ if (_scheduled) return;
+ if (_pauseCount != 0) return;
+ _scheduled = true;
+ scheduleMicrotask(() {
+ _scheduled = false;
+ if (_pauseCount > 0 || _isCanceled) return;
+ var data = _injectData;
+ _injectData = null;
+ // To ensure that 'subscription.isPaused' is false, we resume the
+ // subscription here. This is fine as potential events are delayed.
+ _subscription.resume();
+ if (_userOnData != null) {
+ _userOnData(data);
+ }
+ });
+ }
+}
+
+class _HttpDetachedIncoming extends Stream<Uint8List> {
+ final StreamSubscription<Uint8List> subscription;
+ final Uint8List bufferedData;
+
+ _HttpDetachedIncoming(this.subscription, this.bufferedData);
+
+ StreamSubscription<Uint8List> listen(void onData(Uint8List event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ if (subscription != null) {
+ subscription
+ ..onData(onData)
+ ..onError(onError)
+ ..onDone(onDone);
+ if (bufferedData == null) {
+ return subscription..resume();
+ }
+ return new _HttpDetachedStreamSubscription(
+ subscription, bufferedData, onData)
+ ..resume();
+ } else {
+ // TODO(26379): add test for this branch.
+ return new Stream<Uint8List>.fromIterable([bufferedData]).listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+ }
+}
+
+/**
+ * HTTP parser which parses the data stream given to [consume].
+ *
+ * If an HTTP parser error occurs, the parser will signal an error to either
+ * the current _HttpIncoming or the _parser itself.
+ *
+ * The connection upgrades (e.g. switching from HTTP/1.1 to the
+ * WebSocket protocol) is handled in a special way. If connection
+ * upgrade is specified in the headers, then on the callback to
+ * [:responseStart:] the [:upgrade:] property on the [:HttpParser:]
+ * object will be [:true:] indicating that from now on the protocol is
+ * not HTTP anymore and no more callbacks will happen, that is
+ * [:dataReceived:] and [:dataEnd:] are not called in this case as
+ * there is no more HTTP data. After the upgrade the method
+ * [:readUnparsedData:] can be used to read any remaining bytes in the
+ * HTTP parser which are part of the protocol the connection is
+ * upgrading to. These bytes cannot be processed by the HTTP parser
+ * and should be handled according to whatever protocol is being
+ * upgraded to.
+ */
+class _HttpParser extends Stream<_HttpIncoming> {
+ // State.
+ bool _parserCalled = false;
+
+ // The data that is currently being parsed.
+ Uint8List _buffer;
+ int _index;
+
+ final bool _requestParser;
+ int _state;
+ int _httpVersionIndex;
+ int _messageType;
+ int _statusCode = 0;
+ int _statusCodeLength = 0;
+ final List<int> _method = [];
+ final List<int> _uri_or_reason_phrase = [];
+ final List<int> _headerField = [];
+ final List<int> _headerValue = [];
+
+ int _httpVersion;
+ int _transferLength = -1;
+ bool _persistentConnection;
+ bool _connectionUpgrade;
+ bool _chunked;
+
+ bool _noMessageBody = false;
+ int _remainingContent = -1;
+
+ _HttpHeaders _headers;
+
+ // The current incoming connection.
+ _HttpIncoming _incoming;
+ StreamSubscription<Uint8List> _socketSubscription;
+ bool _paused = true;
+ bool _bodyPaused = false;
+ StreamController<_HttpIncoming> _controller;
+ StreamController<Uint8List> _bodyController;
+
+ factory _HttpParser.requestParser() {
+ return new _HttpParser._(true);
+ }
+
+ factory _HttpParser.responseParser() {
+ return new _HttpParser._(false);
+ }
+
+ _HttpParser._(this._requestParser) {
+ _controller = new StreamController<_HttpIncoming>(
+ sync: true,
+ onListen: () {
+ _paused = false;
+ },
+ onPause: () {
+ _paused = true;
+ _pauseStateChanged();
+ },
+ onResume: () {
+ _paused = false;
+ _pauseStateChanged();
+ },
+ onCancel: () {
+ if (_socketSubscription != null) {
+ _socketSubscription.cancel();
+ }
+ });
+ _reset();
+ }
+
+ StreamSubscription<_HttpIncoming> listen(void onData(_HttpIncoming event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ return _controller.stream.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ void listenToStream(Stream<Uint8List> stream) {
+ // Listen to the stream and handle data accordingly. When a
+ // _HttpIncoming is created, _dataPause, _dataResume, _dataDone is
+ // given to provide a way of controlling the parser.
+ // TODO(ajohnsen): Remove _dataPause, _dataResume and _dataDone and clean up
+ // how the _HttpIncoming signals the parser.
+ _socketSubscription =
+ stream.listen(_onData, onError: _controller.addError, onDone: _onDone);
+ }
+
+ void _parse() {
+ try {
+ _doParse();
+ } catch (e, s) {
+ _state = _State.FAILURE;
+ _reportError(e, s);
+ }
+ }
+
+ // Process end of headers. Returns true if the parser should stop
+ // parsing and return. This will be in case of either an upgrade
+ // request or a request or response with an empty body.
+ bool _headersEnd() {
+ _headers._mutable = false;
+
+ _transferLength = _headers.contentLength;
+ // Ignore the Content-Length header if Transfer-Encoding
+ // is chunked (RFC 2616 section 4.4)
+ if (_chunked) _transferLength = -1;
+
+ // If a request message has neither Content-Length nor
+ // Transfer-Encoding the message must not have a body (RFC
+ // 2616 section 4.3).
+ if (_messageType == _MessageType.REQUEST &&
+ _transferLength < 0 &&
+ _chunked == false) {
+ _transferLength = 0;
+ }
+ if (_connectionUpgrade) {
+ _state = _State.UPGRADED;
+ _transferLength = 0;
+ }
+ _createIncoming(_transferLength);
+ if (_requestParser) {
+ _incoming.method = new String.fromCharCodes(_method);
+ _incoming.uri =
+ Uri.parse(new String.fromCharCodes(_uri_or_reason_phrase));
+ } else {
+ _incoming.statusCode = _statusCode;
+ _incoming.reasonPhrase = new String.fromCharCodes(_uri_or_reason_phrase);
+ }
+ _method.clear();
+ _uri_or_reason_phrase.clear();
+ if (_connectionUpgrade) {
+ _incoming.upgraded = true;
+ _parserCalled = false;
+ var tmp = _incoming;
+ _closeIncoming();
+ _controller.add(tmp);
+ return true;
+ }
+ if (_transferLength == 0 ||
+ (_messageType == _MessageType.RESPONSE && _noMessageBody)) {
+ _reset();
+ var tmp = _incoming;
+ _closeIncoming();
+ _controller.add(tmp);
+ return false;
+ } else if (_chunked) {
+ _state = _State.CHUNK_SIZE;
+ _remainingContent = 0;
+ } else if (_transferLength > 0) {
+ _remainingContent = _transferLength;
+ _state = _State.BODY;
+ } else {
+ // Neither chunked nor content length. End of body
+ // indicated by close.
+ _state = _State.BODY;
+ }
+ _parserCalled = false;
+ _controller.add(_incoming);
+ return true;
+ }
+
+ // From RFC 2616.
+ // generic-message = start-line
+ // *(message-header CRLF)
+ // CRLF
+ // [ message-body ]
+ // start-line = Request-Line | Status-Line
+ // Request-Line = Method SP Request-URI SP HTTP-Version CRLF
+ // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
+ // message-header = field-name ":" [ field-value ]
+ void _doParse() {
+ assert(!_parserCalled);
+ _parserCalled = true;
+ if (_state == _State.CLOSED) {
+ throw new HttpException("Data on closed connection");
+ }
+ if (_state == _State.FAILURE) {
+ throw new HttpException("Data on failed connection");
+ }
+ while (_buffer != null &&
+ _index < _buffer.length &&
+ _state != _State.FAILURE &&
+ _state != _State.UPGRADED) {
+ // Depending on _incoming, we either break on _bodyPaused or _paused.
+ if ((_incoming != null && _bodyPaused) ||
+ (_incoming == null && _paused)) {
+ _parserCalled = false;
+ return;
+ }
+ int byte = _buffer[_index++];
+ switch (_state) {
+ case _State.START:
+ if (byte == _Const.HTTP[0]) {
+ // Start parsing method or HTTP version.
+ _httpVersionIndex = 1;
+ _state = _State.METHOD_OR_RESPONSE_HTTP_VERSION;
+ } else {
+ // Start parsing method.
+ if (!_isTokenChar(byte)) {
+ throw new HttpException("Invalid request method");
+ }
+ _method.add(byte);
+ if (!_requestParser) {
+ throw new HttpException("Invalid response line");
+ }
+ _state = _State.REQUEST_LINE_METHOD;
+ }
+ break;
+
+ case _State.METHOD_OR_RESPONSE_HTTP_VERSION:
+ if (_httpVersionIndex < _Const.HTTP.length &&
+ byte == _Const.HTTP[_httpVersionIndex]) {
+ // Continue parsing HTTP version.
+ _httpVersionIndex++;
+ } else if (_httpVersionIndex == _Const.HTTP.length &&
+ byte == _CharCode.SLASH) {
+ // HTTP/ parsed. As method is a token this cannot be a
+ // method anymore.
+ _httpVersionIndex++;
+ if (_requestParser) {
+ throw new HttpException("Invalid request line");
+ }
+ _state = _State.RESPONSE_HTTP_VERSION;
+ } else {
+ // Did not parse HTTP version. Expect method instead.
+ for (int i = 0; i < _httpVersionIndex; i++) {
+ _method.add(_Const.HTTP[i]);
+ }
+ if (byte == _CharCode.SP) {
+ _state = _State.REQUEST_LINE_URI;
+ } else {
+ _method.add(byte);
+ _httpVersion = _HttpVersion.UNDETERMINED;
+ if (!_requestParser) {
+ throw new HttpException("Invalid response line");
+ }
+ _state = _State.REQUEST_LINE_METHOD;
+ }
+ }
+ break;
+
+ case _State.RESPONSE_HTTP_VERSION:
+ if (_httpVersionIndex < _Const.HTTP1DOT.length) {
+ // Continue parsing HTTP version.
+ _expect(byte, _Const.HTTP1DOT[_httpVersionIndex]);
+ _httpVersionIndex++;
+ } else if (_httpVersionIndex == _Const.HTTP1DOT.length &&
+ byte == _CharCode.ONE) {
+ // HTTP/1.1 parsed.
+ _httpVersion = _HttpVersion.HTTP11;
+ _persistentConnection = true;
+ _httpVersionIndex++;
+ } else if (_httpVersionIndex == _Const.HTTP1DOT.length &&
+ byte == _CharCode.ZERO) {
+ // HTTP/1.0 parsed.
+ _httpVersion = _HttpVersion.HTTP10;
+ _persistentConnection = false;
+ _httpVersionIndex++;
+ } else if (_httpVersionIndex == _Const.HTTP1DOT.length + 1) {
+ _expect(byte, _CharCode.SP);
+ // HTTP version parsed.
+ _state = _State.RESPONSE_LINE_STATUS_CODE;
+ } else {
+ throw new HttpException("Invalid response line");
+ }
+ break;
+
+ case _State.REQUEST_LINE_METHOD:
+ if (byte == _CharCode.SP) {
+ _state = _State.REQUEST_LINE_URI;
+ } else {
+ if (_Const.SEPARATOR_MAP[byte] ||
+ byte == _CharCode.CR ||
+ byte == _CharCode.LF) {
+ throw new HttpException("Invalid request method");
+ }
+ _method.add(byte);
+ }
+ break;
+
+ case _State.REQUEST_LINE_URI:
+ if (byte == _CharCode.SP) {
+ if (_uri_or_reason_phrase.length == 0) {
+ throw new HttpException("Invalid request URI");
+ }
+ _state = _State.REQUEST_LINE_HTTP_VERSION;
+ _httpVersionIndex = 0;
+ } else {
+ if (byte == _CharCode.CR || byte == _CharCode.LF) {
+ throw new HttpException("Invalid request URI");
+ }
+ _uri_or_reason_phrase.add(byte);
+ }
+ break;
+
+ case _State.REQUEST_LINE_HTTP_VERSION:
+ if (_httpVersionIndex < _Const.HTTP1DOT.length) {
+ _expect(byte, _Const.HTTP11[_httpVersionIndex]);
+ _httpVersionIndex++;
+ } else if (_httpVersionIndex == _Const.HTTP1DOT.length) {
+ if (byte == _CharCode.ONE) {
+ // HTTP/1.1 parsed.
+ _httpVersion = _HttpVersion.HTTP11;
+ _persistentConnection = true;
+ _httpVersionIndex++;
+ } else if (byte == _CharCode.ZERO) {
+ // HTTP/1.0 parsed.
+ _httpVersion = _HttpVersion.HTTP10;
+ _persistentConnection = false;
+ _httpVersionIndex++;
+ } else {
+ throw new HttpException("Invalid response line");
+ }
+ } else {
+ if (byte == _CharCode.CR) {
+ _state = _State.REQUEST_LINE_ENDING;
+ } else {
+ _expect(byte, _CharCode.LF);
+ _messageType = _MessageType.REQUEST;
+ _state = _State.HEADER_START;
+ }
+ }
+ break;
+
+ case _State.REQUEST_LINE_ENDING:
+ _expect(byte, _CharCode.LF);
+ _messageType = _MessageType.REQUEST;
+ _state = _State.HEADER_START;
+ break;
+
+ case _State.RESPONSE_LINE_STATUS_CODE:
+ if (byte == _CharCode.SP) {
+ _state = _State.RESPONSE_LINE_REASON_PHRASE;
+ } else if (byte == _CharCode.CR) {
+ // Some HTTP servers does not follow the spec. and send
+ // \r\n right after the status code.
+ _state = _State.RESPONSE_LINE_ENDING;
+ } else {
+ _statusCodeLength++;
+ if ((byte < 0x30 && 0x39 < byte) || _statusCodeLength > 3) {
+ throw new HttpException("Invalid response status code");
+ } else {
+ _statusCode = _statusCode * 10 + byte - 0x30;
+ }
+ }
+ break;
+
+ case _State.RESPONSE_LINE_REASON_PHRASE:
+ if (byte == _CharCode.CR) {
+ _state = _State.RESPONSE_LINE_ENDING;
+ } else {
+ if (byte == _CharCode.CR || byte == _CharCode.LF) {
+ throw new HttpException("Invalid response reason phrase");
+ }
+ _uri_or_reason_phrase.add(byte);
+ }
+ break;
+
+ case _State.RESPONSE_LINE_ENDING:
+ _expect(byte, _CharCode.LF);
+ _messageType == _MessageType.RESPONSE;
+ if (_statusCode < 100 || _statusCode > 599) {
+ throw new HttpException("Invalid response status code");
+ } else {
+ // Check whether this response will never have a body.
+ if (_statusCode <= 199 ||
+ _statusCode == 204 ||
+ _statusCode == 304) {
+ _noMessageBody = true;
+ }
+ }
+ _state = _State.HEADER_START;
+ break;
+
+ case _State.HEADER_START:
+ _headers = new _HttpHeaders(version);
+ if (byte == _CharCode.CR) {
+ _state = _State.HEADER_ENDING;
+ } else if (byte == _CharCode.LF) {
+ _state = _State.HEADER_ENDING;
+ _index--; // Make the new state see the LF again.
+ } else {
+ // Start of new header field.
+ _headerField.add(_toLowerCaseByte(byte));
+ _state = _State.HEADER_FIELD;
+ }
+ break;
+
+ case _State.HEADER_FIELD:
+ if (byte == _CharCode.COLON) {
+ _state = _State.HEADER_VALUE_START;
+ } else {
+ if (!_isTokenChar(byte)) {
+ throw new HttpException("Invalid header field name");
+ }
+ _headerField.add(_toLowerCaseByte(byte));
+ }
+ break;
+
+ case _State.HEADER_VALUE_START:
+ if (byte == _CharCode.CR) {
+ _state = _State.HEADER_VALUE_FOLDING_OR_ENDING;
+ } else if (byte == _CharCode.LF) {
+ _state = _State.HEADER_VALUE_FOLD_OR_END;
+ } else if (byte != _CharCode.SP && byte != _CharCode.HT) {
+ // Start of new header value.
+ _headerValue.add(byte);
+ _state = _State.HEADER_VALUE;
+ }
+ break;
+
+ case _State.HEADER_VALUE:
+ if (byte == _CharCode.CR) {
+ _state = _State.HEADER_VALUE_FOLDING_OR_ENDING;
+ } else if (byte == _CharCode.LF) {
+ _state = _State.HEADER_VALUE_FOLD_OR_END;
+ } else {
+ _headerValue.add(byte);
+ }
+ break;
+
+ case _State.HEADER_VALUE_FOLDING_OR_ENDING:
+ _expect(byte, _CharCode.LF);
+ _state = _State.HEADER_VALUE_FOLD_OR_END;
+ break;
+
+ case _State.HEADER_VALUE_FOLD_OR_END:
+ if (byte == _CharCode.SP || byte == _CharCode.HT) {
+ _state = _State.HEADER_VALUE_START;
+ } else {
+ String headerField = new String.fromCharCodes(_headerField);
+ String headerValue = new String.fromCharCodes(_headerValue);
+ if (headerField == "transfer-encoding" &&
+ _caseInsensitiveCompare("chunked".codeUnits, _headerValue)) {
+ _chunked = true;
+ }
+ if (headerField == "connection") {
+ List<String> tokens = _tokenizeFieldValue(headerValue);
+ final bool isResponse = _messageType == _MessageType.RESPONSE;
+ final bool isUpgradeCode =
+ (_statusCode == HttpStatus.upgradeRequired) ||
+ (_statusCode == HttpStatus.switchingProtocols);
+ for (int i = 0; i < tokens.length; i++) {
+ final bool isUpgrade = _caseInsensitiveCompare(
+ "upgrade".codeUnits, tokens[i].codeUnits);
+ if ((isUpgrade && !isResponse) ||
+ (isUpgrade && isResponse && isUpgradeCode)) {
+ _connectionUpgrade = true;
+ }
+ _headers._add(headerField, tokens[i]);
+ }
+ } else {
+ _headers._add(headerField, headerValue);
+ }
+ _headerField.clear();
+ _headerValue.clear();
+
+ if (byte == _CharCode.CR) {
+ _state = _State.HEADER_ENDING;
+ } else if (byte == _CharCode.LF) {
+ _state = _State.HEADER_ENDING;
+ _index--; // Make the new state see the LF again.
+ } else {
+ // Start of new header field.
+ _headerField.add(_toLowerCaseByte(byte));
+ _state = _State.HEADER_FIELD;
+ }
+ }
+ break;
+
+ case _State.HEADER_ENDING:
+ _expect(byte, _CharCode.LF);
+ if (_headersEnd()) {
+ return;
+ } else {
+ break;
+ }
+ return;
+
+ case _State.CHUNK_SIZE_STARTING_CR:
+ _expect(byte, _CharCode.CR);
+ _state = _State.CHUNK_SIZE_STARTING_LF;
+ break;
+
+ case _State.CHUNK_SIZE_STARTING_LF:
+ _expect(byte, _CharCode.LF);
+ _state = _State.CHUNK_SIZE;
+ break;
+
+ case _State.CHUNK_SIZE:
+ if (byte == _CharCode.CR) {
+ _state = _State.CHUNK_SIZE_ENDING;
+ } else if (byte == _CharCode.SEMI_COLON) {
+ _state = _State.CHUNK_SIZE_EXTENSION;
+ } else {
+ int value = _expectHexDigit(byte);
+ _remainingContent = _remainingContent * 16 + value;
+ }
+ break;
+
+ case _State.CHUNK_SIZE_EXTENSION:
+ if (byte == _CharCode.CR) {
+ _state = _State.CHUNK_SIZE_ENDING;
+ }
+ break;
+
+ case _State.CHUNK_SIZE_ENDING:
+ _expect(byte, _CharCode.LF);
+ if (_remainingContent > 0) {
+ _state = _State.BODY;
+ } else {
+ _state = _State.CHUNKED_BODY_DONE_CR;
+ }
+ break;
+
+ case _State.CHUNKED_BODY_DONE_CR:
+ _expect(byte, _CharCode.CR);
+ _state = _State.CHUNKED_BODY_DONE_LF;
+ break;
+
+ case _State.CHUNKED_BODY_DONE_LF:
+ _expect(byte, _CharCode.LF);
+ _reset();
+ _closeIncoming();
+ break;
+
+ case _State.BODY:
+ // The body is not handled one byte at a time but in blocks.
+ _index--;
+ int dataAvailable = _buffer.length - _index;
+ if (_remainingContent >= 0 && dataAvailable > _remainingContent) {
+ dataAvailable = _remainingContent;
+ }
+ // Always present the data as a view. This way we can handle all
+ // cases like this, and the user will not experience different data
+ // typed (which could lead to polymorphic user code).
+ Uint8List data = new Uint8List.view(
+ _buffer.buffer, _buffer.offsetInBytes + _index, dataAvailable);
+ _bodyController.add(data);
+ if (_remainingContent != -1) {
+ _remainingContent -= data.length;
+ }
+ _index += data.length;
+ if (_remainingContent == 0) {
+ if (!_chunked) {
+ _reset();
+ _closeIncoming();
+ } else {
+ _state = _State.CHUNK_SIZE_STARTING_CR;
+ }
+ }
+ break;
+
+ case _State.FAILURE:
+ // Should be unreachable.
+ assert(false);
+ break;
+
+ default:
+ // Should be unreachable.
+ assert(false);
+ break;
+ }
+ }
+
+ _parserCalled = false;
+ if (_buffer != null && _index == _buffer.length) {
+ // If all data is parsed release the buffer and resume receiving
+ // data.
+ _releaseBuffer();
+ if (_state != _State.UPGRADED && _state != _State.FAILURE) {
+ _socketSubscription.resume();
+ }
+ }
+ }
+
+ void _onData(Uint8List buffer) {
+ _socketSubscription.pause();
+ assert(_buffer == null);
+ _buffer = buffer;
+ _index = 0;
+ _parse();
+ }
+
+ void _onDone() {
+ // onDone cancels the subscription.
+ _socketSubscription = null;
+ if (_state == _State.CLOSED || _state == _State.FAILURE) return;
+
+ if (_incoming != null) {
+ if (_state != _State.UPGRADED &&
+ !(_state == _State.START && !_requestParser) &&
+ !(_state == _State.BODY && !_chunked && _transferLength == -1)) {
+ _bodyController.addError(
+ new HttpException("Connection closed while receiving data"));
+ }
+ _closeIncoming(true);
+ _controller.close();
+ return;
+ }
+ // If the connection is idle the HTTP stream is closed.
+ if (_state == _State.START) {
+ if (!_requestParser) {
+ _reportError(new HttpException(
+ "Connection closed before full header was received"));
+ }
+ _controller.close();
+ return;
+ }
+
+ if (_state == _State.UPGRADED) {
+ _controller.close();
+ return;
+ }
+
+ if (_state < _State.FIRST_BODY_STATE) {
+ _state = _State.FAILURE;
+ // Report the error through the error callback if any. Otherwise
+ // throw the error.
+ _reportError(new HttpException(
+ "Connection closed before full header was received"));
+ _controller.close();
+ return;
+ }
+
+ if (!_chunked && _transferLength == -1) {
+ _state = _State.CLOSED;
+ } else {
+ _state = _State.FAILURE;
+ // Report the error through the error callback if any. Otherwise
+ // throw the error.
+ _reportError(
+ new HttpException("Connection closed before full body was received"));
+ }
+ _controller.close();
+ }
+
+ String get version {
+ switch (_httpVersion) {
+ case _HttpVersion.HTTP10:
+ return "1.0";
+ case _HttpVersion.HTTP11:
+ return "1.1";
+ }
+ return null;
+ }
+
+ int get messageType => _messageType;
+ int get transferLength => _transferLength;
+ bool get upgrade => _connectionUpgrade && _state == _State.UPGRADED;
+ bool get persistentConnection => _persistentConnection;
+
+ void set isHead(bool value) {
+ if (value) _noMessageBody = true;
+ }
+
+ _HttpDetachedIncoming detachIncoming() {
+ // Simulate detached by marking as upgraded.
+ _state = _State.UPGRADED;
+ return new _HttpDetachedIncoming(_socketSubscription, readUnparsedData());
+ }
+
+ Uint8List readUnparsedData() {
+ if (_buffer == null) return null;
+ if (_index == _buffer.length) return null;
+ var result = _buffer.sublist(_index);
+ _releaseBuffer();
+ return result;
+ }
+
+ void _reset() {
+ if (_state == _State.UPGRADED) return;
+ _state = _State.START;
+ _messageType = _MessageType.UNDETERMINED;
+ _headerField.clear();
+ _headerValue.clear();
+ _method.clear();
+ _uri_or_reason_phrase.clear();
+
+ _statusCode = 0;
+ _statusCodeLength = 0;
+
+ _httpVersion = _HttpVersion.UNDETERMINED;
+ _transferLength = -1;
+ _persistentConnection = false;
+ _connectionUpgrade = false;
+ _chunked = false;
+
+ _noMessageBody = false;
+ _remainingContent = -1;
+
+ _headers = null;
+ }
+
+ void _releaseBuffer() {
+ _buffer = null;
+ _index = null;
+ }
+
+ static bool _isTokenChar(int byte) {
+ return byte > 31 && byte < 128 && !_Const.SEPARATOR_MAP[byte];
+ }
+
+ static bool _isValueChar(int byte) {
+ return (byte > 31 && byte < 128) ||
+ (byte == _CharCode.SP) ||
+ (byte == _CharCode.HT);
+ }
+
+ static List<String> _tokenizeFieldValue(String headerValue) {
+ List<String> tokens = new List<String>();
+ int start = 0;
+ int index = 0;
+ while (index < headerValue.length) {
+ if (headerValue[index] == ",") {
+ tokens.add(headerValue.substring(start, index));
+ start = index + 1;
+ } else if (headerValue[index] == " " || headerValue[index] == "\t") {
+ start++;
+ }
+ index++;
+ }
+ tokens.add(headerValue.substring(start, index));
+ return tokens;
+ }
+
+ static int _toLowerCaseByte(int x) {
+ // Optimized version:
+ // - 0x41 is 'A'
+ // - 0x7f is ASCII mask
+ // - 26 is the number of alpha characters.
+ // - 0x20 is the delta between lower and upper chars.
+ return (((x - 0x41) & 0x7f) < 26) ? (x | 0x20) : x;
+ }
+
+ // expected should already be lowercase.
+ bool _caseInsensitiveCompare(List<int> expected, List<int> value) {
+ if (expected.length != value.length) return false;
+ for (int i = 0; i < expected.length; i++) {
+ if (expected[i] != _toLowerCaseByte(value[i])) return false;
+ }
+ return true;
+ }
+
+ int _expect(int val1, int val2) {
+ if (val1 != val2) {
+ throw new HttpException("Failed to parse HTTP");
+ }
+ }
+
+ int _expectHexDigit(int byte) {
+ if (0x30 <= byte && byte <= 0x39) {
+ return byte - 0x30; // 0 - 9
+ } else if (0x41 <= byte && byte <= 0x46) {
+ return byte - 0x41 + 10; // A - F
+ } else if (0x61 <= byte && byte <= 0x66) {
+ return byte - 0x61 + 10; // a - f
+ } else {
+ throw new HttpException("Failed to parse HTTP");
+ }
+ }
+
+ void _createIncoming(int transferLength) {
+ assert(_incoming == null);
+ assert(_bodyController == null);
+ assert(!_bodyPaused);
+ var incoming;
+ _bodyController = new StreamController<Uint8List>(
+ sync: true,
+ onListen: () {
+ if (incoming != _incoming) return;
+ assert(_bodyPaused);
+ _bodyPaused = false;
+ _pauseStateChanged();
+ },
+ onPause: () {
+ if (incoming != _incoming) return;
+ assert(!_bodyPaused);
+ _bodyPaused = true;
+ _pauseStateChanged();
+ },
+ onResume: () {
+ if (incoming != _incoming) return;
+ assert(_bodyPaused);
+ _bodyPaused = false;
+ _pauseStateChanged();
+ },
+ onCancel: () {
+ if (incoming != _incoming) return;
+ if (_socketSubscription != null) {
+ _socketSubscription.cancel();
+ }
+ _closeIncoming(true);
+ _controller.close();
+ });
+ incoming = _incoming =
+ new _HttpIncoming(_headers, transferLength, _bodyController.stream);
+ _bodyPaused = true;
+ _pauseStateChanged();
+ }
+
+ void _closeIncoming([bool closing = false]) {
+ // Ignore multiple close (can happen in re-entrance).
+ if (_incoming == null) return;
+ var tmp = _incoming;
+ tmp.close(closing);
+ _incoming = null;
+ if (_bodyController != null) {
+ _bodyController.close();
+ _bodyController = null;
+ }
+ _bodyPaused = false;
+ _pauseStateChanged();
+ }
+
+ void _pauseStateChanged() {
+ if (_incoming != null) {
+ if (!_bodyPaused && !_parserCalled) {
+ _parse();
+ }
+ } else {
+ if (!_paused && !_parserCalled) {
+ _parse();
+ }
+ }
+ }
+
+ void _reportError(error, [stackTrace]) {
+ if (_socketSubscription != null) _socketSubscription.cancel();
+ _state = _State.FAILURE;
+ _controller.addError(error, stackTrace);
+ _controller.close();
+ }
+}
diff --git a/sdk_nnbd/lib/_http/http_session.dart b/sdk_nnbd/lib/_http/http_session.dart
new file mode 100644
index 0000000..3907609
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http_session.dart
@@ -0,0 +1,205 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+const String _DART_SESSION_ID = "DARTSESSID";
+
+// A _HttpSession is a node in a double-linked list, with _next and _prev being
+// the previous and next pointers.
+class _HttpSession implements HttpSession {
+ // Destroyed marked. Used by the http connection to see if a session is valid.
+ bool _destroyed = false;
+ bool _isNew = true;
+ DateTime _lastSeen;
+ Function _timeoutCallback;
+ _HttpSessionManager _sessionManager;
+ // Pointers in timeout queue.
+ _HttpSession _prev;
+ _HttpSession _next;
+ final String id;
+
+ final Map _data = new HashMap();
+
+ _HttpSession(this._sessionManager, this.id) : _lastSeen = new DateTime.now();
+
+ void destroy() {
+ _destroyed = true;
+ _sessionManager._removeFromTimeoutQueue(this);
+ _sessionManager._sessions.remove(id);
+ }
+
+ // Mark the session as seen. This will reset the timeout and move the node to
+ // the end of the timeout queue.
+ void _markSeen() {
+ _lastSeen = new DateTime.now();
+ _sessionManager._bumpToEnd(this);
+ }
+
+ DateTime get lastSeen => _lastSeen;
+
+ bool get isNew => _isNew;
+
+ void set onTimeout(void callback()) {
+ _timeoutCallback = callback;
+ }
+
+ // Map implementation:
+ bool containsValue(value) => _data.containsValue(value);
+ bool containsKey(key) => _data.containsKey(key);
+ operator [](key) => _data[key];
+ void operator []=(key, value) {
+ _data[key] = value;
+ }
+
+ putIfAbsent(key, ifAbsent) => _data.putIfAbsent(key, ifAbsent);
+ addAll(Map other) => _data.addAll(other);
+ remove(key) => _data.remove(key);
+ void clear() {
+ _data.clear();
+ }
+
+ void forEach(void f(key, value)) {
+ _data.forEach(f);
+ }
+
+ Iterable<MapEntry> get entries => _data.entries;
+
+ void addEntries(Iterable<MapEntry> entries) {
+ _data.addEntries(entries);
+ }
+
+ Map<K, V> map<K, V>(MapEntry<K, V> transform(key, value)) =>
+ _data.map(transform);
+
+ void removeWhere(bool test(key, value)) {
+ _data.removeWhere(test);
+ }
+
+ Map<K, V> cast<K, V>() => _data.cast<K, V>();
+ update(key, update(value), {ifAbsent()}) =>
+ _data.update(key, update, ifAbsent: ifAbsent);
+
+ void updateAll(update(key, value)) {
+ _data.updateAll(update);
+ }
+
+ Iterable get keys => _data.keys;
+ Iterable get values => _data.values;
+ int get length => _data.length;
+ bool get isEmpty => _data.isEmpty;
+ bool get isNotEmpty => _data.isNotEmpty;
+
+ String toString() => 'HttpSession id:$id $_data';
+}
+
+// Private class used to manage all the active sessions. The sessions are stored
+// in two ways:
+//
+// * In a map, mapping from ID to HttpSession.
+// * In a linked list, used as a timeout queue.
+class _HttpSessionManager {
+ Map<String, _HttpSession> _sessions;
+ int _sessionTimeout = 20 * 60; // 20 mins.
+ _HttpSession _head;
+ _HttpSession _tail;
+ Timer _timer;
+
+ _HttpSessionManager() : _sessions = {};
+
+ String createSessionId() {
+ const int _KEY_LENGTH = 16; // 128 bits.
+ var data = _CryptoUtils.getRandomBytes(_KEY_LENGTH);
+ return _CryptoUtils.bytesToHex(data);
+ }
+
+ _HttpSession getSession(String id) => _sessions[id];
+
+ _HttpSession createSession() {
+ var id = createSessionId();
+ // TODO(ajohnsen): Consider adding a limit and throwing an exception.
+ // Should be very unlikely however.
+ while (_sessions.containsKey(id)) {
+ id = createSessionId();
+ }
+ var session = _sessions[id] = new _HttpSession(this, id);
+ _addToTimeoutQueue(session);
+ return session;
+ }
+
+ void set sessionTimeout(int timeout) {
+ _sessionTimeout = timeout;
+ _stopTimer();
+ _startTimer();
+ }
+
+ void close() {
+ _stopTimer();
+ }
+
+ void _bumpToEnd(_HttpSession session) {
+ _removeFromTimeoutQueue(session);
+ _addToTimeoutQueue(session);
+ }
+
+ void _addToTimeoutQueue(_HttpSession session) {
+ if (_head == null) {
+ assert(_tail == null);
+ _tail = _head = session;
+ _startTimer();
+ } else {
+ assert(_timer != null);
+ assert(_tail != null);
+ // Add to end.
+ _tail._next = session;
+ session._prev = _tail;
+ _tail = session;
+ }
+ }
+
+ void _removeFromTimeoutQueue(_HttpSession session) {
+ if (session._next != null) {
+ session._next._prev = session._prev;
+ }
+ if (session._prev != null) {
+ session._prev._next = session._next;
+ }
+ if (_head == session) {
+ // We removed the head element, start new timer.
+ _head = session._next;
+ _stopTimer();
+ _startTimer();
+ }
+ if (_tail == session) {
+ _tail = session._prev;
+ }
+ session._next = session._prev = null;
+ }
+
+ void _timerTimeout() {
+ _stopTimer(); // Clear timer.
+ assert(_head != null);
+ var session = _head;
+ session.destroy(); // Will remove the session from timeout queue and map.
+ if (session._timeoutCallback != null) {
+ session._timeoutCallback();
+ }
+ }
+
+ void _startTimer() {
+ assert(_timer == null);
+ if (_head != null) {
+ int seconds = new DateTime.now().difference(_head.lastSeen).inSeconds;
+ _timer = new Timer(
+ new Duration(seconds: _sessionTimeout - seconds), _timerTimeout);
+ }
+ }
+
+ void _stopTimer() {
+ if (_timer != null) {
+ _timer.cancel();
+ _timer = null;
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/_http/http_sources.gni b/sdk_nnbd/lib/_http/http_sources.gni
new file mode 100644
index 0000000..1ce36b4
--- /dev/null
+++ b/sdk_nnbd/lib/_http/http_sources.gni
@@ -0,0 +1,18 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+http_sdk_sources = [
+ "http.dart",
+
+ # The above file needs to be first if additional parts are added to the lib.
+ "crypto.dart",
+ "http_date.dart",
+ "http_headers.dart",
+ "http_impl.dart",
+ "http_parser.dart",
+ "http_session.dart",
+ "overrides.dart",
+ "websocket.dart",
+ "websocket_impl.dart",
+]
diff --git a/sdk_nnbd/lib/_http/overrides.dart b/sdk_nnbd/lib/_http/overrides.dart
new file mode 100644
index 0000000..7f9e689
--- /dev/null
+++ b/sdk_nnbd/lib/_http/overrides.dart
@@ -0,0 +1,118 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+final _httpOverridesToken = new Object();
+
+const _asyncRunZoned = runZoned;
+
+/// This class facilitates overriding [HttpClient] with a mock implementation.
+/// It should be extended by another class in client code with overrides
+/// that construct a mock implementation. The implementation in this base class
+/// defaults to the actual [HttpClient] implementation. For example:
+///
+/// ```
+/// class MyHttpClient implements HttpClient {
+/// ...
+/// // An implementation of the HttpClient interface
+/// ...
+/// }
+///
+/// main() {
+/// HttpOverrides.runZoned(() {
+/// ...
+/// // Operations will use MyHttpClient instead of the real HttpClient
+/// // implementation whenever HttpClient is used.
+/// ...
+/// }, createHttpClient: (SecurityContext c) => new MyHttpClient(c));
+/// }
+/// ```
+abstract class HttpOverrides {
+ static HttpOverrides _global;
+
+ static HttpOverrides get current {
+ return Zone.current[_httpOverridesToken] ?? _global;
+ }
+
+ /// The [HttpOverrides] to use in the root [Zone].
+ ///
+ /// These are the [HttpOverrides] that will be used in the root Zone, and in
+ /// Zone's that do not set [HttpOverrides] and whose ancestors up to the root
+ /// Zone do not set [HttpOverrides].
+ static set global(HttpOverrides overrides) {
+ _global = overrides;
+ }
+
+ /// Runs [body] in a fresh [Zone] using the provided overrides.
+ static R runZoned<R>(R body(),
+ {HttpClient Function(SecurityContext) createHttpClient,
+ String Function(Uri uri, Map<String, String> environment)
+ findProxyFromEnvironment,
+ ZoneSpecification zoneSpecification,
+ Function onError}) {
+ HttpOverrides overrides =
+ new _HttpOverridesScope(createHttpClient, findProxyFromEnvironment);
+ return _asyncRunZoned<R>(body,
+ zoneValues: {_httpOverridesToken: overrides},
+ zoneSpecification: zoneSpecification,
+ onError: onError);
+ }
+
+ /// Runs [body] in a fresh [Zone] using the overrides found in [overrides].
+ ///
+ /// Note that [overrides] should be an instance of a class that extends
+ /// [HttpOverrides].
+ static R runWithHttpOverrides<R>(R body(), HttpOverrides overrides,
+ {ZoneSpecification zoneSpecification, Function onError}) {
+ return _asyncRunZoned<R>(body,
+ zoneValues: {_httpOverridesToken: overrides},
+ zoneSpecification: zoneSpecification,
+ onError: onError);
+ }
+
+ /// Returns a new [HttpClient] using the given [context].
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `new HttpClient`.
+ HttpClient createHttpClient(SecurityContext context) {
+ return new _HttpClient(context);
+ }
+
+ /// Resolves the proxy server to be used for HTTP connections.
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `HttpClient.findProxyFromEnvironment`.
+ String findProxyFromEnvironment(Uri url, Map<String, String> environment) {
+ return _HttpClient._findProxyFromEnvironment(url, environment);
+ }
+}
+
+class _HttpOverridesScope extends HttpOverrides {
+ final HttpOverrides _previous = HttpOverrides.current;
+
+ final HttpClient Function(SecurityContext) _createHttpClient;
+ final String Function(Uri uri, Map<String, String> environment)
+ _findProxyFromEnvironment;
+
+ _HttpOverridesScope(this._createHttpClient, this._findProxyFromEnvironment);
+
+ @override
+ HttpClient createHttpClient(SecurityContext context) {
+ if (_createHttpClient != null) return _createHttpClient(context);
+ if (_previous != null) return _previous.createHttpClient(context);
+ return super.createHttpClient(context);
+ }
+
+ @override
+ String findProxyFromEnvironment(Uri url, Map<String, String> environment) {
+ if (_findProxyFromEnvironment != null) {
+ return _findProxyFromEnvironment(url, environment);
+ }
+ if (_previous != null) {
+ return _previous.findProxyFromEnvironment(url, environment);
+ }
+ return super.findProxyFromEnvironment(url, environment);
+ }
+}
diff --git a/sdk_nnbd/lib/_http/websocket.dart b/sdk_nnbd/lib/_http/websocket.dart
new file mode 100644
index 0000000..5a949af
--- /dev/null
+++ b/sdk_nnbd/lib/_http/websocket.dart
@@ -0,0 +1,497 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+/**
+ * WebSocket status codes used when closing a WebSocket connection.
+ */
+abstract class WebSocketStatus {
+ static const int normalClosure = 1000;
+ static const int goingAway = 1001;
+ static const int protocolError = 1002;
+ static const int unsupportedData = 1003;
+ static const int reserved1004 = 1004;
+ static const int noStatusReceived = 1005;
+ static const int abnormalClosure = 1006;
+ static const int invalidFramePayloadData = 1007;
+ static const int policyViolation = 1008;
+ static const int messageTooBig = 1009;
+ static const int missingMandatoryExtension = 1010;
+ static const int internalServerError = 1011;
+ static const int reserved1015 = 1015;
+
+ @Deprecated("Use normalClosure instead")
+ static const int NORMAL_CLOSURE = normalClosure;
+ @Deprecated("Use goingAway instead")
+ static const int GOING_AWAY = goingAway;
+ @Deprecated("Use protocolError instead")
+ static const int PROTOCOL_ERROR = protocolError;
+ @Deprecated("Use unsupportedData instead")
+ static const int UNSUPPORTED_DATA = unsupportedData;
+ @Deprecated("Use reserved1004 instead")
+ static const int RESERVED_1004 = reserved1004;
+ @Deprecated("Use noStatusReceived instead")
+ static const int NO_STATUS_RECEIVED = noStatusReceived;
+ @Deprecated("Use abnormalClosure instead")
+ static const int ABNORMAL_CLOSURE = abnormalClosure;
+ @Deprecated("Use invalidFramePayloadData instead")
+ static const int INVALID_FRAME_PAYLOAD_DATA = invalidFramePayloadData;
+ @Deprecated("Use policyViolation instead")
+ static const int POLICY_VIOLATION = policyViolation;
+ @Deprecated("Use messageTooBig instead")
+ static const int MESSAGE_TOO_BIG = messageTooBig;
+ @Deprecated("Use missingMandatoryExtension instead")
+ static const int MISSING_MANDATORY_EXTENSION = missingMandatoryExtension;
+ @Deprecated("Use internalServerError instead")
+ static const int INTERNAL_SERVER_ERROR = internalServerError;
+ @Deprecated("Use reserved1015 instead")
+ static const int RESERVED_1015 = reserved1015;
+}
+
+/// Options controlling compression in a [WebSocket].
+///
+/// A [CompressionOptions] instance can be passed to [WebSocket.connect], or
+/// used in other similar places where [WebSocket] compression is configured.
+///
+/// In most cases the default [compressionDefault] is sufficient, but in some
+/// situations, it might be desirable to use different compression parameters,
+/// for example to preserve memory on small devices.
+class CompressionOptions {
+ /// Default [WebSocket] compression configuration.
+ ///
+ /// Enables compression with default window sizes and no reuse. This is the
+ /// default options used by [WebSocket.connect] if no [CompressionOptions] is
+ /// supplied.
+ ///
+ /// * `clientNoContextTakeover`: false
+ /// * `serverNoContextTakeover`: false
+ /// * `clientMaxWindowBits`: null (default maximal window size of 15 bits)
+ /// * `serverMaxWindowBits`: null (default maximal window size of 15 bits)
+ static const CompressionOptions compressionDefault =
+ const CompressionOptions();
+ @Deprecated("Use compressionDefault instead")
+ static const CompressionOptions DEFAULT = compressionDefault;
+
+ /// No-compression configuration.
+ ///
+ /// Disables compression when used as compression configuration for a
+ /// [WebSocket].
+ static const CompressionOptions compressionOff =
+ const CompressionOptions(enabled: false);
+ @Deprecated("Use compressionOff instead")
+ static const CompressionOptions OFF = compressionOff;
+
+ /// Whether the client will reuse its compression instances.
+ final bool clientNoContextTakeover;
+
+ /// Whether the server will reuse its compression instances.
+ final bool serverNoContextTakeover;
+
+ /// The maximal window size bit count requested by the client.
+ ///
+ /// The windows size for the compression is always a power of two, so the
+ /// number of bits precisely determines the window size.
+ ///
+ /// If set to `null`, the client has no preference, and the compression can
+ /// use up to its default maximum window size of 15 bits depending on the
+ /// server's preference.
+ final int clientMaxWindowBits;
+
+ /// The maximal window size bit count requested by the server.
+ ///
+ /// The windows size for the compression is always a power of two, so the
+ /// number of bits precisely determines the window size.
+ ///
+ /// If set to `null`, the server has no preference, and the compression can
+ /// use up to its default maximum window size of 15 bits depending on the
+ /// client's preference.
+ final int serverMaxWindowBits;
+
+ /// Whether WebSocket compression is enabled.
+ ///
+ /// If not enabled, the remaining fields have no effect, and the
+ /// [compressionOff] instance can, and should, be reused instead of creating a
+ /// new instance with compression disabled.
+ final bool enabled;
+
+ const CompressionOptions(
+ {this.clientNoContextTakeover = false,
+ this.serverNoContextTakeover = false,
+ this.clientMaxWindowBits,
+ this.serverMaxWindowBits,
+ this.enabled = true});
+
+ /// Parses list of requested server headers to return server compression
+ /// response headers.
+ ///
+ /// Uses [serverMaxWindowBits] value if set, otherwise will attempt to use
+ /// value from headers. Defaults to [WebSocket.DEFAULT_WINDOW_BITS]. Returns a
+ /// [_CompressionMaxWindowBits] object which contains the response headers and
+ /// negotiated max window bits.
+ _CompressionMaxWindowBits _createServerResponseHeader(HeaderValue requested) {
+ var info = new _CompressionMaxWindowBits();
+
+ int mwb;
+ String part;
+ if (requested?.parameters != null) {
+ part = requested.parameters[_serverMaxWindowBits];
+ }
+ if (part != null) {
+ if (part.length >= 2 && part.startsWith('0')) {
+ throw new ArgumentError("Illegal 0 padding on value.");
+ } else {
+ mwb = serverMaxWindowBits == null
+ ? int.parse(part,
+ onError: (source) => _WebSocketImpl.DEFAULT_WINDOW_BITS)
+ : serverMaxWindowBits;
+ info.headerValue = "; server_max_window_bits=${mwb}";
+ info.maxWindowBits = mwb;
+ }
+ } else {
+ info.headerValue = "";
+ info.maxWindowBits = _WebSocketImpl.DEFAULT_WINDOW_BITS;
+ }
+ return info;
+ }
+
+ /// Returns default values for client compression request headers.
+ String _createClientRequestHeader(HeaderValue requested, int size) {
+ var info = "";
+
+ // If responding to a valid request, specify size
+ if (requested != null) {
+ info = "; client_max_window_bits=$size";
+ } else {
+ // Client request. Specify default
+ if (clientMaxWindowBits == null) {
+ info = "; client_max_window_bits";
+ } else {
+ info = "; client_max_window_bits=$clientMaxWindowBits";
+ }
+ if (serverMaxWindowBits != null) {
+ info += "; server_max_window_bits=$serverMaxWindowBits";
+ }
+ }
+
+ return info;
+ }
+
+ /// Create a Compression Header.
+ ///
+ /// If [requested] is null or contains client request headers, returns Client
+ /// compression request headers with default settings for
+ /// `client_max_window_bits` header value. If [requested] contains server
+ /// response headers this method returns a Server compression response header
+ /// negotiating the max window bits for both client and server as requested
+ /// `server_max_window_bits` value. This method returns a
+ /// [_CompressionMaxWindowBits] object with the response headers and
+ /// negotiated `maxWindowBits` value.
+ _CompressionMaxWindowBits _createHeader([HeaderValue requested]) {
+ var info = new _CompressionMaxWindowBits("", 0);
+ if (!enabled) {
+ return info;
+ }
+
+ info.headerValue = _WebSocketImpl.PER_MESSAGE_DEFLATE;
+
+ if (clientNoContextTakeover &&
+ (requested == null ||
+ (requested != null &&
+ requested.parameters.containsKey(_clientNoContextTakeover)))) {
+ info.headerValue += "; client_no_context_takeover";
+ }
+
+ if (serverNoContextTakeover &&
+ (requested == null ||
+ (requested != null &&
+ requested.parameters.containsKey(_serverNoContextTakeover)))) {
+ info.headerValue += "; server_no_context_takeover";
+ }
+
+ var headerList = _createServerResponseHeader(requested);
+ info.headerValue += headerList.headerValue;
+ info.maxWindowBits = headerList.maxWindowBits;
+
+ info.headerValue +=
+ _createClientRequestHeader(requested, info.maxWindowBits);
+
+ return info;
+ }
+}
+
+/**
+ * The [WebSocketTransformer] provides the ability to upgrade a
+ * [HttpRequest] to a [WebSocket] connection. It supports both
+ * upgrading a single [HttpRequest] and upgrading a stream of
+ * [HttpRequest]s.
+ *
+ * To upgrade a single [HttpRequest] use the static [upgrade] method.
+ *
+ * HttpServer server;
+ * server.listen((request) {
+ * if (...) {
+ * WebSocketTransformer.upgrade(request).then((websocket) {
+ * ...
+ * });
+ * } else {
+ * // Do normal HTTP request processing.
+ * }
+ * });
+ *
+ * To transform a stream of [HttpRequest] events as it implements a
+ * stream transformer that transforms a stream of HttpRequest into a
+ * stream of WebSockets by upgrading each HttpRequest from the HTTP or
+ * HTTPS server, to the WebSocket protocol.
+ *
+ * server.transform(new WebSocketTransformer()).listen((webSocket) => ...);
+ *
+ * This transformer strives to implement WebSockets as specified by RFC6455.
+ */
+abstract class WebSocketTransformer
+ implements StreamTransformer<HttpRequest, WebSocket> {
+ /**
+ * Create a new [WebSocketTransformer].
+ *
+ * If [protocolSelector] is provided, [protocolSelector] will be called to
+ * select what protocol to use, if any were provided by the client.
+ * [protocolSelector] is should return either a [String] or a [Future]
+ * completing with a [String]. The [String] must exist in the list of
+ * protocols.
+ *
+ * If [compression] is provided, the [WebSocket] created will be configured
+ * to negotiate with the specified [CompressionOptions]. If none is specified
+ * then the [WebSocket] will be created with the default [CompressionOptions].
+ */
+ factory WebSocketTransformer(
+ {/*String|Future<String>*/ protocolSelector(List<String> protocols),
+ CompressionOptions compression: CompressionOptions.compressionDefault}) {
+ return new _WebSocketTransformerImpl(protocolSelector, compression);
+ }
+
+ /**
+ * Upgrades a [HttpRequest] to a [WebSocket] connection. If the
+ * request is not a valid WebSocket upgrade request an HTTP response
+ * with status code 500 will be returned. Otherwise the returned
+ * future will complete with the [WebSocket] when the upgrade process
+ * is complete.
+ *
+ * If [protocolSelector] is provided, [protocolSelector] will be called to
+ * select what protocol to use, if any were provided by the client.
+ * [protocolSelector] is should return either a [String] or a [Future]
+ * completing with a [String]. The [String] must exist in the list of
+ * protocols.
+ *
+ * If [compression] is provided, the [WebSocket] created will be configured
+ * to negotiate with the specified [CompressionOptions]. If none is specified
+ * then the [WebSocket] will be created with the default [CompressionOptions].
+ */
+ static Future<WebSocket> upgrade(HttpRequest request,
+ {protocolSelector(List<String> protocols),
+ CompressionOptions compression: CompressionOptions.compressionDefault}) {
+ return _WebSocketTransformerImpl._upgrade(
+ request, protocolSelector, compression);
+ }
+
+ /**
+ * Checks whether the request is a valid WebSocket upgrade request.
+ */
+ static bool isUpgradeRequest(HttpRequest request) {
+ return _WebSocketTransformerImpl._isUpgradeRequest(request);
+ }
+}
+
+/**
+ * A two-way HTTP communication object for client or server applications.
+ *
+ * The stream exposes the messages received. A text message will be of type
+ * `String` and a binary message will be of type `List<int>`.
+ */
+abstract class WebSocket
+ implements
+ Stream<dynamic /*String|List<int>*/ >,
+ StreamSink<dynamic /*String|List<int>*/ > {
+ /**
+ * Possible states of the connection.
+ */
+ static const int connecting = 0;
+ static const int open = 1;
+ static const int closing = 2;
+ static const int closed = 3;
+
+ @Deprecated("Use connecting instead")
+ static const int CONNECTING = connecting;
+ @Deprecated("Use open instead")
+ static const int OPEN = open;
+ @Deprecated("Use closing instead")
+ static const int CLOSING = closing;
+ @Deprecated("Use closed instead")
+ static const int CLOSED = closed;
+
+ /**
+ * Set and get the interval for sending ping signals. If a ping message is not
+ * answered by a pong message from the peer, the `WebSocket` is assumed
+ * disconnected and the connection is closed with a
+ * [WebSocketStatus.GOING_AWAY] close code. When a ping signal is sent, the
+ * pong message must be received within [pingInterval].
+ *
+ * There are never two outstanding pings at any given time, and the next ping
+ * timer starts when the pong is received.
+ *
+ * Set the [pingInterval] to `null` to disable sending ping messages.
+ *
+ * The default value is `null`.
+ */
+ Duration pingInterval;
+
+ /**
+ * Create a new WebSocket connection. The URL supplied in [url]
+ * must use the scheme `ws` or `wss`.
+ *
+ * The [protocols] argument is specifying the subprotocols the
+ * client is willing to speak.
+ *
+ * The [headers] argument is specifying additional HTTP headers for
+ * setting up the connection. This would typically be the `Origin`
+ * header and potentially cookies. The keys of the map are the header
+ * fields and the values are either String or List<String>.
+ *
+ * If [headers] is provided, there are a number of headers
+ * which are controlled by the WebSocket connection process. These
+ * headers are:
+ *
+ * - `connection`
+ * - `sec-websocket-key`
+ * - `sec-websocket-protocol`
+ * - `sec-websocket-version`
+ * - `upgrade`
+ *
+ * If any of these are passed in the `headers` map they will be ignored.
+ *
+ * If the `url` contains user information this will be passed as basic
+ * authentication when setting up the connection.
+ */
+ static Future<WebSocket> connect(String url,
+ {Iterable<String> protocols,
+ Map<String, dynamic> headers,
+ CompressionOptions compression:
+ CompressionOptions.compressionDefault}) =>
+ _WebSocketImpl.connect(url, protocols, headers, compression: compression);
+
+ @Deprecated('This constructor will be removed in Dart 2.0. Use `implements`'
+ ' instead of `extends` if implementing this abstract class.')
+ WebSocket();
+
+ /**
+ * Creates a WebSocket from an already-upgraded socket.
+ *
+ * The initial WebSocket handshake must have occurred prior to this call. A
+ * WebSocket client can automatically perform the handshake using
+ * [WebSocket.connect], while a server can do so using
+ * [WebSocketTransformer.upgrade]. To manually upgrade an [HttpRequest],
+ * [HttpResponse.detachSocket] may be called.
+ *
+ * [protocol] should be the protocol negotiated by this handshake, if any.
+ *
+ * [serverSide] must be passed explicitly. If it's `false`, the WebSocket will
+ * act as the client and mask the messages it sends. If it's `true`, it will
+ * act as the server and will not mask its messages.
+ *
+ * If [compression] is provided, the [WebSocket] created will be configured
+ * to negotiate with the specified [CompressionOptions]. If none is specified
+ * then the [WebSocket] will be created with the default [CompressionOptions].
+ */
+ factory WebSocket.fromUpgradedSocket(Socket socket,
+ {String protocol,
+ bool serverSide,
+ CompressionOptions compression: CompressionOptions.compressionDefault}) {
+ if (serverSide == null) {
+ throw new ArgumentError("The serverSide argument must be passed "
+ "explicitly to WebSocket.fromUpgradedSocket.");
+ }
+ return new _WebSocketImpl._fromSocket(
+ socket, protocol, compression, serverSide);
+ }
+
+ /**
+ * Returns the current state of the connection.
+ */
+ int get readyState;
+
+ /**
+ * The extensions property is initially the empty string. After the
+ * WebSocket connection is established this string reflects the
+ * extensions used by the server.
+ */
+ String get extensions;
+
+ /**
+ * The protocol property is initially the empty string. After the
+ * WebSocket connection is established the value is the subprotocol
+ * selected by the server. If no subprotocol is negotiated the
+ * value will remain [:null:].
+ */
+ String get protocol;
+
+ /**
+ * The close code set when the WebSocket connection is closed. If
+ * there is no close code available this property will be [:null:]
+ */
+ int get closeCode;
+
+ /**
+ * The close reason set when the WebSocket connection is closed. If
+ * there is no close reason available this property will be [:null:]
+ */
+ String get closeReason;
+
+ /**
+ * Closes the WebSocket connection. Set the optional [code] and [reason]
+ * arguments to send close information to the remote peer. If they are
+ * omitted, the peer will see [WebSocketStatus.NO_STATUS_RECEIVED] code
+ * with no reason.
+ */
+ Future close([int code, String reason]);
+
+ /**
+ * Sends data on the WebSocket connection. The data in [data] must
+ * be either a `String`, or a `List<int>` holding bytes.
+ */
+ void add(/*String|List<int>*/ data);
+
+ /**
+ * Sends data from a stream on WebSocket connection. Each data event from
+ * [stream] will be send as a single WebSocket frame. The data from [stream]
+ * must be either `String`s, or `List<int>`s holding bytes.
+ */
+ Future addStream(Stream stream);
+
+ /**
+ * Sends a text message with the text represented by [bytes].
+ *
+ * The [bytes] should be valid UTF-8 encoded Unicode characters. If they are
+ * not, the receiving end will close the connection.
+ */
+ void addUtf8Text(List<int> bytes);
+
+ /**
+ * Gets the user agent used for WebSocket connections.
+ */
+ static String get userAgent => _WebSocketImpl.userAgent;
+
+ /**
+ * Sets the user agent to use for WebSocket connections.
+ */
+ static set userAgent(String userAgent) {
+ _WebSocketImpl.userAgent = userAgent;
+ }
+}
+
+class WebSocketException implements IOException {
+ final String message;
+
+ const WebSocketException([this.message = ""]);
+
+ String toString() => "WebSocketException: $message";
+}
diff --git a/sdk_nnbd/lib/_http/websocket_impl.dart b/sdk_nnbd/lib/_http/websocket_impl.dart
new file mode 100644
index 0000000..8750ccc
--- /dev/null
+++ b/sdk_nnbd/lib/_http/websocket_impl.dart
@@ -0,0 +1,1317 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+const String _clientNoContextTakeover = "client_no_context_takeover";
+const String _serverNoContextTakeover = "server_no_context_takeover";
+const String _clientMaxWindowBits = "client_max_window_bits";
+const String _serverMaxWindowBits = "server_max_window_bits";
+
+// Matches _WebSocketOpcode.
+class _WebSocketMessageType {
+ static const int NONE = 0;
+ static const int TEXT = 1;
+ static const int BINARY = 2;
+}
+
+class _WebSocketOpcode {
+ static const int CONTINUATION = 0;
+ static const int TEXT = 1;
+ static const int BINARY = 2;
+ static const int RESERVED_3 = 3;
+ static const int RESERVED_4 = 4;
+ static const int RESERVED_5 = 5;
+ static const int RESERVED_6 = 6;
+ static const int RESERVED_7 = 7;
+ static const int CLOSE = 8;
+ static const int PING = 9;
+ static const int PONG = 10;
+ static const int RESERVED_B = 11;
+ static const int RESERVED_C = 12;
+ static const int RESERVED_D = 13;
+ static const int RESERVED_E = 14;
+ static const int RESERVED_F = 15;
+}
+
+class _EncodedString {
+ final List<int> bytes;
+ _EncodedString(this.bytes);
+}
+
+/**
+ * Stores the header and integer value derived from negotiation of
+ * client_max_window_bits and server_max_window_bits. headerValue will be
+ * set in the Websocket response headers.
+ */
+class _CompressionMaxWindowBits {
+ String headerValue;
+ int maxWindowBits;
+ _CompressionMaxWindowBits([this.headerValue, this.maxWindowBits]);
+ String toString() => headerValue;
+}
+
+/**
+ * The web socket protocol transformer handles the protocol byte stream
+ * which is supplied through the `handleData`. As the protocol is processed,
+ * it'll output frame data as either a List<int> or String.
+ *
+ * Important information about usage: Be sure you use cancelOnError, so the
+ * socket will be closed when the processor encounter an error. Not using it
+ * will lead to undefined behaviour.
+ */
+class _WebSocketProtocolTransformer extends StreamTransformerBase<List<int>,
+ dynamic /*List<int>|_WebSocketPing|_WebSocketPong*/ >
+ implements EventSink<List<int>> {
+ static const int START = 0;
+ static const int LEN_FIRST = 1;
+ static const int LEN_REST = 2;
+ static const int MASK = 3;
+ static const int PAYLOAD = 4;
+ static const int CLOSED = 5;
+ static const int FAILURE = 6;
+ static const int FIN = 0x80;
+ static const int RSV1 = 0x40;
+ static const int RSV2 = 0x20;
+ static const int RSV3 = 0x10;
+ static const int OPCODE = 0xF;
+
+ int _state = START;
+ bool _fin = false;
+ bool _compressed = false;
+ int _opcode = -1;
+ int _len = -1;
+ bool _masked = false;
+ int _remainingLenBytes = -1;
+ int _remainingMaskingKeyBytes = 4;
+ int _remainingPayloadBytes = -1;
+ int _unmaskingIndex = 0;
+ int _currentMessageType = _WebSocketMessageType.NONE;
+ int closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
+ String closeReason = "";
+
+ EventSink<dynamic /*List<int>|_WebSocketPing|_WebSocketPong*/ > _eventSink;
+
+ final bool _serverSide;
+ final List _maskingBytes = new List(4);
+ final BytesBuilder _payload = new BytesBuilder(copy: false);
+
+ _WebSocketPerMessageDeflate _deflate;
+ _WebSocketProtocolTransformer([this._serverSide = false, this._deflate]);
+
+ Stream<dynamic /*List<int>|_WebSocketPing|_WebSocketPong*/ > bind(
+ Stream<List<int>> stream) {
+ return new Stream.eventTransformed(stream, (EventSink eventSink) {
+ if (_eventSink != null) {
+ throw new StateError("WebSocket transformer already used.");
+ }
+ _eventSink = eventSink;
+ return this;
+ });
+ }
+
+ void addError(Object error, [StackTrace stackTrace]) {
+ _eventSink.addError(error, stackTrace);
+ }
+
+ void close() {
+ _eventSink.close();
+ }
+
+ /**
+ * Process data received from the underlying communication channel.
+ */
+ void add(List<int> bytes) {
+ var buffer = bytes is Uint8List ? bytes : new Uint8List.fromList(bytes);
+ int index = 0;
+ int lastIndex = buffer.length;
+ if (_state == CLOSED) {
+ throw new WebSocketException("Data on closed connection");
+ }
+ if (_state == FAILURE) {
+ throw new WebSocketException("Data on failed connection");
+ }
+ while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) {
+ int byte = buffer[index];
+ if (_state <= LEN_REST) {
+ if (_state == START) {
+ _fin = (byte & FIN) != 0;
+
+ if ((byte & (RSV2 | RSV3)) != 0) {
+ // The RSV2, RSV3 bits must both be zero.
+ throw new WebSocketException("Protocol error");
+ }
+
+ _opcode = (byte & OPCODE);
+
+ if (_opcode != _WebSocketOpcode.CONTINUATION) {
+ if ((byte & RSV1) != 0) {
+ _compressed = true;
+ } else {
+ _compressed = false;
+ }
+ }
+
+ if (_opcode <= _WebSocketOpcode.BINARY) {
+ if (_opcode == _WebSocketOpcode.CONTINUATION) {
+ if (_currentMessageType == _WebSocketMessageType.NONE) {
+ throw new WebSocketException("Protocol error");
+ }
+ } else {
+ assert(_opcode == _WebSocketOpcode.TEXT ||
+ _opcode == _WebSocketOpcode.BINARY);
+ if (_currentMessageType != _WebSocketMessageType.NONE) {
+ throw new WebSocketException("Protocol error");
+ }
+ _currentMessageType = _opcode;
+ }
+ } else if (_opcode >= _WebSocketOpcode.CLOSE &&
+ _opcode <= _WebSocketOpcode.PONG) {
+ // Control frames cannot be fragmented.
+ if (!_fin) throw new WebSocketException("Protocol error");
+ } else {
+ throw new WebSocketException("Protocol error");
+ }
+ _state = LEN_FIRST;
+ } else if (_state == LEN_FIRST) {
+ _masked = (byte & 0x80) != 0;
+ _len = byte & 0x7F;
+ if (_isControlFrame() && _len > 125) {
+ throw new WebSocketException("Protocol error");
+ }
+ if (_len == 126) {
+ _len = 0;
+ _remainingLenBytes = 2;
+ _state = LEN_REST;
+ } else if (_len == 127) {
+ _len = 0;
+ _remainingLenBytes = 8;
+ _state = LEN_REST;
+ } else {
+ assert(_len < 126);
+ _lengthDone();
+ }
+ } else {
+ assert(_state == LEN_REST);
+ _len = _len << 8 | byte;
+ _remainingLenBytes--;
+ if (_remainingLenBytes == 0) {
+ _lengthDone();
+ }
+ }
+ } else {
+ if (_state == MASK) {
+ _maskingBytes[4 - _remainingMaskingKeyBytes--] = byte;
+ if (_remainingMaskingKeyBytes == 0) {
+ _maskDone();
+ }
+ } else {
+ assert(_state == PAYLOAD);
+ // The payload is not handled one byte at a time but in blocks.
+ int payloadLength = min(lastIndex - index, _remainingPayloadBytes);
+ _remainingPayloadBytes -= payloadLength;
+ // Unmask payload if masked.
+ if (_masked) {
+ _unmask(index, payloadLength, buffer);
+ }
+ // Control frame and data frame share _payloads.
+ _payload.add(new Uint8List.view(buffer.buffer, index, payloadLength));
+ index += payloadLength;
+ if (_isControlFrame()) {
+ if (_remainingPayloadBytes == 0) _controlFrameEnd();
+ } else {
+ if (_currentMessageType != _WebSocketMessageType.TEXT &&
+ _currentMessageType != _WebSocketMessageType.BINARY) {
+ throw new WebSocketException("Protocol error");
+ }
+ if (_remainingPayloadBytes == 0) _messageFrameEnd();
+ }
+
+ // Hack - as we always do index++ below.
+ index--;
+ }
+ }
+
+ // Move to the next byte.
+ index++;
+ }
+ }
+
+ void _unmask(int index, int length, Uint8List buffer) {
+ const int BLOCK_SIZE = 16;
+ // Skip Int32x4-version if message is small.
+ if (length >= BLOCK_SIZE) {
+ // Start by aligning to 16 bytes.
+ final int startOffset = BLOCK_SIZE - (index & 15);
+ final int end = index + startOffset;
+ for (int i = index; i < end; i++) {
+ buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3];
+ }
+ index += startOffset;
+ length -= startOffset;
+ final int blockCount = length ~/ BLOCK_SIZE;
+ if (blockCount > 0) {
+ // Create mask block.
+ int mask = 0;
+ for (int i = 3; i >= 0; i--) {
+ mask = (mask << 8) | _maskingBytes[(_unmaskingIndex + i) & 3];
+ }
+ Int32x4 blockMask = new Int32x4(mask, mask, mask, mask);
+ Int32x4List blockBuffer =
+ new Int32x4List.view(buffer.buffer, index, blockCount);
+ for (int i = 0; i < blockBuffer.length; i++) {
+ blockBuffer[i] ^= blockMask;
+ }
+ final int bytes = blockCount * BLOCK_SIZE;
+ index += bytes;
+ length -= bytes;
+ }
+ }
+ // Handle end.
+ final int end = index + length;
+ for (int i = index; i < end; i++) {
+ buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3];
+ }
+ }
+
+ void _lengthDone() {
+ if (_masked) {
+ if (!_serverSide) {
+ throw new WebSocketException("Received masked frame from server");
+ }
+ _state = MASK;
+ } else {
+ if (_serverSide) {
+ throw new WebSocketException("Received unmasked frame from client");
+ }
+ _remainingPayloadBytes = _len;
+ _startPayload();
+ }
+ }
+
+ void _maskDone() {
+ _remainingPayloadBytes = _len;
+ _startPayload();
+ }
+
+ void _startPayload() {
+ // If there is no actual payload perform perform callbacks without
+ // going through the PAYLOAD state.
+ if (_remainingPayloadBytes == 0) {
+ if (_isControlFrame()) {
+ switch (_opcode) {
+ case _WebSocketOpcode.CLOSE:
+ _state = CLOSED;
+ _eventSink.close();
+ break;
+ case _WebSocketOpcode.PING:
+ _eventSink.add(new _WebSocketPing());
+ break;
+ case _WebSocketOpcode.PONG:
+ _eventSink.add(new _WebSocketPong());
+ break;
+ }
+ _prepareForNextFrame();
+ } else {
+ _messageFrameEnd();
+ }
+ } else {
+ _state = PAYLOAD;
+ }
+ }
+
+ void _messageFrameEnd() {
+ if (_fin) {
+ var bytes = _payload.takeBytes();
+ if (_deflate != null && _compressed) {
+ bytes = _deflate.processIncomingMessage(bytes);
+ }
+
+ switch (_currentMessageType) {
+ case _WebSocketMessageType.TEXT:
+ _eventSink.add(utf8.decode(bytes));
+ break;
+ case _WebSocketMessageType.BINARY:
+ _eventSink.add(bytes);
+ break;
+ }
+ _currentMessageType = _WebSocketMessageType.NONE;
+ }
+ _prepareForNextFrame();
+ }
+
+ void _controlFrameEnd() {
+ switch (_opcode) {
+ case _WebSocketOpcode.CLOSE:
+ closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
+ var payload = _payload.takeBytes();
+ if (payload.length > 0) {
+ if (payload.length == 1) {
+ throw new WebSocketException("Protocol error");
+ }
+ closeCode = payload[0] << 8 | payload[1];
+ if (closeCode == WebSocketStatus.NO_STATUS_RECEIVED) {
+ throw new WebSocketException("Protocol error");
+ }
+ if (payload.length > 2) {
+ closeReason = utf8.decode(payload.sublist(2));
+ }
+ }
+ _state = CLOSED;
+ _eventSink.close();
+ break;
+
+ case _WebSocketOpcode.PING:
+ _eventSink.add(new _WebSocketPing(_payload.takeBytes()));
+ break;
+
+ case _WebSocketOpcode.PONG:
+ _eventSink.add(new _WebSocketPong(_payload.takeBytes()));
+ break;
+ }
+ _prepareForNextFrame();
+ }
+
+ bool _isControlFrame() {
+ return _opcode == _WebSocketOpcode.CLOSE ||
+ _opcode == _WebSocketOpcode.PING ||
+ _opcode == _WebSocketOpcode.PONG;
+ }
+
+ void _prepareForNextFrame() {
+ if (_state != CLOSED && _state != FAILURE) _state = START;
+ _fin = false;
+ _opcode = -1;
+ _len = -1;
+ _remainingLenBytes = -1;
+ _remainingMaskingKeyBytes = 4;
+ _remainingPayloadBytes = -1;
+ _unmaskingIndex = 0;
+ }
+}
+
+class _WebSocketPing {
+ final List<int> payload;
+ _WebSocketPing([this.payload = null]);
+}
+
+class _WebSocketPong {
+ final List<int> payload;
+ _WebSocketPong([this.payload = null]);
+}
+
+typedef /*String|Future<String>*/ _ProtocolSelector(List<String> protocols);
+
+class _WebSocketTransformerImpl
+ extends StreamTransformerBase<HttpRequest, WebSocket>
+ implements WebSocketTransformer {
+ final StreamController<WebSocket> _controller =
+ new StreamController<WebSocket>(sync: true);
+ final _ProtocolSelector _protocolSelector;
+ final CompressionOptions _compression;
+
+ _WebSocketTransformerImpl(this._protocolSelector, this._compression);
+
+ Stream<WebSocket> bind(Stream<HttpRequest> stream) {
+ stream.listen((request) {
+ _upgrade(request, _protocolSelector, _compression)
+ .then((WebSocket webSocket) => _controller.add(webSocket))
+ .catchError(_controller.addError);
+ }, onDone: () {
+ _controller.close();
+ });
+
+ return _controller.stream;
+ }
+
+ static List<String> _tokenizeFieldValue(String headerValue) {
+ List<String> tokens = new List<String>();
+ int start = 0;
+ int index = 0;
+ while (index < headerValue.length) {
+ if (headerValue[index] == ",") {
+ tokens.add(headerValue.substring(start, index));
+ start = index + 1;
+ } else if (headerValue[index] == " " || headerValue[index] == "\t") {
+ start++;
+ }
+ index++;
+ }
+ tokens.add(headerValue.substring(start, index));
+ return tokens;
+ }
+
+ static Future<WebSocket> _upgrade(HttpRequest request,
+ _ProtocolSelector _protocolSelector, CompressionOptions compression) {
+ var response = request.response;
+ if (!_isUpgradeRequest(request)) {
+ // Send error response.
+ response
+ ..statusCode = HttpStatus.badRequest
+ ..close();
+ return new Future.error(
+ new WebSocketException("Invalid WebSocket upgrade request"));
+ }
+
+ Future<WebSocket> upgrade(String protocol) {
+ // Send the upgrade response.
+ response
+ ..statusCode = HttpStatus.switchingProtocols
+ ..headers.add(HttpHeaders.connectionHeader, "Upgrade")
+ ..headers.add(HttpHeaders.upgradeHeader, "websocket");
+ String key = request.headers.value("Sec-WebSocket-Key");
+ _SHA1 sha1 = new _SHA1();
+ sha1.add("$key$_webSocketGUID".codeUnits);
+ String accept = _CryptoUtils.bytesToBase64(sha1.close());
+ response.headers.add("Sec-WebSocket-Accept", accept);
+ if (protocol != null) {
+ response.headers.add("Sec-WebSocket-Protocol", protocol);
+ }
+
+ var deflate = _negotiateCompression(request, response, compression);
+
+ response.headers.contentLength = 0;
+ return response.detachSocket().then<WebSocket>((socket) =>
+ new _WebSocketImpl._fromSocket(
+ socket, protocol, compression, true, deflate));
+ }
+
+ var protocols = request.headers['Sec-WebSocket-Protocol'];
+ if (protocols != null && _protocolSelector != null) {
+ // The suggested protocols can be spread over multiple lines, each
+ // consisting of multiple protocols. To unify all of them, first join
+ // the lists with ', ' and then tokenize.
+ protocols = _tokenizeFieldValue(protocols.join(', '));
+ return new Future<String>(() => _protocolSelector(protocols))
+ .then<String>((protocol) {
+ if (protocols.indexOf(protocol) < 0) {
+ throw new WebSocketException(
+ "Selected protocol is not in the list of available protocols");
+ }
+ return protocol;
+ }).catchError((error) {
+ response
+ ..statusCode = HttpStatus.internalServerError
+ ..close();
+ throw error;
+ }).then<WebSocket>(upgrade);
+ } else {
+ return upgrade(null);
+ }
+ }
+
+ static _WebSocketPerMessageDeflate _negotiateCompression(HttpRequest request,
+ HttpResponse response, CompressionOptions compression) {
+ var extensionHeader = request.headers.value("Sec-WebSocket-Extensions");
+
+ extensionHeader ??= "";
+
+ var hv = HeaderValue.parse(extensionHeader, valueSeparator: ',');
+ if (compression.enabled && hv.value == _WebSocketImpl.PER_MESSAGE_DEFLATE) {
+ var info = compression._createHeader(hv);
+
+ response.headers.add("Sec-WebSocket-Extensions", info.headerValue);
+ var serverNoContextTakeover =
+ (hv.parameters.containsKey(_serverNoContextTakeover) &&
+ compression.serverNoContextTakeover);
+ var clientNoContextTakeover =
+ (hv.parameters.containsKey(_clientNoContextTakeover) &&
+ compression.clientNoContextTakeover);
+ var deflate = new _WebSocketPerMessageDeflate(
+ serverNoContextTakeover: serverNoContextTakeover,
+ clientNoContextTakeover: clientNoContextTakeover,
+ serverMaxWindowBits: info.maxWindowBits,
+ clientMaxWindowBits: info.maxWindowBits,
+ serverSide: true);
+
+ return deflate;
+ }
+
+ return null;
+ }
+
+ static bool _isUpgradeRequest(HttpRequest request) {
+ if (request.method != "GET") {
+ return false;
+ }
+ if (request.headers[HttpHeaders.connectionHeader] == null) {
+ return false;
+ }
+ bool isUpgrade = false;
+ request.headers[HttpHeaders.connectionHeader].forEach((String value) {
+ if (value.toLowerCase() == "upgrade") isUpgrade = true;
+ });
+ if (!isUpgrade) return false;
+ String upgrade = request.headers.value(HttpHeaders.upgradeHeader);
+ if (upgrade == null || upgrade.toLowerCase() != "websocket") {
+ return false;
+ }
+ String version = request.headers.value("Sec-WebSocket-Version");
+ if (version == null || version != "13") {
+ return false;
+ }
+ String key = request.headers.value("Sec-WebSocket-Key");
+ if (key == null) {
+ return false;
+ }
+ return true;
+ }
+}
+
+class _WebSocketPerMessageDeflate {
+ bool serverNoContextTakeover;
+ bool clientNoContextTakeover;
+ int clientMaxWindowBits;
+ int serverMaxWindowBits;
+ bool serverSide;
+
+ RawZLibFilter decoder;
+ RawZLibFilter encoder;
+
+ _WebSocketPerMessageDeflate(
+ {this.clientMaxWindowBits: _WebSocketImpl.DEFAULT_WINDOW_BITS,
+ this.serverMaxWindowBits: _WebSocketImpl.DEFAULT_WINDOW_BITS,
+ this.serverNoContextTakeover: false,
+ this.clientNoContextTakeover: false,
+ this.serverSide: false});
+
+ void _ensureDecoder() {
+ if (decoder == null) {
+ decoder = new RawZLibFilter.inflateFilter(
+ windowBits: serverSide ? clientMaxWindowBits : serverMaxWindowBits,
+ raw: true);
+ }
+ }
+
+ void _ensureEncoder() {
+ if (encoder == null) {
+ encoder = new RawZLibFilter.deflateFilter(
+ windowBits: serverSide ? serverMaxWindowBits : clientMaxWindowBits,
+ raw: true);
+ }
+ }
+
+ Uint8List processIncomingMessage(List<int> msg) {
+ _ensureDecoder();
+
+ var data = <int>[];
+ data.addAll(msg);
+ data.addAll(const [0x00, 0x00, 0xff, 0xff]);
+
+ decoder.process(data, 0, data.length);
+ var result = <int>[];
+ List<int> out;
+
+ while ((out = decoder.processed()) != null) {
+ result.addAll(out);
+ }
+
+ if ((serverSide && clientNoContextTakeover) ||
+ (!serverSide && serverNoContextTakeover)) {
+ decoder = null;
+ }
+
+ return new Uint8List.fromList(result);
+ }
+
+ List<int> processOutgoingMessage(List<int> msg) {
+ _ensureEncoder();
+ var result = <int>[];
+ Uint8List buffer;
+
+ if (msg is! Uint8List) {
+ for (var i = 0; i < msg.length; i++) {
+ if (msg[i] < 0 || 255 < msg[i]) {
+ throw new ArgumentError("List element is not a byte value "
+ "(value ${msg[i]} at index $i)");
+ }
+ }
+ buffer = new Uint8List.fromList(msg);
+ } else {
+ buffer = msg;
+ }
+
+ encoder.process(buffer, 0, buffer.length);
+
+ List<int> out;
+ while ((out = encoder.processed()) != null) {
+ result.addAll(out);
+ }
+
+ if ((!serverSide && clientNoContextTakeover) ||
+ (serverSide && serverNoContextTakeover)) {
+ encoder = null;
+ }
+
+ if (result.length > 4) {
+ result = result.sublist(0, result.length - 4);
+ }
+
+ // RFC 7692 7.2.3.6. "Generating an Empty Fragment" says that if the
+ // compression library doesn't generate any data when the bufer is empty,
+ // then an empty uncompressed deflate block is used for this purpose. The
+ // 0x00 block has the BFINAL header bit set to 0 and the BTYPE header set to
+ // 00 along with 5 bits of padding. This block decodes to zero bytes.
+ if (result.length == 0) {
+ return [0x00];
+ }
+
+ return result;
+ }
+}
+
+// TODO(ajohnsen): Make this transformer reusable.
+class _WebSocketOutgoingTransformer
+ extends StreamTransformerBase<dynamic, List<int>> implements EventSink {
+ final _WebSocketImpl webSocket;
+ EventSink<List<int>> _eventSink;
+
+ _WebSocketPerMessageDeflate _deflateHelper;
+
+ _WebSocketOutgoingTransformer(this.webSocket) {
+ _deflateHelper = webSocket._deflate;
+ }
+
+ Stream<List<int>> bind(Stream stream) {
+ return new Stream<List<int>>.eventTransformed(stream,
+ (EventSink<List<int>> eventSink) {
+ if (_eventSink != null) {
+ throw new StateError("WebSocket transformer already used");
+ }
+ _eventSink = eventSink;
+ return this;
+ });
+ }
+
+ void add(message) {
+ if (message is _WebSocketPong) {
+ addFrame(_WebSocketOpcode.PONG, message.payload);
+ return;
+ }
+ if (message is _WebSocketPing) {
+ addFrame(_WebSocketOpcode.PING, message.payload);
+ return;
+ }
+ List<int> data;
+ int opcode;
+ if (message != null) {
+ if (message is String) {
+ opcode = _WebSocketOpcode.TEXT;
+ data = utf8.encode(message);
+ } else if (message is List<int>) {
+ opcode = _WebSocketOpcode.BINARY;
+ data = message;
+ } else if (message is _EncodedString) {
+ opcode = _WebSocketOpcode.TEXT;
+ data = message.bytes;
+ } else {
+ throw new ArgumentError(message);
+ }
+
+ if (_deflateHelper != null) {
+ data = _deflateHelper.processOutgoingMessage(data);
+ }
+ } else {
+ opcode = _WebSocketOpcode.TEXT;
+ }
+ addFrame(opcode, data);
+ }
+
+ void addError(Object error, [StackTrace stackTrace]) {
+ _eventSink.addError(error, stackTrace);
+ }
+
+ void close() {
+ int code = webSocket._outCloseCode;
+ String reason = webSocket._outCloseReason;
+ List<int> data;
+ if (code != null) {
+ data = new List<int>();
+ data.add((code >> 8) & 0xFF);
+ data.add(code & 0xFF);
+ if (reason != null) {
+ data.addAll(utf8.encode(reason));
+ }
+ }
+ addFrame(_WebSocketOpcode.CLOSE, data);
+ _eventSink.close();
+ }
+
+ void addFrame(int opcode, List<int> data) {
+ createFrame(
+ opcode,
+ data,
+ webSocket._serverSide,
+ _deflateHelper != null &&
+ (opcode == _WebSocketOpcode.TEXT ||
+ opcode == _WebSocketOpcode.BINARY))
+ .forEach((e) {
+ _eventSink.add(e);
+ });
+ }
+
+ static Iterable<List<int>> createFrame(
+ int opcode, List<int> data, bool serverSide, bool compressed) {
+ bool mask = !serverSide; // Masking not implemented for server.
+ int dataLength = data == null ? 0 : data.length;
+ // Determine the header size.
+ int headerSize = (mask) ? 6 : 2;
+ if (dataLength > 65535) {
+ headerSize += 8;
+ } else if (dataLength > 125) {
+ headerSize += 2;
+ }
+ Uint8List header = new Uint8List(headerSize);
+ int index = 0;
+
+ // Set FIN and opcode.
+ var hoc = _WebSocketProtocolTransformer.FIN |
+ (compressed ? _WebSocketProtocolTransformer.RSV1 : 0) |
+ (opcode & _WebSocketProtocolTransformer.OPCODE);
+
+ header[index++] = hoc;
+ // Determine size and position of length field.
+ int lengthBytes = 1;
+ if (dataLength > 65535) {
+ header[index++] = 127;
+ lengthBytes = 8;
+ } else if (dataLength > 125) {
+ header[index++] = 126;
+ lengthBytes = 2;
+ }
+ // Write the length in network byte order into the header.
+ for (int i = 0; i < lengthBytes; i++) {
+ header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF;
+ }
+ if (mask) {
+ header[1] |= 1 << 7;
+ var maskBytes = _CryptoUtils.getRandomBytes(4);
+ header.setRange(index, index + 4, maskBytes);
+ index += 4;
+ if (data != null) {
+ Uint8List list;
+ // If this is a text message just do the masking inside the
+ // encoded data.
+ if (opcode == _WebSocketOpcode.TEXT && data is Uint8List) {
+ list = data;
+ } else {
+ if (data is Uint8List) {
+ list = new Uint8List.fromList(data);
+ } else {
+ list = new Uint8List(data.length);
+ for (int i = 0; i < data.length; i++) {
+ if (data[i] < 0 || 255 < data[i]) {
+ throw new ArgumentError("List element is not a byte value "
+ "(value ${data[i]} at index $i)");
+ }
+ list[i] = data[i];
+ }
+ }
+ }
+ const int BLOCK_SIZE = 16;
+ int blockCount = list.length ~/ BLOCK_SIZE;
+ if (blockCount > 0) {
+ // Create mask block.
+ int mask = 0;
+ for (int i = 3; i >= 0; i--) {
+ mask = (mask << 8) | maskBytes[i];
+ }
+ Int32x4 blockMask = new Int32x4(mask, mask, mask, mask);
+ Int32x4List blockBuffer =
+ new Int32x4List.view(list.buffer, 0, blockCount);
+ for (int i = 0; i < blockBuffer.length; i++) {
+ blockBuffer[i] ^= blockMask;
+ }
+ }
+ // Handle end.
+ for (int i = blockCount * BLOCK_SIZE; i < list.length; i++) {
+ list[i] ^= maskBytes[i & 3];
+ }
+ data = list;
+ }
+ }
+ assert(index == headerSize);
+ if (data == null) {
+ return [header];
+ } else {
+ return [header, data];
+ }
+ }
+}
+
+class _WebSocketConsumer implements StreamConsumer {
+ final _WebSocketImpl webSocket;
+ final Socket socket;
+ StreamController _controller;
+ StreamSubscription _subscription;
+ bool _issuedPause = false;
+ bool _closed = false;
+ Completer _closeCompleter = new Completer<WebSocket>();
+ Completer _completer;
+
+ _WebSocketConsumer(this.webSocket, this.socket);
+
+ void _onListen() {
+ if (_subscription != null) {
+ _subscription.cancel();
+ }
+ }
+
+ void _onPause() {
+ if (_subscription != null) {
+ _subscription.pause();
+ } else {
+ _issuedPause = true;
+ }
+ }
+
+ void _onResume() {
+ if (_subscription != null) {
+ _subscription.resume();
+ } else {
+ _issuedPause = false;
+ }
+ }
+
+ void _cancel() {
+ if (_subscription != null) {
+ var subscription = _subscription;
+ _subscription = null;
+ subscription.cancel();
+ }
+ }
+
+ _ensureController() {
+ if (_controller != null) return;
+ _controller = new StreamController(
+ sync: true,
+ onPause: _onPause,
+ onResume: _onResume,
+ onCancel: _onListen);
+ var stream = _controller.stream
+ .transform(new _WebSocketOutgoingTransformer(webSocket));
+ socket.addStream(stream).then((_) {
+ _done();
+ _closeCompleter.complete(webSocket);
+ }, onError: (error, StackTrace stackTrace) {
+ _closed = true;
+ _cancel();
+ if (error is ArgumentError) {
+ if (!_done(error, stackTrace)) {
+ _closeCompleter.completeError(error, stackTrace);
+ }
+ } else {
+ _done();
+ _closeCompleter.complete(webSocket);
+ }
+ });
+ }
+
+ bool _done([error, StackTrace stackTrace]) {
+ if (_completer == null) return false;
+ if (error != null) {
+ _completer.completeError(error, stackTrace);
+ } else {
+ _completer.complete(webSocket);
+ }
+ _completer = null;
+ return true;
+ }
+
+ Future addStream(var stream) {
+ if (_closed) {
+ stream.listen(null).cancel();
+ return new Future.value(webSocket);
+ }
+ _ensureController();
+ _completer = new Completer();
+ _subscription = stream.listen((data) {
+ _controller.add(data);
+ }, onDone: _done, onError: _done, cancelOnError: true);
+ if (_issuedPause) {
+ _subscription.pause();
+ _issuedPause = false;
+ }
+ return _completer.future;
+ }
+
+ Future close() {
+ _ensureController();
+ Future closeSocket() {
+ return socket.close().catchError((_) {}).then((_) => webSocket);
+ }
+
+ _controller.close();
+ return _closeCompleter.future.then((_) => closeSocket());
+ }
+
+ void add(data) {
+ if (_closed) return;
+ _ensureController();
+ // Stop sending message if _controller has been closed.
+ // https://github.com/dart-lang/sdk/issues/37441
+ if (_controller.isClosed) return;
+ _controller.add(data);
+ }
+
+ void closeSocket() {
+ _closed = true;
+ _cancel();
+ close();
+ }
+}
+
+class _WebSocketImpl extends Stream with _ServiceObject implements WebSocket {
+ // Use default Map so we keep order.
+ static Map<int, _WebSocketImpl> _webSockets = new Map<int, _WebSocketImpl>();
+ static const int DEFAULT_WINDOW_BITS = 15;
+ static const String PER_MESSAGE_DEFLATE = "permessage-deflate";
+
+ final String protocol;
+
+ StreamController _controller;
+ StreamSubscription _subscription;
+ StreamSink _sink;
+
+ final _socket;
+ final bool _serverSide;
+ int _readyState = WebSocket.connecting;
+ bool _writeClosed = false;
+ int _closeCode;
+ String _closeReason;
+ Duration _pingInterval;
+ Timer _pingTimer;
+ _WebSocketConsumer _consumer;
+
+ int _outCloseCode;
+ String _outCloseReason;
+ Timer _closeTimer;
+ _WebSocketPerMessageDeflate _deflate;
+
+ static final HttpClient _httpClient = new HttpClient();
+
+ static Future<WebSocket> connect(
+ String url, Iterable<String> protocols, Map<String, dynamic> headers,
+ {CompressionOptions compression: CompressionOptions.compressionDefault}) {
+ Uri uri = Uri.parse(url);
+ if (uri.scheme != "ws" && uri.scheme != "wss") {
+ throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'");
+ }
+
+ Random random = new Random();
+ // Generate 16 random bytes.
+ Uint8List nonceData = new Uint8List(16);
+ for (int i = 0; i < 16; i++) {
+ nonceData[i] = random.nextInt(256);
+ }
+ String nonce = _CryptoUtils.bytesToBase64(nonceData);
+
+ uri = new Uri(
+ scheme: uri.scheme == "wss" ? "https" : "http",
+ userInfo: uri.userInfo,
+ host: uri.host,
+ port: uri.port,
+ path: uri.path,
+ query: uri.query,
+ fragment: uri.fragment);
+ return _httpClient.openUrl("GET", uri).then((request) {
+ if (uri.userInfo != null && !uri.userInfo.isEmpty) {
+ // If the URL contains user information use that for basic
+ // authorization.
+ String auth = _CryptoUtils.bytesToBase64(utf8.encode(uri.userInfo));
+ request.headers.set(HttpHeaders.authorizationHeader, "Basic $auth");
+ }
+ if (headers != null) {
+ headers.forEach((field, value) => request.headers.add(field, value));
+ }
+ // Setup the initial handshake.
+ request.headers
+ ..set(HttpHeaders.connectionHeader, "Upgrade")
+ ..set(HttpHeaders.upgradeHeader, "websocket")
+ ..set("Sec-WebSocket-Key", nonce)
+ ..set("Cache-Control", "no-cache")
+ ..set("Sec-WebSocket-Version", "13");
+ if (protocols != null) {
+ request.headers.add("Sec-WebSocket-Protocol", protocols.toList());
+ }
+
+ if (compression.enabled) {
+ request.headers
+ .add("Sec-WebSocket-Extensions", compression._createHeader());
+ }
+
+ return request.close();
+ }).then((response) {
+ void error(String message) {
+ // Flush data.
+ response.detachSocket().then((socket) {
+ socket.destroy();
+ });
+ throw new WebSocketException(message);
+ }
+
+ if (response.statusCode != HttpStatus.switchingProtocols ||
+ response.headers[HttpHeaders.connectionHeader] == null ||
+ !response.headers[HttpHeaders.connectionHeader]
+ .any((value) => value.toLowerCase() == "upgrade") ||
+ response.headers.value(HttpHeaders.upgradeHeader).toLowerCase() !=
+ "websocket") {
+ error("Connection to '$uri' was not upgraded to websocket");
+ }
+ String accept = response.headers.value("Sec-WebSocket-Accept");
+ if (accept == null) {
+ error("Response did not contain a 'Sec-WebSocket-Accept' header");
+ }
+ _SHA1 sha1 = new _SHA1();
+ sha1.add("$nonce$_webSocketGUID".codeUnits);
+ List<int> expectedAccept = sha1.close();
+ List<int> receivedAccept = _CryptoUtils.base64StringToBytes(accept);
+ if (expectedAccept.length != receivedAccept.length) {
+ error("Response header 'Sec-WebSocket-Accept' is the wrong length");
+ }
+ for (int i = 0; i < expectedAccept.length; i++) {
+ if (expectedAccept[i] != receivedAccept[i]) {
+ error("Bad response 'Sec-WebSocket-Accept' header");
+ }
+ }
+ var protocol = response.headers.value('Sec-WebSocket-Protocol');
+
+ _WebSocketPerMessageDeflate deflate =
+ negotiateClientCompression(response, compression);
+
+ return response.detachSocket().then<WebSocket>((socket) =>
+ new _WebSocketImpl._fromSocket(
+ socket, protocol, compression, false, deflate));
+ });
+ }
+
+ static _WebSocketPerMessageDeflate negotiateClientCompression(
+ HttpClientResponse response, CompressionOptions compression) {
+ String extensionHeader = response.headers.value('Sec-WebSocket-Extensions');
+
+ if (extensionHeader == null) {
+ extensionHeader = "";
+ }
+
+ var hv = HeaderValue.parse(extensionHeader, valueSeparator: ',');
+
+ if (compression.enabled && hv.value == PER_MESSAGE_DEFLATE) {
+ var serverNoContextTakeover =
+ hv.parameters.containsKey(_serverNoContextTakeover);
+ var clientNoContextTakeover =
+ hv.parameters.containsKey(_clientNoContextTakeover);
+
+ int getWindowBits(String type) {
+ var o = hv.parameters[type];
+ if (o == null) {
+ return DEFAULT_WINDOW_BITS;
+ }
+
+ return int.parse(o, onError: (s) => DEFAULT_WINDOW_BITS);
+ }
+
+ return new _WebSocketPerMessageDeflate(
+ clientMaxWindowBits: getWindowBits(_clientMaxWindowBits),
+ serverMaxWindowBits: getWindowBits(_serverMaxWindowBits),
+ clientNoContextTakeover: clientNoContextTakeover,
+ serverNoContextTakeover: serverNoContextTakeover);
+ }
+
+ return null;
+ }
+
+ _WebSocketImpl._fromSocket(
+ this._socket, this.protocol, CompressionOptions compression,
+ [this._serverSide = false, _WebSocketPerMessageDeflate deflate]) {
+ _consumer = new _WebSocketConsumer(this, _socket);
+ _sink = new _StreamSinkImpl(_consumer);
+ _readyState = WebSocket.open;
+ _deflate = deflate;
+
+ var transformer = new _WebSocketProtocolTransformer(_serverSide, _deflate);
+ _subscription = transformer.bind(_socket).listen((data) {
+ if (data is _WebSocketPing) {
+ if (!_writeClosed) _consumer.add(new _WebSocketPong(data.payload));
+ } else if (data is _WebSocketPong) {
+ // Simply set pingInterval, as it'll cancel any timers.
+ pingInterval = _pingInterval;
+ } else {
+ _controller.add(data);
+ }
+ }, onError: (error, stackTrace) {
+ if (_closeTimer != null) _closeTimer.cancel();
+ if (error is FormatException) {
+ _close(WebSocketStatus.INVALID_FRAME_PAYLOAD_DATA);
+ } else {
+ _close(WebSocketStatus.PROTOCOL_ERROR);
+ }
+ // An error happened, set the close code set above.
+ _closeCode = _outCloseCode;
+ _closeReason = _outCloseReason;
+ _controller.close();
+ }, onDone: () {
+ if (_closeTimer != null) _closeTimer.cancel();
+ if (_readyState == WebSocket.open) {
+ _readyState = WebSocket.closing;
+ if (!_isReservedStatusCode(transformer.closeCode)) {
+ _close(transformer.closeCode, transformer.closeReason);
+ } else {
+ _close();
+ }
+ _readyState = WebSocket.closed;
+ }
+ // Protocol close, use close code from transformer.
+ _closeCode = transformer.closeCode;
+ _closeReason = transformer.closeReason;
+ _controller.close();
+ }, cancelOnError: true);
+ _subscription.pause();
+ _controller = new StreamController(
+ sync: true,
+ onListen: _subscription.resume,
+ onCancel: () {
+ _subscription.cancel();
+ _subscription = null;
+ },
+ onPause: _subscription.pause,
+ onResume: _subscription.resume);
+
+ _webSockets[_serviceId] = this;
+ }
+
+ StreamSubscription listen(void onData(message),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ return _controller.stream.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ Duration get pingInterval => _pingInterval;
+
+ void set pingInterval(Duration interval) {
+ if (_writeClosed) return;
+ if (_pingTimer != null) _pingTimer.cancel();
+ _pingInterval = interval;
+
+ if (_pingInterval == null) return;
+
+ _pingTimer = new Timer(_pingInterval, () {
+ if (_writeClosed) return;
+ _consumer.add(new _WebSocketPing());
+ _pingTimer = new Timer(_pingInterval, () {
+ // No pong received.
+ _close(WebSocketStatus.GOING_AWAY);
+ });
+ });
+ }
+
+ int get readyState => _readyState;
+
+ String get extensions => null;
+ int get closeCode => _closeCode;
+ String get closeReason => _closeReason;
+
+ void add(data) {
+ _sink.add(data);
+ }
+
+ void addUtf8Text(List<int> bytes) {
+ ArgumentError.checkNotNull(bytes, "bytes");
+ _sink.add(new _EncodedString(bytes));
+ }
+
+ void addError(error, [StackTrace stackTrace]) {
+ _sink.addError(error, stackTrace);
+ }
+
+ Future addStream(Stream stream) => _sink.addStream(stream);
+ Future get done => _sink.done;
+
+ Future close([int code, String reason]) {
+ if (_isReservedStatusCode(code)) {
+ throw new WebSocketException("Reserved status code $code");
+ }
+ if (_outCloseCode == null) {
+ _outCloseCode = code;
+ _outCloseReason = reason;
+ }
+ if (!_controller.isClosed) {
+ // If a close has not yet been received from the other end then
+ // 1) make sure to listen on the stream so the close frame will be
+ // processed if received.
+ // 2) set a timer terminate the connection if a close frame is
+ // not received.
+ if (!_controller.hasListener && _subscription != null) {
+ _controller.stream.drain().catchError((_) => {});
+ }
+ if (_closeTimer == null) {
+ // When closing the web-socket, we no longer accept data.
+ _closeTimer = new Timer(const Duration(seconds: 5), () {
+ // Reuse code and reason from the local close.
+ _closeCode = _outCloseCode;
+ _closeReason = _outCloseReason;
+ if (_subscription != null) _subscription.cancel();
+ _controller.close();
+ _webSockets.remove(_serviceId);
+ });
+ }
+ }
+ return _sink.close();
+ }
+
+ static String get userAgent => _httpClient.userAgent;
+
+ static set userAgent(String userAgent) {
+ _httpClient.userAgent = userAgent;
+ }
+
+ void _close([int code, String reason]) {
+ if (_writeClosed) return;
+ if (_outCloseCode == null) {
+ _outCloseCode = code;
+ _outCloseReason = reason;
+ }
+ _writeClosed = true;
+ _consumer.closeSocket();
+ _webSockets.remove(_serviceId);
+ }
+
+ String get _serviceTypePath => 'io/websockets';
+ String get _serviceTypeName => 'WebSocket';
+
+ Map<String, dynamic> _toJSON(bool ref) {
+ var name = '${_socket.address.host}:${_socket.port}';
+ var r = <String, dynamic>{
+ 'id': _servicePath,
+ 'type': _serviceType(ref),
+ 'name': name,
+ 'user_name': name,
+ };
+ if (ref) {
+ return r;
+ }
+ try {
+ r['socket'] = _socket._toJSON(true);
+ } catch (_) {
+ r['socket'] = {
+ 'id': _servicePath,
+ 'type': '@Socket',
+ 'name': 'UserSocket',
+ 'user_name': 'UserSocket',
+ };
+ }
+ return r;
+ }
+
+ static bool _isReservedStatusCode(int code) {
+ return code != null &&
+ (code < WebSocketStatus.NORMAL_CLOSURE ||
+ code == WebSocketStatus.RESERVED_1004 ||
+ code == WebSocketStatus.NO_STATUS_RECEIVED ||
+ code == WebSocketStatus.ABNORMAL_CLOSURE ||
+ (code > WebSocketStatus.INTERNAL_SERVER_ERROR &&
+ code < WebSocketStatus.RESERVED_1015) ||
+ (code >= WebSocketStatus.RESERVED_1015 && code < 3000));
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
new file mode 100644
index 0000000..91d6847
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
@@ -0,0 +1,595 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Support for interoperating with JavaScript.
+ *
+ * This library provides access to JavaScript objects from Dart, allowing
+ * Dart code to get and set properties, and call methods of JavaScript objects
+ * and invoke JavaScript functions. The library takes care of converting
+ * between Dart and JavaScript objects where possible, or providing proxies if
+ * conversion isn't possible.
+ *
+ * This library does not yet make Dart objects usable from JavaScript, their
+ * methods and proeprties are not accessible, though it does allow Dart
+ * functions to be passed into and called from JavaScript.
+ *
+ * [JsObject] is the core type and represents a proxy of a JavaScript object.
+ * JsObject gives access to the underlying JavaScript objects properties and
+ * methods. `JsObject`s can be acquired by calls to JavaScript, or they can be
+ * created from proxies to JavaScript constructors.
+ *
+ * The top-level getter [context] provides a [JsObject] that represents the
+ * global object in JavaScript, usually `window`.
+ *
+ * The following example shows an alert dialog via a JavaScript call to the
+ * global function `alert()`:
+ *
+ * import 'dart:js';
+ *
+ * main() => context.callMethod('alert', ['Hello from Dart!']);
+ *
+ * This example shows how to create a [JsObject] from a JavaScript constructor
+ * and access its properties:
+ *
+ * import 'dart:js';
+ *
+ * main() {
+ * var object = new JsObject(context['Object']);
+ * object['greeting'] = 'Hello';
+ * object['greet'] = (name) => "${object['greeting']} $name";
+ * var message = object.callMethod('greet', ['JavaScript']);
+ * context['console'].callMethod('log', [message]);
+ * }
+ *
+ * ## Proxying and automatic conversion
+ *
+ * When setting properties on a JsObject or passing arguments to a Javascript
+ * method or function, Dart objects are automatically converted or proxied to
+ * JavaScript objects. When accessing JavaScript properties, or when a Dart
+ * closure is invoked from JavaScript, the JavaScript objects are also
+ * converted to Dart.
+ *
+ * Functions and closures are proxied in such a way that they are callable. A
+ * Dart closure assigned to a JavaScript property is proxied by a function in
+ * JavaScript. A JavaScript function accessed from Dart is proxied by a
+ * [JsFunction], which has a [apply] method to invoke it.
+ *
+ * The following types are transferred directly and not proxied:
+ *
+ * * "Basic" types: `null`, `bool`, `num`, `String`, `DateTime`
+ * * `Blob`
+ * * `Event`
+ * * `HtmlCollection`
+ * * `ImageData`
+ * * `KeyRange`
+ * * `Node`
+ * * `NodeList`
+ * * `TypedData`, including its subclasses like `Int32List`, but _not_
+ * `ByteBuffer`
+ * * `Window`
+ *
+ * ## Converting collections with JsObject.jsify()
+ *
+ * To create a JavaScript collection from a Dart collection use the
+ * [JsObject.jsify] constructor, which converts Dart [Map]s and [Iterable]s
+ * into JavaScript Objects and Arrays.
+ *
+ * The following expression creates a new JavaScript object with the properties
+ * `a` and `b` defined:
+ *
+ * var jsMap = new JsObject.jsify({'a': 1, 'b': 2});
+ *
+ * This expression creates a JavaScript array:
+ *
+ * var jsArray = new JsObject.jsify([1, 2, 3]);
+ */
+library dart.js;
+
+import 'dart:collection' show HashMap, ListMixin;
+
+import 'dart:_js_helper' show Primitives;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_runtime' as dart;
+
+final JsObject context = _wrapToDart(dart.global_);
+
+/**
+ * Proxies a JavaScript object to Dart.
+ *
+ * The properties of the JavaScript object are accessible via the `[]` and
+ * `[]=` operators. Methods are callable via [callMethod].
+ */
+class JsObject {
+ // The wrapped JS object.
+ final dynamic _jsObject;
+
+ // This should only be called from _wrapToDart
+ JsObject._fromJs(this._jsObject) {
+ assert(_jsObject != null);
+ }
+
+ /**
+ * Constructs a new JavaScript object from [constructor] and returns a proxy
+ * to it.
+ */
+ factory JsObject(JsFunction constructor, [List arguments]) {
+ var ctor = constructor._jsObject;
+ if (arguments == null) {
+ return _wrapToDart(JS('', 'new #()', ctor));
+ }
+ var unwrapped = List.from(arguments.map(_convertToJS));
+ return _wrapToDart(JS('', 'new #(...#)', ctor, unwrapped));
+ }
+
+ /**
+ * Constructs a [JsObject] that proxies a native Dart object; _for expert use
+ * only_.
+ *
+ * Use this constructor only if you wish to get access to JavaScript
+ * properties attached to a browser host object, such as a Node or Blob, that
+ * is normally automatically converted into a native Dart object.
+ *
+ * An exception will be thrown if [object] either is `null` or has the type
+ * `bool`, `num`, or `String`.
+ */
+ factory JsObject.fromBrowserObject(object) {
+ if (object is num || object is String || object is bool || object == null) {
+ throw ArgumentError("object cannot be a num, string, bool, or null");
+ }
+ return _wrapToDart(_convertToJS(object));
+ }
+
+ /**
+ * Recursively converts a JSON-like collection of Dart objects to a
+ * collection of JavaScript objects and returns a [JsObject] proxy to it.
+ *
+ * [object] must be a [Map] or [Iterable], the contents of which are also
+ * converted. Maps and Iterables are copied to a new JavaScript object.
+ * Primitives and other transferable values are directly converted to their
+ * JavaScript type, and all other objects are proxied.
+ */
+ factory JsObject.jsify(object) {
+ if ((object is! Map) && (object is! Iterable)) {
+ throw ArgumentError("object must be a Map or Iterable");
+ }
+ return _wrapToDart(_convertDataTree(object));
+ }
+
+ static _convertDataTree(data) {
+ var _convertedObjects = HashMap.identity();
+
+ _convert(o) {
+ if (_convertedObjects.containsKey(o)) {
+ return _convertedObjects[o];
+ }
+ if (o is Map) {
+ final convertedMap = JS('', '{}');
+ _convertedObjects[o] = convertedMap;
+ for (var key in o.keys) {
+ JS('', '#[#] = #', convertedMap, key, _convert(o[key]));
+ }
+ return convertedMap;
+ } else if (o is Iterable) {
+ var convertedList = [];
+ _convertedObjects[o] = convertedList;
+ convertedList.addAll(o.map(_convert));
+ return convertedList;
+ } else {
+ return _convertToJS(o);
+ }
+ }
+
+ return _convert(data);
+ }
+
+ /**
+ * Returns the value associated with [property] from the proxied JavaScript
+ * object.
+ *
+ * The type of [property] must be either [String] or [num].
+ */
+ dynamic operator [](Object property) {
+ if (property is! String && property is! num) {
+ throw ArgumentError("property is not a String or num");
+ }
+ return _convertToDart(JS('', '#[#]', _jsObject, property));
+ }
+
+ /**
+ * Sets the value associated with [property] on the proxied JavaScript
+ * object.
+ *
+ * The type of [property] must be either [String] or [num].
+ */
+ void operator []=(Object property, value) {
+ if (property is! String && property is! num) {
+ throw ArgumentError("property is not a String or num");
+ }
+ JS('', '#[#] = #', _jsObject, property, _convertToJS(value));
+ }
+
+ int get hashCode => 0;
+
+ bool operator ==(other) =>
+ other is JsObject && JS<bool>('!', '# === #', _jsObject, other._jsObject);
+
+ /**
+ * Returns `true` if the JavaScript object contains the specified property
+ * either directly or though its prototype chain.
+ *
+ * This is the equivalent of the `in` operator in JavaScript.
+ */
+ bool hasProperty(property) {
+ if (property is! String && property is! num) {
+ throw ArgumentError("property is not a String or num");
+ }
+ return JS<bool>('!', '# in #', property, _jsObject);
+ }
+
+ /**
+ * Removes [property] from the JavaScript object.
+ *
+ * This is the equivalent of the `delete` operator in JavaScript.
+ */
+ void deleteProperty(property) {
+ if (property is! String && property is! num) {
+ throw ArgumentError("property is not a String or num");
+ }
+ JS<bool>('!', 'delete #[#]', _jsObject, property);
+ }
+
+ /**
+ * Returns `true` if the JavaScript object has [type] in its prototype chain.
+ *
+ * This is the equivalent of the `instanceof` operator in JavaScript.
+ */
+ bool instanceof(JsFunction type) {
+ return JS<bool>('!', '# instanceof #', _jsObject, _convertToJS(type));
+ }
+
+ /**
+ * Returns the result of the JavaScript objects `toString` method.
+ */
+ String toString() {
+ try {
+ return JS<String>('!', 'String(#)', _jsObject);
+ } catch (e) {
+ return super.toString();
+ }
+ }
+
+ /**
+ * Calls [method] on the JavaScript object with the arguments [args] and
+ * returns the result.
+ *
+ * The type of [method] must be either [String] or [num].
+ */
+ dynamic callMethod(method, [List args]) {
+ if (method is! String && method is! num) {
+ throw ArgumentError("method is not a String or num");
+ }
+ if (args != null) args = List.from(args.map(_convertToJS));
+ var fn = JS('', '#[#]', _jsObject, method);
+ if (JS<bool>('!', 'typeof(#) !== "function"', fn)) {
+ throw NoSuchMethodError(_jsObject, Symbol(method), args, {});
+ }
+ return _convertToDart(JS('', '#.apply(#, #)', fn, _jsObject, args));
+ }
+}
+
+/**
+ * Proxies a JavaScript Function object.
+ */
+class JsFunction extends JsObject {
+ /**
+ * Returns a [JsFunction] that captures its 'this' binding and calls [f]
+ * with the value of this passed as the first argument.
+ */
+ factory JsFunction.withThis(Function f) {
+ return JsFunction._fromJs(JS(
+ '',
+ 'function(/*...arguments*/) {'
+ ' let args = [#(this)];'
+ ' for (let arg of arguments) {'
+ ' args.push(#(arg));'
+ ' }'
+ ' return #(#(...args));'
+ '}',
+ _convertToDart,
+ _convertToDart,
+ _convertToJS,
+ f));
+ }
+
+ JsFunction._fromJs(jsObject) : super._fromJs(jsObject);
+
+ /**
+ * Invokes the JavaScript function with arguments [args]. If [thisArg] is
+ * supplied it is the value of `this` for the invocation.
+ */
+ dynamic apply(List args, {thisArg}) => _convertToDart(JS(
+ '',
+ '#.apply(#, #)',
+ _jsObject,
+ _convertToJS(thisArg),
+ args == null ? null : List.from(args.map(_convertToJS))));
+}
+
+// TODO(jmesserly): this is totally unnecessary in dev_compiler.
+/** A [List] that proxies a JavaScript array. */
+class JsArray<E> extends JsObject with ListMixin<E> {
+ /**
+ * Creates a new JavaScript array.
+ */
+ JsArray() : super._fromJs([]);
+
+ /**
+ * Creates a new JavaScript array and initializes it to the contents of
+ * [other].
+ */
+ JsArray.from(Iterable<E> other)
+ : super._fromJs([]..addAll(other.map(_convertToJS)));
+
+ JsArray._fromJs(jsObject) : super._fromJs(jsObject);
+
+ _checkIndex(int index) {
+ if (index is int && (index < 0 || index >= length)) {
+ throw RangeError.range(index, 0, length);
+ }
+ }
+
+ _checkInsertIndex(int index) {
+ if (index is int && (index < 0 || index >= length + 1)) {
+ throw RangeError.range(index, 0, length);
+ }
+ }
+
+ static _checkRange(int start, int end, int length) {
+ if (start < 0 || start > length) {
+ throw RangeError.range(start, 0, length);
+ }
+ if (end < start || end > length) {
+ throw RangeError.range(end, start, length);
+ }
+ }
+
+ // Methods required by ListMixin
+
+ E operator [](Object index) {
+ // TODO(justinfagnani): fix the semantics for non-ints
+ // dartbug.com/14605
+ if (index is num && index == index.toInt()) {
+ _checkIndex(index);
+ }
+ return super[index] as E;
+ }
+
+ void operator []=(Object index, value) {
+ // TODO(justinfagnani): fix the semantics for non-ints
+ // dartbug.com/14605
+ if (index is num && index == index.toInt()) {
+ _checkIndex(index);
+ }
+ super[index] = value;
+ }
+
+ int get length {
+ // Check the length honours the List contract.
+ var len = JS('', '#.length', _jsObject);
+ // JavaScript arrays have lengths which are unsigned 32-bit integers.
+ if (JS<bool>(
+ '!', 'typeof # === "number" && (# >>> 0) === #', len, len, len)) {
+ return JS<int>('!', '#', len);
+ }
+ throw StateError('Bad JsArray length');
+ }
+
+ void set length(int length) {
+ super['length'] = length;
+ }
+
+ // Methods overridden for better performance
+
+ void add(E value) {
+ callMethod('push', [value]);
+ }
+
+ void addAll(Iterable<E> iterable) {
+ var list = (JS<bool>('!', '# instanceof Array', iterable))
+ ? iterable
+ : List.from(iterable);
+ callMethod('push', list);
+ }
+
+ void insert(int index, E element) {
+ _checkInsertIndex(index);
+ callMethod('splice', [index, 0, element]);
+ }
+
+ E removeAt(int index) {
+ _checkIndex(index);
+ return callMethod('splice', [index, 1])[0] as E;
+ }
+
+ E removeLast() {
+ if (length == 0) throw RangeError(-1);
+ return callMethod('pop') as E;
+ }
+
+ void removeRange(int start, int end) {
+ _checkRange(start, end, length);
+ callMethod('splice', [start, end - start]);
+ }
+
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+ _checkRange(start, end, this.length);
+ int length = end - start;
+ if (length == 0) return;
+ if (skipCount < 0) throw ArgumentError(skipCount);
+ var args = <Object>[start, length]
+ ..addAll(iterable.skip(skipCount).take(length));
+ callMethod('splice', args);
+ }
+
+ void sort([int compare(E a, E b)]) {
+ // Note: arr.sort(null) is a type error in FF
+ callMethod('sort', compare == null ? [] : [compare]);
+ }
+}
+
+// Cross frame objects should not be considered browser types.
+// We include the instanceof Object test to filter out cross frame objects
+// on FireFox. Surprisingly on FireFox the instanceof Window test succeeds for
+// cross frame windows while the instanceof Object test fails.
+bool _isBrowserType(o) => JS(
+ 'bool',
+ '# instanceof Object && ('
+ '# instanceof Blob || '
+ '# instanceof Event || '
+ '(window.KeyRange && # instanceof KeyRange) || '
+ '(window.IDBKeyRange && # instanceof IDBKeyRange) || '
+ '# instanceof ImageData || '
+ '# instanceof Node || '
+ // Int8Array.__proto__ is TypedArray.
+ '(window.Int8Array && # instanceof Int8Array.__proto__) || '
+ '# instanceof Window)',
+ o,
+ o,
+ o,
+ o,
+ o,
+ o,
+ o,
+ o,
+ o);
+
+class _DartObject {
+ final _dartObj;
+ _DartObject(this._dartObj);
+}
+
+dynamic _convertToJS(dynamic o) {
+ if (o == null || o is String || o is num || o is bool || _isBrowserType(o)) {
+ return o;
+ } else if (o is DateTime) {
+ return Primitives.lazyAsJsDate(o);
+ } else if (o is JsObject) {
+ return o._jsObject;
+ } else if (o is Function) {
+ return _putIfAbsent(_jsProxies, o, _wrapDartFunction);
+ } else {
+ // TODO(jmesserly): for now, we wrap other objects, to keep compatibility
+ // with the original dart:js behavior.
+ return _putIfAbsent(_jsProxies, o, (o) => _DartObject(o));
+ }
+}
+
+dynamic _wrapDartFunction(f) {
+ var wrapper = JS(
+ '',
+ 'function(/*...arguments*/) {'
+ ' let args = Array.prototype.map.call(arguments, #);'
+ ' return #(#(...args));'
+ '}',
+ _convertToDart,
+ _convertToJS,
+ f);
+ JS('', '#.set(#, #)', _dartProxies, wrapper, f);
+
+ return wrapper;
+}
+
+// converts a Dart object to a reference to a native JS object
+// which might be a DartObject JS->Dart proxy
+Object _convertToDart(o) {
+ if (o == null || o is String || o is num || o is bool || _isBrowserType(o)) {
+ return o;
+ } else if (JS('!', '# instanceof Date', o)) {
+ num ms = JS('!', '#.getTime()', o);
+ return DateTime.fromMillisecondsSinceEpoch(ms);
+ } else if (o is _DartObject &&
+ !identical(dart.getReifiedType(o), dart.jsobject)) {
+ return o._dartObj;
+ } else {
+ return _wrapToDart(o);
+ }
+}
+
+Object _wrapToDart(o) => _putIfAbsent(_dartProxies, o, _wrapToDartHelper);
+
+Object _wrapToDartHelper(o) {
+ if (JS<bool>('!', 'typeof # == "function"', o)) {
+ return JsFunction._fromJs(o);
+ }
+ if (JS<bool>('!', '# instanceof Array', o)) {
+ return JsArray._fromJs(o);
+ }
+ return JsObject._fromJs(o);
+}
+
+final _dartProxies = JS('', 'new WeakMap()');
+final _jsProxies = JS('', 'new WeakMap()');
+
+Object _putIfAbsent(weakMap, o, getValue(o)) {
+ var value = JS('', '#.get(#)', weakMap, o);
+ if (value == null) {
+ value = getValue(o);
+ JS('', '#.set(#, #)', weakMap, o, value);
+ }
+ return value;
+}
+
+Expando<Function> _interopExpando = Expando<Function>();
+
+/// Returns a wrapper around function [f] that can be called from JavaScript
+/// using the package:js Dart-JavaScript interop.
+///
+/// For performance reasons in Dart2Js, by default Dart functions cannot be
+/// passed directly to JavaScript unless this method is called to create
+/// a Function compatible with both Dart and JavaScript.
+/// Calling this method repeatedly on a function will return the same function.
+/// The [Function] returned by this method can be used from both Dart and
+/// JavaScript. We may remove the need to call this method completely in the
+/// future if Dart2Js is refactored so that its function calling conventions
+/// are more compatible with JavaScript.
+F allowInterop<F extends Function>(F f) {
+ var ret = _interopExpando[f];
+ if (ret == null) {
+ ret = JS(
+ '',
+ 'function (...args) {'
+ ' return #(#, args);'
+ '}',
+ dart.dcall,
+ f);
+ _interopExpando[f] = ret;
+ }
+ return ret;
+}
+
+Expando<Function> _interopCaptureThisExpando = Expando<Function>();
+
+/// Returns a [Function] that when called from JavaScript captures its 'this'
+/// binding and calls [f] with the value of this passed as the first argument.
+/// When called from Dart, [null] will be passed as the first argument.
+///
+/// See the documentation for [allowInterop]. This method should only be used
+/// with package:js Dart-JavaScript interop.
+Function allowInteropCaptureThis(Function f) {
+ var ret = _interopCaptureThisExpando[f];
+ if (ret == null) {
+ ret = JS(
+ '',
+ 'function(...arguments) {'
+ ' let args = [this];'
+ ' args.push.apply(args, arguments);'
+ ' return #(#, args);'
+ '}',
+ dart.dcall,
+ f);
+ _interopCaptureThisExpando[f] = ret;
+ }
+ return ret;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart
new file mode 100644
index 0000000..4b9fdb0
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart
@@ -0,0 +1,126 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Utility methods to efficiently manipulate typed JSInterop objects in cases
+/// where the name to call is not known at runtime. You should only use these
+/// methods when the same effect cannot be achieved with @JS annotations.
+/// These methods would be extension methods on JSObject if Dart supported
+/// extension methods.
+library dart.js_util;
+
+import 'dart:_foreign_helper' show JS;
+import 'dart:collection' show HashMap;
+
+/// WARNING: performance of this method is much worse than other uitil
+/// methods in this library. Only use this method as a last resort.
+///
+/// Recursively converts a JSON-like collection of Dart objects to a
+/// collection of JavaScript objects and returns a [JsObject] proxy to it.
+///
+/// [object] must be a [Map] or [Iterable], the contents of which are also
+/// converted. Maps and Iterables are copied to a new JavaScript object.
+/// Primitives and other transferrable values are directly converted to their
+/// JavaScript type, and all other objects are proxied.
+jsify(object) {
+ if ((object is! Map) && (object is! Iterable)) {
+ throw ArgumentError("object must be a Map or Iterable");
+ }
+ return _convertDataTree(object);
+}
+
+_convertDataTree(data) {
+ var _convertedObjects = HashMap.identity();
+
+ _convert(o) {
+ if (_convertedObjects.containsKey(o)) {
+ return _convertedObjects[o];
+ }
+ if (o is Map) {
+ final convertedMap = JS('=Object', '{}');
+ _convertedObjects[o] = convertedMap;
+ for (var key in o.keys) {
+ JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key]));
+ }
+ return convertedMap;
+ } else if (o is Iterable) {
+ var convertedList = [];
+ _convertedObjects[o] = convertedList;
+ convertedList.addAll(o.map(_convert));
+ return convertedList;
+ } else {
+ return o;
+ }
+ }
+
+ return _convert(data);
+}
+
+newObject() => JS('=Object', '{}');
+
+hasProperty(o, name) => JS<bool>('!', '# in #', name, o);
+getProperty(o, name) => JS('Object', '#[#]', o, name);
+setProperty(o, name, value) => JS('', '#[#]=#', o, name, value);
+
+callMethod(o, String method, List args) =>
+ JS('Object', '#[#].apply(#, #)', o, method, o, args);
+
+instanceof(o, Function type) => JS<bool>('!', '# instanceof #', o, type);
+callConstructor(Function constr, List arguments) {
+ if (arguments == null) {
+ return JS('Object', 'new #()', constr);
+ }
+
+ if (JS<bool>('!', '# instanceof Array', arguments)) {
+ int argumentCount = JS('!', '#.length', arguments);
+ switch (argumentCount) {
+ case 0:
+ return JS('Object', 'new #()', constr);
+
+ case 1:
+ var arg0 = JS('', '#[0]', arguments);
+ return JS('Object', 'new #(#)', constr, arg0);
+
+ case 2:
+ var arg0 = JS('', '#[0]', arguments);
+ var arg1 = JS('', '#[1]', arguments);
+ return JS('Object', 'new #(#, #)', constr, arg0, arg1);
+
+ case 3:
+ var arg0 = JS('', '#[0]', arguments);
+ var arg1 = JS('', '#[1]', arguments);
+ var arg2 = JS('', '#[2]', arguments);
+ return JS('Object', 'new #(#, #, #)', constr, arg0, arg1, arg2);
+
+ case 4:
+ var arg0 = JS('', '#[0]', arguments);
+ var arg1 = JS('', '#[1]', arguments);
+ var arg2 = JS('', '#[2]', arguments);
+ var arg3 = JS('', '#[3]', arguments);
+ return JS(
+ 'Object', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg3);
+ }
+ }
+
+ // The following code solves the problem of invoking a JavaScript
+ // constructor with an unknown number arguments.
+ // First bind the constructor to the argument list using bind.apply().
+ // The first argument to bind() is the binding of 't', so add 'null' to
+ // the arguments list passed to apply().
+ // After that, use the JavaScript 'new' operator which overrides any binding
+ // of 'this' with the new instance.
+ var args = <dynamic>[null]..addAll(arguments);
+ var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args);
+ // Without this line, calling factoryFunction as a constructor throws
+ JS<String>('!', 'String(#)', factoryFunction);
+ // This could return an UnknownJavaScriptObject, or a native
+ // object for which there is an interceptor
+ return JS('Object', 'new #()', factoryFunction);
+
+ // TODO(sra): Investigate:
+ //
+ // var jsObj = JS('', 'Object.create(#.prototype)', constr);
+ // JS('', '#.apply(#, #)', constr, jsObj,
+ // []..addAll(arguments.map(_convertToJS)));
+ // return _wrapToDart(jsObj);
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/libraries.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/libraries.dart
new file mode 100644
index 0000000..d5cffa2
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/libraries.dart
@@ -0,0 +1,310 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library libraries;
+
+/**
+ * A bit flag used by [LibraryInfo] indicating that a library is used by dart2js
+ */
+const int DART2JS_PLATFORM = 1;
+
+/**
+ * A bit flag used by [LibraryInfo] indicating that a library is used by the VM
+ */
+const int VM_PLATFORM = 2;
+
+/// The contexts that a library can be used from.
+enum Category {
+ /// Indicates that a library can be used in a browser context.
+ client,
+
+ /// Indicates that a library can be used in a command line context.
+ server,
+
+ /// Indicates that a library can be used from embedded devices.
+ embedded
+}
+
+Category parseCategory(String name) {
+ switch (name) {
+ case "Client":
+ return Category.client;
+ case "Server":
+ return Category.server;
+ case "Embedded":
+ return Category.embedded;
+ }
+ return null;
+}
+
+/// Mapping of "dart:" library name (e.g. "core") to information about that
+/// library.
+const Map<String, LibraryInfo> libraries = const {
+ "async": const LibraryInfo("async/async.dart",
+ categories: "Client,Server",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/async_patch.dart"),
+ "collection": const LibraryInfo("collection/collection.dart",
+ categories: "Client,Server,Embedded",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/collection_patch.dart"),
+ "convert": const LibraryInfo("convert/convert.dart",
+ categories: "Client,Server",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/convert_patch.dart"),
+ "core": const LibraryInfo("core/core.dart",
+ categories: "Client,Server,Embedded",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/core_patch.dart"),
+ "developer": const LibraryInfo("developer/developer.dart",
+ categories: "Client,Server,Embedded",
+ maturity: Maturity.UNSTABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/developer_patch.dart"),
+ "html": const LibraryInfo("html/dart2js/html_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ platforms: DART2JS_PLATFORM),
+ "html_common": const LibraryInfo("html/html_common/html_common.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ dart2jsPath: "html/html_common/html_common_dart2js.dart",
+ documented: false,
+ implementation: true),
+ "indexed_db": const LibraryInfo("indexed_db/dart2js/indexed_db_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ platforms: DART2JS_PLATFORM),
+ "_http":
+ const LibraryInfo("_http/http.dart", categories: "", documented: false),
+ "io": const LibraryInfo("io/io.dart",
+ categories: "Server",
+ dart2jsPatchPath: "_internal/js_runtime/lib/io_patch.dart"),
+ "isolate": const LibraryInfo("isolate/isolate.dart",
+ categories: "Client,Server",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/isolate_patch.dart"),
+ "js": const LibraryInfo("js/dart2js/js_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.STABLE,
+ platforms: DART2JS_PLATFORM),
+ "js_util": const LibraryInfo("js_util/dart2js/js_util_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.STABLE,
+ platforms: DART2JS_PLATFORM),
+ "math": const LibraryInfo("math/math.dart",
+ categories: "Client,Server,Embedded",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/math_patch.dart"),
+ "mirrors": const LibraryInfo("mirrors/mirrors.dart",
+ categories: "Client,Server",
+ maturity: Maturity.UNSTABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/mirrors_patch.dart"),
+ "nativewrappers": const LibraryInfo("html/dartium/nativewrappers.dart",
+ categories: "Client",
+ implementation: true,
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "typed_data": const LibraryInfo("typed_data/typed_data.dart",
+ categories: "Client,Server,Embedded",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/typed_data_patch.dart"),
+ "_native_typed_data": const LibraryInfo(
+ "_internal/js_runtime/lib/native_typed_data.dart",
+ categories: "",
+ implementation: true,
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "cli": const LibraryInfo("cli/cli.dart",
+ categories: "Server",
+ dart2jsPatchPath: "_internal/js_runtime/lib/cli_patch.dart"),
+ "svg": const LibraryInfo("svg/dart2js/svg_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ platforms: DART2JS_PLATFORM),
+ "web_audio": const LibraryInfo("web_audio/dart2js/web_audio_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ platforms: DART2JS_PLATFORM),
+ "web_gl": const LibraryInfo("web_gl/dart2js/web_gl_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ platforms: DART2JS_PLATFORM),
+ "web_sql": const LibraryInfo("web_sql/dart2js/web_sql_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ platforms: DART2JS_PLATFORM),
+ "_internal": const LibraryInfo("internal/internal.dart",
+ categories: "",
+ documented: false,
+ dart2jsPatchPath: "_internal/js_runtime/lib/internal_patch.dart"),
+ "_js_helper": const LibraryInfo("_internal/js_runtime/lib/js_helper.dart",
+ categories: "", documented: false, platforms: DART2JS_PLATFORM),
+ "_interceptors": const LibraryInfo(
+ "_internal/js_runtime/lib/interceptors.dart",
+ categories: "",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "_foreign_helper": const LibraryInfo(
+ "_internal/js_runtime/lib/foreign_helper.dart",
+ categories: "",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "_isolate_helper": const LibraryInfo(
+ "_internal/js_runtime/lib/isolate_helper.dart",
+ categories: "",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "_js_mirrors": const LibraryInfo("_internal/js_runtime/lib/js_mirrors.dart",
+ categories: "", documented: false, platforms: DART2JS_PLATFORM),
+ "_js_primitives": const LibraryInfo(
+ "_internal/js_runtime/lib/js_primitives.dart",
+ categories: "",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "_metadata": const LibraryInfo("html/html_common/metadata.dart",
+ categories: "", documented: false, platforms: DART2JS_PLATFORM),
+ "_debugger": const LibraryInfo("_internal/js_runtime/lib/debugger.dart",
+ category: "", documented: false, platforms: DART2JS_PLATFORM),
+ "_runtime": const LibraryInfo(
+ "_internal/js_runtime/lib/ddc_runtime/runtime.dart",
+ category: "",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+};
+
+/**
+ * Information about a "dart:" library.
+ */
+class LibraryInfo {
+ /**
+ * Path to the library's *.dart file relative to this file.
+ */
+ final String path;
+
+ /**
+ * The categories in which the library can be used encoded as a
+ * comma-separated String.
+ */
+ final String _categories;
+
+ /**
+ * Path to the dart2js library's *.dart file relative to this file
+ * or null if dart2js uses the common library path defined above.
+ * Access using the [#getDart2JsPath()] method.
+ */
+ final String dart2jsPath;
+
+ /**
+ * Path to the dart2js library's patch file relative to this file
+ * or null if no dart2js patch file associated with this library.
+ * Access using the [#getDart2JsPatchPath()] method.
+ */
+ final String dart2jsPatchPath;
+
+ /**
+ * True if this library is documented and should be shown to the user.
+ */
+ final bool documented;
+
+ /**
+ * Bit flags indicating which platforms consume this library.
+ * See [DART2JS_LIBRARY] and [VM_LIBRARY].
+ */
+ final int platforms;
+
+ /**
+ * True if the library contains implementation details for another library.
+ * The implication is that these libraries are less commonly used
+ * and that tools like Dart Editor should not show these libraries
+ * in a list of all libraries unless the user specifically asks the tool to
+ * do so.
+ */
+ final bool implementation;
+
+ /**
+ * States the current maturity of this library.
+ */
+ final Maturity maturity;
+
+ const LibraryInfo(this.path,
+ {String categories: "",
+ this.dart2jsPath,
+ this.dart2jsPatchPath,
+ this.implementation: false,
+ this.documented: true,
+ this.maturity: Maturity.UNSPECIFIED,
+ this.platforms: DART2JS_PLATFORM | VM_PLATFORM})
+ : _categories = categories;
+
+ bool get isDart2jsLibrary => (platforms & DART2JS_PLATFORM) != 0;
+ bool get isVmLibrary => (platforms & VM_PLATFORM) != 0;
+
+ /**
+ * The categories in which the library can be used.
+ *
+ * If no categories are specified, the library is internal and can not be
+ * loaded by user code.
+ */
+ List<Category> get categories {
+ // `"".split(,)` returns [""] not [], so we handle that case separately.
+ if (_categories == "") return const <Category>[];
+ return _categories.split(",").map(parseCategory).toList();
+ }
+
+ bool get isInternal => categories.isEmpty;
+
+ /// The original "categories" String that was passed to the constructor.
+ ///
+ /// Can be used to construct a slightly modified copy of this LibraryInfo.
+ String get categoriesString {
+ return _categories;
+ }
+}
+
+/**
+ * Abstraction to capture the maturity of a library.
+ */
+class Maturity {
+ final int level;
+ final String name;
+ final String description;
+
+ const Maturity(this.level, this.name, this.description);
+
+ String toString() => "$name: $level\n$description\n";
+
+ static const Maturity DEPRECATED = const Maturity(0, "Deprecated",
+ "This library will be remove before next major release.");
+
+ static const Maturity EXPERIMENTAL = const Maturity(
+ 1,
+ "Experimental",
+ "This library is experimental and will likely change or be removed\n"
+ "in future versions.");
+
+ static const Maturity UNSTABLE = const Maturity(
+ 2,
+ "Unstable",
+ "This library is in still changing and have not yet endured\n"
+ "sufficient real-world testing.\n"
+ "Backwards-compatibility is NOT guaranteed.");
+
+ static const Maturity WEB_STABLE = const Maturity(
+ 3,
+ "Web Stable",
+ "This library is tracking the DOM evolution as defined by WC3.\n"
+ "Backwards-compatibility is NOT guaranteed.");
+
+ static const Maturity STABLE = const Maturity(
+ 4,
+ "Stable",
+ "The library is stable. API backwards-compatibility is guaranteed.\n"
+ "However implementation details might change.");
+
+ static const Maturity LOCKED = const Maturity(5, "Locked",
+ "This library will not change except when serious bugs are encountered.");
+
+ static const Maturity UNSPECIFIED = const Maturity(-1, "Unspecified",
+ "The maturity for this library has not been specified.");
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/async_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/async_patch.dart
new file mode 100644
index 0000000..894aef4
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/async_patch.dart
@@ -0,0 +1,472 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for the dart:async library.
+
+import 'dart:_js_helper' show notNull, patch, ReifyFunctionTypes;
+import 'dart:_isolate_helper' show TimerImpl;
+import 'dart:_foreign_helper' show JS, JSExportName;
+import 'dart:_runtime' as dart;
+
+/// This function adapts ES6 generators to implement Dart's async/await.
+///
+/// It's designed to interact with Dart's Future and follow Dart async/await
+/// semantics.
+///
+/// See https://github.com/dart-lang/sdk/issues/27315 for ideas on reconciling
+/// Dart's Future and ES6 Promise. At that point we should use native JS
+/// async/await.
+///
+/// Inspired by `co`: https://github.com/tj/co/blob/master/index.js, which is a
+/// stepping stone for ES async/await.
+@JSExportName('async')
+@ReifyFunctionTypes(false)
+_async<T>(Function() initGenerator) {
+ var iter;
+ Object Function(Object) onValue;
+ Object Function(Object, StackTrace) onError;
+
+ onAwait(Object value) {
+ _Future f;
+ if (value is _Future) {
+ f = value;
+ } else if (value is Future) {
+ f = _Future();
+ _Future._chainForeignFuture(value, f);
+ } else {
+ f = _Future.value(value);
+ }
+ f = JS('', '#', f._thenAwait(onValue, onError));
+ return f;
+ }
+
+ onValue = (value) {
+ var iteratorResult = JS('', '#.next(#)', iter, value);
+ value = JS('', '#.value', iteratorResult);
+ return JS<bool>('!', '#.done', iteratorResult) ? value : onAwait(value);
+ };
+
+ // If the awaited Future throws, we want to convert this to an exception
+ // thrown from the `yield` point, as if it was thrown there.
+ //
+ // If the exception is not caught inside `gen`, it will emerge here, which
+ // will send it to anyone listening on this async function's Future<T>.
+ //
+ // In essence, we are giving the code inside the generator a chance to
+ // use try-catch-finally.
+ onError = (value, stackTrace) {
+ var iteratorResult = JS(
+ '', '#.throw(#)', iter, dart.createErrorWithStack(value, stackTrace));
+ value = JS('', '#.value', iteratorResult);
+ return JS<bool>('!', '#.done', iteratorResult) ? value : onAwait(value);
+ };
+
+ var zone = Zone.current;
+ if (!identical(zone, _rootZone)) {
+ onValue = zone.registerUnaryCallback(onValue);
+ onError = zone.registerBinaryCallback(onError);
+ }
+
+ var asyncFuture = _Future<T>();
+
+ // This will be set to true once we've yielded to the event loop.
+ //
+ // Before we've done that, we need to complete the future asynchronously to
+ // match dart2js/VM. See https://github.com/dart-lang/sdk/issues/33330
+ //
+ // Once we've yielded to the event loop we can complete synchronously.
+ // Other implementations call this `isSync` to indicate that.
+ bool isRunningAsEvent = false;
+ runBody() {
+ try {
+ iter = JS('', '#[Symbol.iterator]()', initGenerator());
+ var iteratorValue = JS('', '#.next(null)', iter);
+ var value = JS('', '#.value', iteratorValue);
+ if (JS<bool>('!', '#.done', iteratorValue)) {
+ // TODO(jmesserly): this is a workaround for ignored cast failures.
+ // Remove it once we've fixed those. We should be able to call:
+ //
+ // if (isRunningAsEvent) {
+ // asyncFuture._complete(value);
+ // } else {
+ // asyncFuture._asyncComplete(value);
+ // }
+ //
+ // But if the user code returns `Future<dynamic>` instead of
+ // `Future<T>`, that function won't recognize it as a future and will
+ // instead treat it as a completed value.
+ if (value is Future) {
+ if (value is _Future) {
+ _Future._chainCoreFuture(value, asyncFuture);
+ } else {
+ _Future._chainForeignFuture(value, asyncFuture);
+ }
+ } else if (isRunningAsEvent) {
+ asyncFuture._completeWithValue(JS('', '#', value));
+ } else {
+ asyncFuture._asyncComplete(JS('', '#', value));
+ }
+ } else {
+ _Future._chainCoreFuture(onAwait(value), asyncFuture);
+ }
+ } catch (e, s) {
+ if (isRunningAsEvent) {
+ _completeWithErrorCallback(asyncFuture, e, s);
+ } else {
+ _asyncCompleteWithErrorCallback(asyncFuture, e, s);
+ }
+ }
+ }
+
+ if (dart.startAsyncSynchronously) {
+ runBody();
+ isRunningAsEvent = true;
+ } else {
+ isRunningAsEvent = true;
+ scheduleMicrotask(runBody);
+ }
+ return asyncFuture;
+}
+
+@patch
+class _AsyncRun {
+ @patch
+ static void _scheduleImmediate(void Function() callback) {
+ _scheduleImmediateClosure(callback);
+ }
+
+ // Lazily initialized.
+ static final _scheduleImmediateClosure = _initializeScheduleImmediate();
+
+ static void Function(void Function()) _initializeScheduleImmediate() {
+ // d8 support, see preambles/d8.js for the definiton of `scheduleImmediate`.
+ //
+ // TODO(jmesserly): do we need this? It's only for our d8 stack trace test.
+ if (JS('', '#.scheduleImmediate', dart.global_) != null) {
+ return _scheduleImmediateJSOverride;
+ }
+ return _scheduleImmediateWithPromise;
+ }
+
+ @ReifyFunctionTypes(false)
+ static void _scheduleImmediateJSOverride(void Function() callback) {
+ dart.addAsyncCallback();
+ JS('void', '#.scheduleImmediate(#)', dart.global_, () {
+ dart.removeAsyncCallback();
+ callback();
+ });
+ }
+
+ @ReifyFunctionTypes(false)
+ static Object _scheduleImmediateWithPromise(void Function() callback) {
+ dart.addAsyncCallback();
+ JS('', '#.Promise.resolve(null).then(#)', dart.global_, () {
+ dart.removeAsyncCallback();
+ callback();
+ });
+ }
+}
+
+@patch
+class DeferredLibrary {
+ @patch
+ Future<Null> load() {
+ throw 'DeferredLibrary not supported. '
+ 'please use the `import "lib.dart" deferred as lib` syntax.';
+ }
+}
+
+@patch
+class Timer {
+ @patch
+ static Timer _createTimer(Duration duration, void callback()) {
+ int milliseconds = duration.inMilliseconds;
+ if (milliseconds < 0) milliseconds = 0;
+ return TimerImpl(milliseconds, callback);
+ }
+
+ @patch
+ static Timer _createPeriodicTimer(
+ Duration duration, void callback(Timer timer)) {
+ int milliseconds = duration.inMilliseconds;
+ if (milliseconds < 0) milliseconds = 0;
+ return TimerImpl.periodic(milliseconds, callback);
+ }
+}
+
+@patch
+void _rethrow(Object error, StackTrace stackTrace) {
+ JS('', 'throw #', dart.createErrorWithStack(error, stackTrace));
+}
+
+/// Used by the compiler to implement `async*` functions.
+///
+/// This is inspired by _AsyncStarStreamController in dart-lang/sdk's
+/// runtime/lib/core_patch.dart
+///
+/// Given input like:
+///
+/// foo() async* {
+/// yield 1;
+/// yield* bar();
+/// print(await baz());
+/// }
+///
+/// This compiles to:
+///
+/// function foo() {
+/// return new (AsyncStarImplOfT()).new(function*(stream) {
+/// if (stream.add(1)) return;
+/// yield;
+/// if (stream.addStream(bar()) return;
+/// yield;
+/// print(yield baz());
+/// });
+/// }
+///
+class _AsyncStarImpl<T> {
+ StreamController<T> controller;
+ Object Function(_AsyncStarImpl<T>) initGenerator;
+ @notNull
+ bool isSuspendedAtYieldStar = false;
+ @notNull
+ bool onListenReceived = false;
+ @notNull
+ bool isScheduled = false;
+ @notNull
+ bool isSuspendedAtYield = false;
+
+ /// Whether we're suspended at an `await`.
+ @notNull
+ bool isSuspendedAtAwait = false;
+
+ Completer cancellationCompleter;
+ Object jsIterator;
+
+ Null Function(Object, StackTrace) _handleErrorCallback;
+ void Function([Object]) _runBodyCallback;
+
+ _AsyncStarImpl(this.initGenerator) {
+ controller = StreamController(
+ onListen: JS('!', 'this.onListen.bind(this)'),
+ onResume: JS('!', 'this.onResume.bind(this)'),
+ onCancel: JS('!', 'this.onCancel.bind(this)'));
+ jsIterator = JS('!', '#[Symbol.iterator]()', initGenerator(this));
+ }
+
+ /// The stream produced by this `async*` function.
+ Stream<T> get stream => controller.stream;
+
+ /// Returns the callback used for error handling.
+ ///
+ /// This callback throws the error back into the user code, at the appropriate
+ /// location (e.g. `await` `yield` or `yield*`). This gives user code a chance
+ /// to handle it try-catch. If they do not handle, the error gets routed to
+ /// the [stream] as an error via [addError].
+ ///
+ /// As a performance optimization, this callback is only bound once to the
+ /// current [Zone]. This works because a single subscription stream should
+ /// always be running in its original zone. An `async*` method will always
+ /// save/restore the zone that was active when `listen()` was first called,
+ /// similar to a stream. This follows from section 16.14 of the Dart 4th
+ /// edition spec:
+ ///
+ /// > If `f` is marked `async*` (9), then a fresh instance `s` implementing
+ /// > the built-in class `Stream` is associated with the invocation and
+ /// > immediately returned. When `s` is listened to, execution of the body of
+ /// > `f` will begin.
+ ///
+ Null Function(Object, StackTrace) get handleError {
+ if (_handleErrorCallback == null) {
+ _handleErrorCallback = (error, StackTrace stackTrace) {
+ try {
+ JS('', '#.throw(#)', jsIterator,
+ dart.createErrorWithStack(error, stackTrace));
+ } catch (e, newStack) {
+ // The generator didn't catch the error, or it threw a new one.
+ // Make sure to propagate the new error.
+ addError(e, newStack);
+ }
+ };
+ var zone = Zone.current;
+ if (!identical(zone, Zone.root)) {
+ _handleErrorCallback = zone.bindBinaryCallback(_handleErrorCallback);
+ }
+ }
+ return _handleErrorCallback;
+ }
+
+ void scheduleGenerator() {
+ // TODO(jmesserly): is this isPaused check in the right place? Assuming the
+ // async* Stream yields, then is paused (by other code), the body will
+ // already be scheduled. This will cause at least one more iteration to
+ // run (adding another data item to the Stream) before actually pausing.
+ // It could be fixed by moving the `isPaused` check inside `runBody`.
+ if (isScheduled ||
+ controller.isPaused ||
+ isSuspendedAtYieldStar ||
+ isSuspendedAtAwait) {
+ return;
+ }
+ isScheduled = true;
+ // Capture the current zone. See comment on [handleError] for more
+ // information about this optimization.
+ var zone = Zone.current;
+ if (_runBodyCallback == null) {
+ _runBodyCallback = JS('!', '#.bind(this)', runBody);
+ if (!identical(zone, Zone.root)) {
+ var registered = zone.registerUnaryCallback(_runBodyCallback);
+ _runBodyCallback = ([arg]) => zone.runUnaryGuarded(registered, arg);
+ }
+ }
+ zone.scheduleMicrotask(_runBodyCallback);
+ }
+
+ void runBody(awaitValue) {
+ isScheduled = false;
+ isSuspendedAtYield = false;
+ isSuspendedAtAwait = false;
+
+ Object iterResult;
+ try {
+ iterResult = JS('', '#.next(#)', jsIterator, awaitValue);
+ } catch (e, s) {
+ addError(e, s);
+ return null;
+ }
+
+ if (JS('!', '#.done', iterResult)) {
+ close();
+ return null;
+ }
+
+ // If we're suspended at a yield/yield*, we're done for now.
+ if (isSuspendedAtYield || isSuspendedAtYieldStar) return null;
+
+ // Handle `await`: if we get a value passed to `yield` it means we are
+ // waiting on this Future. Make sure to prevent scheduling, and pass the
+ // value back as the result of the `yield`.
+ //
+ // TODO(jmesserly): is the timing here correct? The assumption here is
+ // that we should schedule `await` in `async*` the same as in `async`.
+ isSuspendedAtAwait = true;
+ FutureOr<Object> value = JS('', '#.value', iterResult);
+
+ // TODO(jmesserly): this logic was copied from `async` function impl.
+ _Future f;
+ if (value is _Future) {
+ f = value;
+ } else if (value is Future) {
+ f = _Future();
+ _Future._chainForeignFuture(value, f);
+ } else {
+ f = _Future.value(value);
+ }
+ f._thenAwait(_runBodyCallback, handleError);
+ }
+
+ /// Adds element to [stream] and returns true if the caller should terminate
+ /// execution of the generator.
+ ///
+ /// This is called from generated code like this:
+ ///
+ /// if (controller.add(1)) return;
+ /// yield;
+ //
+ // TODO(hausner): Per spec, the generator should be suspended before exiting
+ // when the stream is closed. We could add a getter like this:
+ //
+ // get isCancelled => controller.hasListener;
+ //
+ // The generator would translate a 'yield e' statement to
+ //
+ // controller.add(1);
+ // suspend; // this is `yield` in JS.
+ // if (controller.isCancelled) return;
+ bool add(T event) {
+ if (!onListenReceived) _fatal("yield before stream is listened to");
+ if (isSuspendedAtYield) _fatal("unexpected yield");
+ // If stream is cancelled, tell caller to exit the async generator.
+ if (!controller.hasListener) {
+ return true;
+ }
+ controller.add(event);
+ scheduleGenerator();
+ isSuspendedAtYield = true;
+ return false;
+ }
+
+ /// Adds the elements of [stream] into this [controller]'s stream, and returns
+ /// true if the caller should terminate execution of the generator.
+ ///
+ /// The generator will be scheduled again when all of the elements of the
+ /// added stream have been consumed.
+ bool addStream(Stream<T> stream) {
+ if (!onListenReceived) _fatal("yield* before stream is listened to");
+ // If stream is cancelled, tell caller to exit the async generator.
+ if (!controller.hasListener) return true;
+ isSuspendedAtYieldStar = true;
+ var whenDoneAdding = controller.addStream(stream, cancelOnError: false);
+ whenDoneAdding.then((_) {
+ isSuspendedAtYieldStar = false;
+ scheduleGenerator();
+ if (!isScheduled) isSuspendedAtYield = true;
+ }, onError: handleError);
+ return false;
+ }
+
+ void addError(Object error, StackTrace stackTrace) {
+ if (cancellationCompleter != null && !cancellationCompleter.isCompleted) {
+ // If the stream has been cancelled, complete the cancellation future
+ // with the error.
+ cancellationCompleter.completeError(error, stackTrace);
+ } else if (controller.hasListener) {
+ controller.addError(error, stackTrace);
+ }
+ // No need to schedule the generator body here. This code is only
+ // called from the catch clause of the implicit try-catch-finally
+ // around the generator body. That is, we are on the error path out
+ // of the generator and do not need to run the generator again.
+ close();
+ }
+
+ void close() {
+ if (cancellationCompleter != null && !cancellationCompleter.isCompleted) {
+ // If the stream has been cancelled, complete the cancellation future
+ // with the error.
+ cancellationCompleter.complete();
+ }
+ controller.close();
+ }
+
+ onListen() {
+ assert(!onListenReceived);
+ onListenReceived = true;
+ scheduleGenerator();
+ }
+
+ onResume() {
+ if (isSuspendedAtYield) {
+ scheduleGenerator();
+ }
+ }
+
+ onCancel() {
+ if (controller.isClosed) {
+ return null;
+ }
+ if (cancellationCompleter == null) {
+ cancellationCompleter = Completer();
+ // Only resume the generator if it is suspended at a yield.
+ // Cancellation does not affect an async generator that is
+ // suspended at an await.
+ if (isSuspendedAtYield) {
+ scheduleGenerator();
+ }
+ }
+ return cancellationCompleter.future;
+ }
+
+ _fatal(String message) => throw StateError(message);
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/cli_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/cli_patch.dart
new file mode 100644
index 0000000..b1c3841
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/cli_patch.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:_js_helper' show patch;
+
+@patch
+void _waitForEvent(int timeoutMillis) {
+ throw UnsupportedError("waitForEvent");
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/collection_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/collection_patch.dart
new file mode 100644
index 0000000..daa3bf8
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/collection_patch.dart
@@ -0,0 +1,602 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:collection classes.
+import 'dart:_foreign_helper' show JS, JSExportName;
+import 'dart:_runtime' as dart;
+import 'dart:_interceptors' show JSArray;
+import 'dart:_js_helper'
+ show
+ NoInline,
+ NoSideEffects,
+ NoThrows,
+ patch,
+ LinkedMap,
+ IdentityMap,
+ CustomHashMap,
+ CustomKeyHashMap,
+ DartIterator,
+ notNull,
+ putLinkedMapKey;
+
+@patch
+class HashMap<K, V> {
+ @patch
+ factory HashMap(
+ {bool equals(K key1, K key2),
+ int hashCode(K key),
+ bool isValidKey(Object potentialKey)}) {
+ if (isValidKey == null) {
+ if (hashCode == null) {
+ if (equals == null) {
+ if (identical(K, String) || identical(K, int)) {
+ return IdentityMap<K, V>();
+ }
+ return LinkedMap<K, V>();
+ }
+ hashCode = dart.hashCode;
+ } else if (identical(identityHashCode, hashCode) &&
+ identical(identical, equals)) {
+ return IdentityMap<K, V>();
+ }
+ return CustomHashMap<K, V>(equals ?? dart.equals, hashCode);
+ }
+ return CustomKeyHashMap<K, V>(
+ equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
+ }
+
+ @patch
+ factory HashMap.identity() = IdentityMap<K, V>;
+}
+
+@patch
+class LinkedHashMap<K, V> {
+ @patch
+ factory LinkedHashMap(
+ {bool equals(K key1, K key2),
+ int hashCode(K key),
+ bool isValidKey(Object potentialKey)}) {
+ if (isValidKey == null) {
+ if (hashCode == null) {
+ if (equals == null) {
+ if (identical(K, String) || identical(K, int)) {
+ return IdentityMap<K, V>();
+ }
+ return LinkedMap<K, V>();
+ }
+ hashCode = dart.hashCode;
+ } else if (identical(identityHashCode, hashCode) &&
+ identical(identical, equals)) {
+ return IdentityMap<K, V>();
+ }
+ return CustomHashMap<K, V>(equals ?? dart.equals, hashCode);
+ }
+ return CustomKeyHashMap<K, V>(
+ equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
+ }
+
+ @patch
+ factory LinkedHashMap.identity() = IdentityMap<K, V>;
+}
+
+@patch
+class HashSet<E> {
+ @patch
+ factory HashSet(
+ {bool equals(E e1, E e2),
+ int hashCode(E e),
+ bool isValidKey(Object potentialKey)}) {
+ if (isValidKey == null) {
+ if (hashCode == null) {
+ if (equals == null) {
+ if (identical(E, String) || identical(E, int)) {
+ return _IdentityHashSet<E>();
+ }
+ return _HashSet<E>();
+ }
+ hashCode = dart.hashCode;
+ } else if (identical(identityHashCode, hashCode) &&
+ identical(identical, equals)) {
+ return _IdentityHashSet<E>();
+ }
+ return _CustomHashSet<E>(
+ equals ?? dart.equals, hashCode ?? dart.hashCode);
+ }
+ return _CustomKeyHashSet<E>(
+ equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
+ }
+
+ @patch
+ factory HashSet.identity() = _IdentityHashSet<E>;
+}
+
+@patch
+class LinkedHashSet<E> {
+ @patch
+ factory LinkedHashSet(
+ {bool equals(E e1, E e2),
+ int hashCode(E e),
+ bool isValidKey(Object potentialKey)}) {
+ if (isValidKey == null) {
+ if (hashCode == null) {
+ if (equals == null) {
+ if (identical(E, String) || identical(E, int)) {
+ return _IdentityHashSet<E>();
+ }
+ return _HashSet<E>();
+ }
+ hashCode = dart.hashCode;
+ } else if (identical(identityHashCode, hashCode) &&
+ identical(identical, equals)) {
+ return _IdentityHashSet<E>();
+ }
+ return _CustomHashSet<E>(
+ equals ?? dart.equals, hashCode ?? dart.hashCode);
+ }
+ return _CustomKeyHashSet<E>(
+ equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
+ }
+
+ @patch
+ factory LinkedHashSet.identity() = _IdentityHashSet<E>;
+}
+
+class _HashSet<E> extends _InternalSet<E>
+ implements HashSet<E>, LinkedHashSet<E> {
+ /// The backing store for this set.
+ ///
+ /// Keys that use identity equality are stored directly. For other types of
+ /// keys, we first look them up (by hashCode) in the [_keyMap] map, then
+ /// we lookup the key in this map.
+ @notNull
+ final _map = JS('', 'new Set()');
+
+ /// Items that use custom equality semantics.
+ ///
+ /// This maps from the item's hashCode to the canonical key, which is then
+ /// used to lookup the item in [_map]. Keeping the data in our primary backing
+ /// map gives us the ordering semantics requred by [LinkedHashMap], while
+ /// also providing convenient access to keys/values.
+ @notNull
+ final _keyMap = JS('', 'new Map()');
+
+ // We track the number of modifications done to the key set of the
+ // hash map to be able to throw when the map is modified while being
+ // iterated over.
+ //
+ // Value cycles after 2^30 modifications so that modification counts are
+ // always unboxed (Smi) values. Modification detection will be missed if you
+ // make exactly some multiple of 2^30 modifications between advances of an
+ // iterator.
+ @notNull
+ int _modifications = 0;
+
+ _HashSet();
+
+ Set<E> _newSet() => _HashSet<E>();
+
+ Set<R> _newSimilarSet<R>() => _HashSet<R>();
+
+ bool contains(Object key) {
+ if (key == null) {
+ key = null;
+ } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+ dart.identityEquals)) {
+ @notNull
+ var k = key;
+ var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
+ if (buckets != null) {
+ for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+ k = JS('', '#[#]', buckets, i);
+ if (k == key) return true;
+ }
+ }
+ return false;
+ }
+ return JS<bool>('!', '#.has(#)', _map, key);
+ }
+
+ E lookup(Object key) {
+ if (key == null) return null;
+ if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+ dart.identityEquals)) {
+ @notNull
+ var k = key;
+ var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
+ if (buckets != null) {
+ for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+ k = JS('', '#[#]', buckets, i);
+ if (k == key) return JS('', '#', k);
+ }
+ }
+ return null;
+ }
+ return JS('', '#.has(#) ? # : null', _map, key, key);
+ }
+
+ bool add(E key) {
+ var map = _map;
+ if (key == null) {
+ if (JS('', '#.has(null)', map)) return false;
+ key = null;
+ } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+ dart.identityEquals)) {
+ var keyMap = _keyMap;
+ @notNull
+ var k = key;
+ int hash = JS('!', '# & 0x3ffffff', k.hashCode);
+ var buckets = JS('', '#.get(#)', keyMap, hash);
+ if (buckets == null) {
+ JS('', '#.set(#, [#])', keyMap, hash, key);
+ } else {
+ for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+ k = JS('', '#[#]', buckets, i);
+ if (k == key) return false;
+ }
+ JS('', '#.push(#)', buckets, key);
+ }
+ } else if (JS('', '#.has(#)', map, key)) {
+ return false;
+ }
+ JS('', '#.add(#)', map, key);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ return true;
+ }
+
+ void addAll(Iterable<E> objects) {
+ var map = _map;
+ int length = JS('', '#.size', map);
+ for (E key in objects) {
+ if (key == null) {
+ key = null; // converts undefined to null, if needed.
+ } else if (JS<bool>('!', '#[#] !== #', key,
+ dart.extensionSymbol('_equals'), dart.identityEquals)) {
+ key = putLinkedMapKey(key, _keyMap);
+ }
+ JS('', '#.add(#)', map, key);
+ }
+ if (length != JS<int>('!', '#.size', map)) {
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ }
+
+ bool remove(Object key) {
+ if (key == null) {
+ key = null;
+ } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+ dart.identityEquals)) {
+ @notNull
+ var k = key;
+ int hash = JS('!', '# & 0x3ffffff', k.hashCode);
+ var buckets = JS('', '#.get(#)', _keyMap, hash);
+ if (buckets == null) return false; // not found
+ for (int i = 0, n = JS('!', '#.length', buckets);;) {
+ k = JS('', '#[#]', buckets, i);
+ if (k == key) {
+ key = k;
+ if (n == 1) {
+ JS('', '#.delete(#)', _keyMap, hash);
+ } else {
+ JS('', '#.splice(#, 1)', buckets, i);
+ }
+ break;
+ }
+ if (++i >= n) return false; // not found
+ }
+ }
+ var map = _map;
+ if (JS<bool>('!', '#.delete(#)', map, key)) {
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ return true;
+ }
+ return false;
+ }
+
+ void clear() {
+ var map = _map;
+ if (JS<int>('!', '#.size', map) > 0) {
+ JS('', '#.clear()', map);
+ JS('', '#.clear()', _keyMap);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ }
+}
+
+// Used for DDC const sets.
+class _ImmutableSet<E> extends _HashSet<E> {
+ _ImmutableSet.from(JSArray entries) {
+ var map = _map;
+ for (Object key in entries) {
+ if (key == null) {
+ key = null; // converts undefined to null, if needed.
+ } else if (JS<bool>('!', '#[#] !== #', key,
+ dart.extensionSymbol('_equals'), dart.identityEquals)) {
+ key = putLinkedMapKey(key, _keyMap);
+ }
+ JS('', '#.add(#)', map, key);
+ }
+ }
+
+ bool add(Object other) => throw _unsupported();
+ void addAll(Object other) => throw _unsupported();
+ void clear() => throw _unsupported();
+ bool remove(Object key) => throw _unsupported();
+
+ static Error _unsupported() =>
+ UnsupportedError("Cannot modify unmodifiable set");
+}
+
+class _IdentityHashSet<E> extends _InternalSet<E>
+ implements HashSet<E>, LinkedHashSet<E> {
+ /// The backing store for this set.
+ @notNull
+ final _map = JS('', 'new Set()');
+
+ @notNull
+ int _modifications = 0;
+
+ _IdentityHashSet();
+
+ Set<E> _newSet() => _IdentityHashSet<E>();
+
+ Set<R> _newSimilarSet<R>() => _IdentityHashSet<R>();
+
+ bool contains(Object element) {
+ return JS('', '#.has(#)', _map, element);
+ }
+
+ E lookup(Object element) {
+ return JS('', '#.has(#)', _map, element) ? element : null;
+ }
+
+ bool add(E element) {
+ var map = _map;
+ if (JS<bool>('!', '#.has(#)', map, element)) return false;
+ JS('', '#.add(#)', map, element);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ return true;
+ }
+
+ void addAll(Iterable<E> objects) {
+ var map = _map;
+ int length = JS('', '#.size', map);
+ for (E key in objects) {
+ JS('', '#.add(#)', map, key);
+ }
+ if (length != JS<int>('!', '#.size', map)) {
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ }
+
+ bool remove(Object element) {
+ if (JS<bool>('!', '#.delete(#)', _map, element)) {
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ return true;
+ }
+ return false;
+ }
+
+ void clear() {
+ var map = _map;
+ if (JS<int>('!', '#.size', map) > 0) {
+ JS('', '#.clear()', map);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ }
+}
+
+class _CustomKeyHashSet<E> extends _CustomHashSet<E> {
+ _Predicate<Object> _validKey;
+ _CustomKeyHashSet(_Equality<E> equals, _Hasher<E> hashCode, this._validKey)
+ : super(equals, hashCode);
+
+ Set<E> _newSet() => _CustomKeyHashSet<E>(_equals, _hashCode, _validKey);
+
+ Set<R> _newSimilarSet<R>() => _HashSet<R>();
+
+ bool contains(Object element) {
+ // TODO(jmesserly): there is a subtle difference here compared to Dart 1.
+ // See the comment on CustomKeyHashMap.containsKey for more information.
+ // Treatment of `null` is different due to strong mode's requirement to
+ // perform an `element is E` check before calling equals/hashCode.
+ if (!_validKey(element)) return false;
+ return super.contains(element);
+ }
+
+ E lookup(Object element) {
+ if (!_validKey(element)) return null;
+ return super.lookup(element);
+ }
+
+ bool remove(Object element) {
+ if (!_validKey(element)) return false;
+ return super.remove(element);
+ }
+}
+
+class _CustomHashSet<E> extends _InternalSet<E>
+ implements HashSet<E>, LinkedHashSet<E> {
+ _Equality<E> _equals;
+ _Hasher<E> _hashCode;
+
+ // We track the number of modifications done to the key set of the
+ // hash map to be able to throw when the map is modified while being
+ // iterated over.
+ //
+ // Value cycles after 2^30 modifications so that modification counts are
+ // always unboxed (Smi) values. Modification detection will be missed if you
+ // make exactly some multiple of 2^30 modifications between advances of an
+ // iterator.
+ @notNull
+ int _modifications = 0;
+
+ /// The backing store for this set, used to handle ordering.
+ // TODO(jmesserly): a non-linked custom hash set could skip this.
+ @notNull
+ final _map = JS('', 'new Set()');
+
+ /// Our map used to map keys onto the canonical key that is stored in [_map].
+ @notNull
+ final _keyMap = JS('', 'new Map()');
+
+ _CustomHashSet(this._equals, this._hashCode);
+
+ Set<E> _newSet() => _CustomHashSet<E>(_equals, _hashCode);
+ Set<R> _newSimilarSet<R>() => _HashSet<R>();
+
+ bool contains(Object key) {
+ if (key is E) {
+ var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
+ if (buckets != null) {
+ var equals = _equals;
+ for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+ E k = JS('', '#[#]', buckets, i);
+ if (equals(k, key)) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ E lookup(Object key) {
+ if (key is E) {
+ var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
+ if (buckets != null) {
+ var equals = _equals;
+ for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+ E k = JS('', '#[#]', buckets, i);
+ if (equals(k, key)) return k;
+ }
+ }
+ }
+ return null;
+ }
+
+ bool add(E key) {
+ var keyMap = _keyMap;
+ var hash = JS<int>('!', '# & 0x3ffffff', _hashCode(key));
+ var buckets = JS('', '#.get(#)', keyMap, hash);
+ if (buckets == null) {
+ JS('', '#.set(#, [#])', keyMap, hash, key);
+ } else {
+ var equals = _equals;
+ for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+ E k = JS('', '#[#]', buckets, i);
+ if (equals(k, key)) return false;
+ }
+ JS('', '#.push(#)', buckets, key);
+ }
+ JS('', '#.add(#)', _map, key);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ return true;
+ }
+
+ void addAll(Iterable<E> objects) {
+ // TODO(jmesserly): it'd be nice to skip the covariance check here.
+ for (E element in objects) add(element);
+ }
+
+ bool remove(Object key) {
+ if (key is E) {
+ var hash = JS<int>('!', '# & 0x3ffffff', _hashCode(key));
+ var keyMap = _keyMap;
+ var buckets = JS('', '#.get(#)', keyMap, hash);
+ if (buckets == null) return false; // not found
+ var equals = _equals;
+ for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+ E k = JS('', '#[#]', buckets, i);
+ if (equals(k, key)) {
+ if (n == 1) {
+ JS('', '#.delete(#)', keyMap, hash);
+ } else {
+ JS('', '#.splice(#, 1)', buckets, i);
+ }
+ JS('', '#.delete(#)', _map, k);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ void clear() {
+ var map = _map;
+ if (JS<int>('!', '#.size', map) > 0) {
+ JS('', '#.clear()', map);
+ JS('', '#.clear()', _keyMap);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ }
+}
+
+/// Base class for our internal [LinkedHashSet]/[HashSet] implementations.
+///
+/// This implements the common functionality.
+abstract class _InternalSet<E> extends _SetBase<E> {
+ @notNull
+ get _map;
+
+ @notNull
+ int get _modifications;
+
+ @notNull
+ int get length => JS<int>('!', '#.size', _map);
+
+ @notNull
+ bool get isEmpty => JS<bool>('!', '#.size == 0', _map);
+
+ @notNull
+ bool get isNotEmpty => JS<bool>('!', '#.size != 0', _map);
+
+ Iterator<E> get iterator => DartIterator<E>(_jsIterator());
+
+ @JSExportName('Symbol.iterator')
+ _jsIterator() {
+ var self = this;
+ var iterator = JS('', '#.values()', self._map);
+ int modifications = self._modifications;
+ return JS(
+ '',
+ '''{
+ next() {
+ if (# != #) {
+ throw #;
+ }
+ return #.next();
+ }
+ }''',
+ modifications,
+ self._modifications,
+ ConcurrentModificationError(self),
+ iterator);
+ }
+}
+
+@patch
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
+ @patch
+ Node _splayMin(Node node) {
+ Node current = node;
+ while (current.left != null) {
+ Node left = current.left;
+ current.left = left.right;
+ left.right = current;
+ current = left;
+ }
+ return current;
+ }
+
+ @patch
+ Node _splayMax(Node node) {
+ Node current = node;
+ while (current.right != null) {
+ Node right = current.right;
+ current.right = right.left;
+ right.left = current;
+ current = right;
+ }
+ return current;
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/convert_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/convert_patch.dart
new file mode 100644
index 0000000..486473b
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/convert_patch.dart
@@ -0,0 +1,508 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:convert library.
+
+import 'dart:_js_helper' show argumentErrorValue, patch;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show JSExtendableArray;
+import 'dart:_internal' show MappedIterable, ListIterable;
+import 'dart:collection' show Maps, LinkedHashMap, MapBase;
+import 'dart:_native_typed_data' show NativeUint8List;
+
+/**
+ * Parses [json] and builds the corresponding parsed JSON value.
+ *
+ * Parsed JSON values Nare of the types [num], [String], [bool], [Null],
+ * [List]s of parsed JSON values or [Map]s from [String] to parsed
+ * JSON values.
+ *
+ * The optional [reviver] function, if provided, is called once for each object
+ * or list property parsed. The arguments are the property name ([String]) or
+ * list index ([int]), and the value is the parsed value. The return value of
+ * the reviver will be used as the value of that property instead of the parsed
+ * value. The top level value is passed to the reviver with the empty string as
+ * a key.
+ *
+ * Throws [FormatException] if the input is not valid JSON text.
+ */
+@patch
+_parseJson(String source, reviver(Object key, Object value)) {
+ if (source is! String) throw argumentErrorValue(source);
+
+ var parsed;
+ try {
+ parsed = JS('=Object|JSExtendableArray|Null|bool|num|String',
+ 'JSON.parse(#)', source);
+ } catch (e) {
+ throw FormatException(JS<String>('!', 'String(#)', e));
+ }
+
+ if (reviver == null) {
+ return _convertJsonToDartLazy(parsed);
+ } else {
+ return _convertJsonToDart(parsed, reviver);
+ }
+}
+
+/**
+ * Walks the raw JavaScript value [json], replacing JavaScript Objects with
+ * Maps. [json] is expected to be freshly allocated so elements can be replaced
+ * in-place.
+ */
+_convertJsonToDart(json, reviver(Object key, Object value)) {
+ assert(reviver != null);
+ walk(e) {
+ // JavaScript null, string, number, bool are in the correct representation.
+ if (JS<bool>('!', '# == null', e) ||
+ JS<bool>('!', 'typeof # != "object"', e)) {
+ return e;
+ }
+
+ // This test is needed to avoid identifying '{"__proto__":[]}' as an Array.
+ // TODO(sra): Replace this test with cheaper '#.constructor === Array' when
+ // bug 621 below is fixed.
+ if (JS<bool>('!', 'Object.getPrototypeOf(#) === Array.prototype', e)) {
+ // In-place update of the elements since JS Array is a Dart List.
+ for (int i = 0; i < JS<int>('!', '#.length', e); i++) {
+ // Use JS indexing to avoid range checks. We know this is the only
+ // reference to the list, but the compiler will likely never be able to
+ // tell that this instance of the list cannot have its length changed by
+ // the reviver even though it later will be passed to the reviver at the
+ // outer level.
+ var item = JS('', '#[#]', e, i);
+ JS('', '#[#]=#', e, i, reviver(i, walk(item)));
+ }
+ return e;
+ }
+
+ // Otherwise it is a plain object, so copy to a JSON map, so we process
+ // and revive all entries recursively.
+ _JsonMap map = _JsonMap(e);
+ var processed = map._processed;
+ List<String> keys = map._computeKeys();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i];
+ var revived = reviver(key, walk(JS('', '#[#]', e, key)));
+ JS('', '#[#]=#', processed, key, revived);
+ }
+
+ // Update the JSON map structure so future access is cheaper.
+ map._original = processed; // Don't keep two objects around.
+ return map;
+ }
+
+ return reviver(null, walk(json));
+}
+
+_convertJsonToDartLazy(object) {
+ // JavaScript null and undefined are represented as null.
+ if (object == null) return null;
+
+ // JavaScript string, number, bool already has the correct representation.
+ if (JS<bool>('!', 'typeof # != "object"', object)) {
+ return object;
+ }
+
+ // This test is needed to avoid identifying '{"__proto__":[]}' as an array.
+ // TODO(sra): Replace this test with cheaper '#.constructor === Array' when
+ // bug https://code.google.com/p/v8/issues/detail?id=621 is fixed.
+ if (JS<bool>('!', 'Object.getPrototypeOf(#) !== Array.prototype', object)) {
+ return _JsonMap(object);
+ }
+
+ // Update the elements in place since JS arrays are Dart lists.
+ for (int i = 0; i < JS<int>('!', '#.length', object); i++) {
+ // Use JS indexing to avoid range checks. We know this is the only
+ // reference to the list, but the compiler will likely never be able to
+ // tell that this instance of the list cannot have its length changed by
+ // the reviver even though it later will be passed to the reviver at the
+ // outer level.
+ var item = JS('', '#[#]', object, i);
+ JS('', '#[#]=#', object, i, _convertJsonToDartLazy(item));
+ }
+ return object;
+}
+
+class _JsonMap extends MapBase<String, dynamic> {
+ // The original JavaScript object remains unchanged until
+ // the map is eventually upgraded, in which case we null it
+ // out to reclaim the memory used by it.
+ var _original;
+
+ // We keep track of the map entries that we have already
+ // processed by adding them to a separate JavaScript object.
+ var _processed = _newJavaScriptObject();
+
+ // If the data slot isn't null, it represents either the list
+ // of keys (for non-upgraded JSON maps) or the upgraded map.
+ var _data = null;
+
+ _JsonMap(this._original);
+
+ operator [](key) {
+ if (_isUpgraded) {
+ return _upgradedMap[key];
+ } else if (key is! String) {
+ return null;
+ } else {
+ var result = _getProperty(_processed, key);
+ if (_isUnprocessed(result)) result = _process(key);
+ return result;
+ }
+ }
+
+ int get length => _isUpgraded ? _upgradedMap.length : _computeKeys().length;
+
+ bool get isEmpty => length == 0;
+ bool get isNotEmpty => length > 0;
+
+ Iterable<String> get keys {
+ if (_isUpgraded) return _upgradedMap.keys;
+ return _JsonMapKeyIterable(this);
+ }
+
+ Iterable get values {
+ if (_isUpgraded) return _upgradedMap.values;
+ return MappedIterable(_computeKeys(), (each) => this[each]);
+ }
+
+ operator []=(key, value) {
+ if (_isUpgraded) {
+ _upgradedMap[key] = value;
+ } else if (containsKey(key)) {
+ var processed = _processed;
+ _setProperty(processed, key, value);
+ var original = _original;
+ if (!identical(original, processed)) {
+ _setProperty(original, key, null); // Reclaim memory.
+ }
+ } else {
+ _upgrade()[key] = value;
+ }
+ }
+
+ void addAll(Map<String, dynamic> other) {
+ other.forEach((key, value) {
+ this[key] = value;
+ });
+ }
+
+ bool containsValue(value) {
+ if (_isUpgraded) return _upgradedMap.containsValue(value);
+ List<String> keys = _computeKeys();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i];
+ if (this[key] == value) return true;
+ }
+ return false;
+ }
+
+ bool containsKey(key) {
+ if (_isUpgraded) return _upgradedMap.containsKey(key);
+ if (key is! String) return false;
+ return _hasProperty(_original, key);
+ }
+
+ putIfAbsent(key, ifAbsent()) {
+ if (containsKey(key)) return this[key];
+ var value = ifAbsent();
+ this[key] = value;
+ return value;
+ }
+
+ remove(Object key) {
+ if (!_isUpgraded && !containsKey(key)) return null;
+ return _upgrade().remove(key);
+ }
+
+ void clear() {
+ if (_isUpgraded) {
+ _upgradedMap.clear();
+ } else {
+ if (_data != null) {
+ // Clear the list of keys to make sure we force
+ // a concurrent modification error if anyone is
+ // currently iterating over it.
+ _data.clear();
+ }
+ _original = _processed = null;
+ _data = {};
+ }
+ }
+
+ void forEach(void f(String key, value)) {
+ if (_isUpgraded) return _upgradedMap.forEach(f);
+ List<String> keys = _computeKeys();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i];
+
+ // Compute the value under the assumption that the property
+ // is present but potentially not processed.
+ var value = _getProperty(_processed, key);
+ if (_isUnprocessed(value)) {
+ value = _convertJsonToDartLazy(_getProperty(_original, key));
+ _setProperty(_processed, key, value);
+ }
+
+ // Do the callback.
+ f(key, value);
+
+ // Check if invoking the callback function changed
+ // the key set. If so, throw an exception.
+ if (!identical(keys, _data)) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ }
+
+ // ------------------------------------------
+ // Private helper methods.
+ // ------------------------------------------
+
+ bool get _isUpgraded => _processed == null;
+
+ Map<String, dynamic> get _upgradedMap {
+ assert(_isUpgraded);
+ // 'cast' the union type to LinkedHashMap. It would be even better if we
+ // could 'cast' to the implementation type, since LinkedHashMap includes
+ // _JsonMap.
+ return JS('LinkedHashMap', '#', _data);
+ }
+
+ List<String> _computeKeys() {
+ assert(!_isUpgraded);
+ List keys = _data;
+ if (keys == null) {
+ keys = _data = _getPropertyNames(_original);
+ }
+ return JS('JSExtendableArray', '#', keys);
+ }
+
+ Map<String, dynamic> _upgrade() {
+ if (_isUpgraded) return _upgradedMap;
+
+ // Copy all the (key, value) pairs to a freshly allocated
+ // linked hash map thus preserving the ordering.
+ var result = <String, dynamic>{};
+ List<String> keys = _computeKeys();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i];
+ result[key] = this[key];
+ }
+
+ // We only upgrade when we need to extend the map, so we can
+ // safely force a concurrent modification error in case
+ // someone is iterating over the map here.
+ if (keys.isEmpty) {
+ keys.add(null);
+ } else {
+ keys.clear();
+ }
+
+ // Clear out the associated JavaScript objects and mark the
+ // map as having been upgraded.
+ _original = _processed = null;
+ _data = result;
+ assert(_isUpgraded);
+ return result;
+ }
+
+ _process(String key) {
+ if (!_hasProperty(_original, key)) return null;
+ var result = _convertJsonToDartLazy(_getProperty(_original, key));
+ return _setProperty(_processed, key, result);
+ }
+
+ // ------------------------------------------
+ // Private JavaScript helper methods.
+ // ------------------------------------------
+
+ static bool _hasProperty(object, String key) =>
+ JS<bool>('!', 'Object.prototype.hasOwnProperty.call(#,#)', object, key);
+ static _getProperty(object, String key) => JS('', '#[#]', object, key);
+ static _setProperty(object, String key, value) =>
+ JS('', '#[#]=#', object, key, value);
+ static List _getPropertyNames(object) =>
+ JS('JSExtendableArray', 'Object.keys(#)', object);
+ static bool _isUnprocessed(object) =>
+ JS<bool>('!', 'typeof(#)=="undefined"', object);
+ static _newJavaScriptObject() => JS('=Object', 'Object.create(null)');
+}
+
+class _JsonMapKeyIterable extends ListIterable<String> {
+ final _JsonMap _parent;
+
+ _JsonMapKeyIterable(this._parent);
+
+ int get length => _parent.length;
+
+ String elementAt(int index) {
+ return _parent._isUpgraded
+ ? _parent.keys.elementAt(index)
+ : _parent._computeKeys()[index];
+ }
+
+ /// Although [ListIterable] defines its own iterator, we return the iterator
+ /// of the underlying list [_keys] in order to propagate
+ /// [ConcurrentModificationError]s.
+ Iterator<String> get iterator {
+ return _parent._isUpgraded
+ ? _parent.keys.iterator
+ : _parent._computeKeys().iterator;
+ }
+
+ /// Delegate to [parent.containsKey] to ensure the performance expected
+ /// from [Map.keys.containsKey].
+ bool contains(Object key) => _parent.containsKey(key);
+}
+
+@patch
+class JsonDecoder {
+ @patch
+ StringConversionSink startChunkedConversion(Sink<Object> sink) {
+ return _JsonDecoderSink(_reviver, sink);
+ }
+}
+
+/**
+ * Implements the chunked conversion from a JSON string to its corresponding
+ * object.
+ *
+ * The sink only creates one object, but its input can be chunked.
+ */
+// TODO(floitsch): don't accumulate everything before starting to decode.
+class _JsonDecoderSink extends _StringSinkConversionSink {
+ final Function(Object key, Object value) _reviver;
+ final Sink<Object> _sink;
+
+ _JsonDecoderSink(this._reviver, this._sink) : super(StringBuffer(''));
+
+ void close() {
+ super.close();
+ StringBuffer buffer = _stringSink;
+ String accumulated = buffer.toString();
+ buffer.clear();
+ Object decoded = _parseJson(accumulated, _reviver);
+ _sink.add(decoded);
+ _sink.close();
+ }
+}
+
+@patch
+class Utf8Decoder {
+ @patch
+ Converter<List<int>, T> fuse<T>(Converter<String, T> next) {
+ return super.fuse(next);
+ }
+
+ // Currently not intercepting UTF8 decoding.
+ @patch
+ static String _convertIntercepted(
+ bool allowMalformed, List<int> codeUnits, int start, int end) {
+ // Test `codeUnits is NativeUint8List`. Dart's NativeUint8List is
+ // implemented by JavaScript's Uint8Array.
+ if (JS<bool>('!', '# instanceof Uint8Array', codeUnits)) {
+ // JS 'cast' to avoid a downcast equivalent to the is-check we hand-coded.
+ NativeUint8List casted = JS<NativeUint8List>('!', '#', codeUnits);
+ return _convertInterceptedUint8List(allowMalformed, casted, start, end);
+ }
+ }
+
+ static String _convertInterceptedUint8List(
+ bool allowMalformed, NativeUint8List codeUnits, int start, int end) {
+ if (allowMalformed) {
+ // TextDecoder with option {fatal: false} does not produce the same result
+ // as [Utf8Decoder]. It disagrees on the number of `U+FFFD` (REPLACEMENT
+ // CHARACTER) generated for some malformed sequences. We could use
+ // TextDecoder with option {fatal: true}, catch the error, and re-try
+ // without acceleration. That turns out to be extremely slow (the Error
+ // captures a stack trace).
+ // TODO(31370): Bring Utf8Decoder into alignment with TextDecoder.
+ // TODO(sra): If we can't do that, can we detect valid input fast enough
+ // to use a check like the [_unsafe] check below?
+ return null;
+ }
+
+ var decoder = _decoder;
+ if (decoder == null) return null;
+ if (0 == start && end == null) {
+ return _useTextDecoderChecked(decoder, codeUnits);
+ }
+
+ int length = codeUnits.length;
+ end = RangeError.checkValidRange(start, end, length);
+
+ if (0 == start && end == codeUnits.length) {
+ return _useTextDecoderChecked(decoder, codeUnits);
+ }
+
+ return _useTextDecoderChecked(decoder,
+ JS<NativeUint8List>('!', '#.subarray(#, #)', codeUnits, start, end));
+ }
+
+ static String _useTextDecoderChecked(decoder, NativeUint8List codeUnits) {
+ if (_unsafe(codeUnits)) return null;
+ return _useTextDecoderUnchecked(decoder, codeUnits);
+ }
+
+ static String _useTextDecoderUnchecked(decoder, NativeUint8List codeUnits) {
+ // If the input is malformed, catch the exception and return `null` to fall
+ // back on unintercepted decoder. The fallback will either succeed in
+ // decoding, or report the problem better than TextDecoder.
+ try {
+ return JS<String>('!', '#.decode(#)', decoder, codeUnits);
+ } catch (e) {}
+ return null;
+ }
+
+ /// Returns `true` if [codeUnits] contains problematic encodings.
+ ///
+ /// TextDecoder behaves differently to [Utf8Encoder] when the input encodes a
+ /// surrogate (U+D800 through U+DFFF). TextDecoder considers the surrogate to
+ /// be an encoding error and, depending on the `fatal` option, either throws
+ /// and Error or encodes the surrogate as U+FFFD. [Utf8Decoder] does not
+ /// consider the surrogate to be an error and returns the code unit encoded by
+ /// the surrogate.
+ ///
+ /// Throwing an `Error` captures the stack, whoch makes it so expensive that
+ /// it is worth checking the input for surrogates and avoiding TextDecoder in
+ /// this case.
+ static bool _unsafe(NativeUint8List codeUnits) {
+ // Surrogates encode as (hex) ED Ax xx or ED Bx xx.
+ int limit = codeUnits.length - 2;
+ for (int i = 0; i < limit; i++) {
+ int unit1 = codeUnits[i];
+ if (unit1 == 0xED) {
+ int unit2 = JS('!', '#', codeUnits[i + 1]);
+ if ((unit2 & 0xE0) == 0xA0) return true;
+ }
+ }
+ return false;
+ }
+
+ //// TextDecoder is not defined on some browsers and on the stand-alone d8 and
+ /// jsshell engines. Use a lazy initializer to do feature detection once.
+ static final _decoder = () {
+ try {
+ // Use `{fatal: true}`. 'fatal' does not correspond exactly to
+ // `!allowMalformed`: TextDecoder rejects unpaired surrogates which
+ // [Utf8Decoder] accepts. In non-fatal mode, TextDecoder translates
+ // unpaired surrogates to REPLACEMENT CHARACTER (U+FFFD) whereas
+ // [Utf8Decoder] leaves the surrogate intact.
+ return JS('', 'new TextDecoder("utf-8", {fatal: true})');
+ } catch (e) {}
+ return null;
+ }();
+}
+
+@patch
+int _scanOneByteCharacters(List<int> units, int from, int endIndex) {
+ final to = endIndex;
+ for (var i = from; i < to; i++) {
+ final unit = units[i];
+ if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
+ }
+ return to - from;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart
new file mode 100644
index 0000000..746ac61
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart
@@ -0,0 +1,2910 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:core classes.
+import "dart:_internal" as _symbol_dev;
+import 'dart:_interceptors';
+import 'dart:_js_helper'
+ show
+ patch,
+ checkInt,
+ getRuntimeType,
+ LinkedMap,
+ JSSyntaxRegExp,
+ NoInline,
+ notNull,
+ nullCheck,
+ Primitives,
+ PrivateSymbol,
+ quoteStringForRegExp,
+ undefined;
+import 'dart:_runtime' as dart;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_native_typed_data' show NativeUint8List;
+import 'dart:collection' show UnmodifiableMapView;
+import 'dart:convert' show Encoding, utf8;
+import 'dart:typed_data' show Endian, Uint8List, Uint16List;
+
+String _symbolToString(Symbol symbol) => symbol is PrivateSymbol
+ ? PrivateSymbol.getName(symbol)
+ : _symbol_dev.Symbol.getName(symbol);
+
+@patch
+int identityHashCode(Object object) {
+ if (object == null) return 0;
+ // Note: this works for primitives because we define the `identityHashCode`
+ // for them to be equivalent to their computed hashCode function.
+ int hash = JS('int|Null', r'#[#]', object, dart.identityHashCode_);
+ if (hash == null) {
+ hash = JS<int>('!', '(Math.random() * 0x3fffffff) | 0');
+ JS('void', r'#[#] = #', object, dart.identityHashCode_, hash);
+ }
+ return JS<int>('!', '#', hash);
+}
+
+// Patch for Object implementation.
+@patch
+class Object {
+ @patch
+ bool operator ==(other) => identical(this, other);
+
+ @patch
+ int get hashCode => identityHashCode(this);
+
+ @patch
+ String toString() =>
+ "Instance of '${dart.typeName(dart.getReifiedType(this))}'";
+
+ @patch
+ noSuchMethod(Invocation invocation) {
+ return dart.defaultNoSuchMethod(this, invocation);
+ }
+
+ @patch
+ Type get runtimeType => dart.wrapType(dart.getReifiedType(this));
+}
+
+@patch
+class Null {
+ @patch
+ int get hashCode => super.hashCode;
+}
+
+// Patch for Function implementation.
+@patch
+class Function {
+ @patch
+ static apply(Function f, List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
+ positionalArguments ??= [];
+ // dcall expects the namedArguments as a JS map in the last slot.
+ if (namedArguments != null && namedArguments.isNotEmpty) {
+ var map = JS('', '{}');
+ namedArguments.forEach((symbol, arg) {
+ JS('', '#[#] = #', map, _symbolToString(symbol), arg);
+ });
+ return dart.dcall(f, positionalArguments, map);
+ }
+ return dart.dcall(f, positionalArguments);
+ }
+
+ static Map<String, dynamic> _toMangledNames(
+ Map<Symbol, dynamic> namedArguments) {
+ Map<String, dynamic> result = {};
+ namedArguments.forEach((symbol, value) {
+ result[_symbolToString(symbol)] = value;
+ });
+ return result;
+ }
+}
+
+// TODO(jmesserly): switch to WeakMap
+// Patch for Expando implementation.
+@patch
+class Expando<T> {
+ @patch
+ Expando([String name]) : this.name = name;
+
+ @patch
+ T operator [](Object object) {
+ var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
+ return (values == null) ? null : Primitives.getProperty(values, _getKey());
+ }
+
+ @patch
+ void operator []=(Object object, T value) {
+ var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
+ if (values == null) {
+ values = Object();
+ Primitives.setProperty(object, _EXPANDO_PROPERTY_NAME, values);
+ }
+ Primitives.setProperty(values, _getKey(), value);
+ }
+
+ String _getKey() {
+ String key = Primitives.getProperty(this, _KEY_PROPERTY_NAME);
+ if (key == null) {
+ key = "expando\$key\$${_keyCount++}";
+ Primitives.setProperty(this, _KEY_PROPERTY_NAME, key);
+ }
+ return key;
+ }
+
+ static const String _KEY_PROPERTY_NAME = 'expando\$key';
+ static const String _EXPANDO_PROPERTY_NAME = 'expando\$values';
+ static int _keyCount = 0;
+}
+
+Null _kNull(_) => null;
+
+@patch
+class int {
+ @patch
+ static int parse(String source,
+ {int radix, @deprecated int onError(String source)}) {
+ return Primitives.parseInt(source, radix, onError);
+ }
+
+ @patch
+ static int tryParse(String source, {int radix}) {
+ return Primitives.parseInt(source, radix, _kNull);
+ }
+
+ @patch
+ factory int.fromEnvironment(String name, {int defaultValue}) {
+ // ignore: const_constructor_throws_exception
+ throw UnsupportedError(
+ 'int.fromEnvironment can only be used as a const constructor');
+ }
+}
+
+@patch
+class double {
+ @patch
+ static double parse(String source,
+ [@deprecated double onError(String source)]) {
+ return Primitives.parseDouble(source, onError);
+ }
+
+ @patch
+ static double tryParse(String source) {
+ return Primitives.parseDouble(source, _kNull);
+ }
+}
+
+@patch
+class BigInt implements Comparable<BigInt> {
+ @patch
+ static BigInt get zero => _BigIntImpl.zero;
+ @patch
+ static BigInt get one => _BigIntImpl.one;
+ @patch
+ static BigInt get two => _BigIntImpl.two;
+
+ @patch
+ static BigInt parse(String source, {int radix}) =>
+ _BigIntImpl.parse(source, radix: radix);
+
+ @patch
+ static BigInt tryParse(String source, {int radix}) =>
+ _BigIntImpl._tryParse(source, radix: radix);
+
+ @patch
+ factory BigInt.from(num value) = _BigIntImpl.from;
+}
+
+@patch
+class Error {
+ @patch
+ static String _objectToString(Object object) {
+ return "Instance of '${dart.typeName(dart.getReifiedType(object))}'";
+ }
+
+ @patch
+ static String _stringToSafeString(String string) {
+ return JS("String", "JSON.stringify(#)", string);
+ }
+
+ @patch
+ StackTrace get stackTrace => dart.stackTraceForError(this);
+}
+
+@patch
+class FallThroughError {
+ @patch
+ FallThroughError._create(String url, int line);
+
+ @patch
+ String toString() => super.toString();
+}
+
+@patch
+class AbstractClassInstantiationError {
+ @patch
+ String toString() => "Cannot instantiate abstract class: '$_className'";
+}
+
+// Patch for DateTime implementation.
+@patch
+class DateTime {
+ @patch
+ DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
+ {bool isUtc = false})
+ : this._withValue(millisecondsSinceEpoch, isUtc: isUtc);
+
+ @patch
+ DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
+ {bool isUtc = false})
+ : this._withValue(
+ _microsecondInRoundedMilliseconds(microsecondsSinceEpoch),
+ isUtc: isUtc);
+
+ @patch
+ DateTime._internal(int year, int month, int day, int hour, int minute,
+ int second, int millisecond, int microsecond, bool isUtc)
+ // checkBool is manually inlined here because dart2js doesn't inline it
+ // and [isUtc] is usually a constant.
+ : this.isUtc =
+ isUtc is bool ? isUtc : throw ArgumentError.value(isUtc, 'isUtc'),
+ _value = checkInt(Primitives.valueFromDecomposedDate(
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ millisecond + _microsecondInRoundedMilliseconds(microsecond),
+ isUtc));
+
+ @patch
+ DateTime._now()
+ : isUtc = false,
+ _value = Primitives.dateNow();
+
+ /// Rounds the given [microsecond] to the nearest milliseconds value.
+ ///
+ /// For example, invoked with argument `2600` returns `3`.
+ static int _microsecondInRoundedMilliseconds(int microsecond) {
+ return (microsecond / 1000).round();
+ }
+
+ @patch
+ static int _brokenDownDateToValue(int year, int month, int day, int hour,
+ int minute, int second, int millisecond, int microsecond, bool isUtc) {
+ return Primitives.valueFromDecomposedDate(
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ millisecond + _microsecondInRoundedMilliseconds(microsecond),
+ isUtc);
+ }
+
+ @patch
+ String get timeZoneName {
+ if (isUtc) return "UTC";
+ return Primitives.getTimeZoneName(this);
+ }
+
+ @patch
+ Duration get timeZoneOffset {
+ if (isUtc) return Duration();
+ return Duration(minutes: Primitives.getTimeZoneOffsetInMinutes(this));
+ }
+
+ @patch
+ DateTime add(Duration duration) {
+ return DateTime._withValue(_value + duration.inMilliseconds, isUtc: isUtc);
+ }
+
+ @patch
+ DateTime subtract(Duration duration) {
+ return DateTime._withValue(_value - duration.inMilliseconds, isUtc: isUtc);
+ }
+
+ @patch
+ Duration difference(DateTime other) {
+ return Duration(milliseconds: _value - other._value);
+ }
+
+ @patch
+ int get millisecondsSinceEpoch => _value;
+
+ @patch
+ int get microsecondsSinceEpoch => _value * 1000;
+
+ @patch
+ int get year => Primitives.getYear(this);
+
+ @patch
+ int get month => Primitives.getMonth(this);
+
+ @patch
+ int get day => Primitives.getDay(this);
+
+ @patch
+ int get hour => Primitives.getHours(this);
+
+ @patch
+ int get minute => Primitives.getMinutes(this);
+
+ @patch
+ int get second => Primitives.getSeconds(this);
+
+ @patch
+ int get millisecond => Primitives.getMilliseconds(this);
+
+ @patch
+ int get microsecond => 0;
+
+ @patch
+ int get weekday => Primitives.getWeekday(this);
+
+ @patch
+ bool operator ==(dynamic other) =>
+ other is DateTime &&
+ _value == other.millisecondsSinceEpoch &&
+ isUtc == other.isUtc;
+
+ @patch
+ bool isBefore(DateTime other) => _value < other.millisecondsSinceEpoch;
+
+ @patch
+ bool isAfter(DateTime other) => _value > other.millisecondsSinceEpoch;
+
+ @patch
+ bool isAtSameMomentAs(DateTime other) =>
+ _value == other.millisecondsSinceEpoch;
+
+ @patch
+ int compareTo(DateTime other) =>
+ _value.compareTo(other.millisecondsSinceEpoch);
+}
+
+// Patch for Stopwatch implementation.
+@patch
+class Stopwatch {
+ @patch
+ static void _initTicker() {
+ Primitives.initTicker();
+ _frequency = Primitives.timerFrequency;
+ }
+
+ @patch
+ static int _now() => Primitives.timerTicks();
+
+ @patch
+ int get elapsedMicroseconds {
+ int ticks = elapsedTicks;
+ if (_frequency == 1000000) return ticks;
+ assert(_frequency == 1000);
+ return ticks * 1000;
+ }
+
+ @patch
+ int get elapsedMilliseconds {
+ int ticks = elapsedTicks;
+ if (_frequency == 1000) return ticks;
+ assert(_frequency == 1000000);
+ return ticks ~/ 1000;
+ }
+}
+
+// Patch for List implementation.
+@patch
+class List<E> {
+ @patch
+ factory List([@undefined int _length]) {
+ dynamic list;
+ if (JS<bool>('!', '# === void 0', _length)) {
+ list = JS('', '[]');
+ } else {
+ int length = JS('!', '#', _length);
+ if (_length == null || length < 0) {
+ throw ArgumentError("Length must be a non-negative integer: $_length");
+ }
+ list = JS('', 'new Array(#)', length);
+ JS('', '#.fill(null)', list);
+ JSArray.markFixedList(list);
+ }
+ return JSArray<E>.of(list);
+ }
+
+ @patch
+ factory List.filled(@nullCheck int length, E fill, {bool growable = false}) {
+ var list = JSArray<E>.of(JS('', 'new Array(#)', length));
+ JS('', '#.fill(#)', list, fill);
+ if (!growable) JSArray.markFixedList(list);
+ return list;
+ }
+
+ @patch
+ factory List.from(Iterable elements, {bool growable = true}) {
+ var list = JSArray<E>.of(JS('', '[]'));
+ // Specialize the copy loop for the case that doesn't need a
+ // runtime check.
+ if (elements is Iterable<E>) {
+ for (var e in elements) {
+ list.add(e);
+ }
+ } else {
+ for (var e in elements) {
+ list.add(e as E);
+ }
+ }
+ if (!growable) JSArray.markFixedList(list);
+ return list;
+ }
+
+ @patch
+ factory List.unmodifiable(Iterable elements) {
+ var list = List<E>.from(elements);
+ JSArray.markUnmodifiableList(list);
+ return list;
+ }
+}
+
+@patch
+class Map<K, V> {
+ @patch
+ factory Map.unmodifiable(Map other) {
+ return UnmodifiableMapView<K, V>(Map<K, V>.from(other));
+ }
+
+ @patch
+ factory Map() = LinkedMap<K, V>;
+}
+
+@patch
+class String {
+ @patch
+ factory String.fromCharCodes(Iterable<int> charCodes,
+ [int start = 0, int end]) {
+ if (charCodes is JSArray) {
+ return _stringFromJSArray(charCodes, start, end);
+ }
+ if (charCodes is NativeUint8List) {
+ return _stringFromUint8List(charCodes, start, end);
+ }
+ return _stringFromIterable(charCodes, start, end);
+ }
+
+ @patch
+ factory String.fromCharCode(int charCode) {
+ return Primitives.stringFromCharCode(charCode);
+ }
+
+ @patch
+ factory String.fromEnvironment(String name, {String defaultValue}) {
+ // ignore: const_constructor_throws_exception
+ throw UnsupportedError(
+ 'String.fromEnvironment can only be used as a const constructor');
+ }
+
+ static String _stringFromJSArray(
+ /*=JSArray<int>*/ list,
+ int start,
+ int endOrNull) {
+ int len = list.length;
+ int end = RangeError.checkValidRange(start, endOrNull, len);
+ if (start > 0 || end < len) {
+ list = list.sublist(start, end);
+ }
+ return Primitives.stringFromCharCodes(list);
+ }
+
+ static String _stringFromUint8List(
+ NativeUint8List charCodes, int start, int endOrNull) {
+ int len = charCodes.length;
+ int end = RangeError.checkValidRange(start, endOrNull, len);
+ return Primitives.stringFromNativeUint8List(charCodes, start, end);
+ }
+
+ static String _stringFromIterable(
+ Iterable<int> charCodes, int start, int end) {
+ if (start < 0) throw RangeError.range(start, 0, charCodes.length);
+ if (end != null && end < start) {
+ throw RangeError.range(end, start, charCodes.length);
+ }
+ var it = charCodes.iterator;
+ for (int i = 0; i < start; i++) {
+ if (!it.moveNext()) {
+ throw RangeError.range(start, 0, i);
+ }
+ }
+ var list = <int>[];
+ if (end == null) {
+ while (it.moveNext()) list.add(it.current);
+ } else {
+ for (int i = start; i < end; i++) {
+ if (!it.moveNext()) {
+ throw RangeError.range(end, start, i);
+ }
+ list.add(it.current);
+ }
+ }
+ return Primitives.stringFromCharCodes(list);
+ }
+}
+
+@patch
+class bool {
+ @patch
+ factory bool.fromEnvironment(String name, {bool defaultValue = false}) {
+ // ignore: const_constructor_throws_exception
+ throw UnsupportedError(
+ 'bool.fromEnvironment can only be used as a const constructor');
+ }
+
+ @patch
+ int get hashCode => super.hashCode;
+}
+
+@patch
+class RegExp {
+ @patch
+ factory RegExp(String source,
+ {bool multiLine = false,
+ bool caseSensitive = true,
+ bool unicode = false,
+ bool dotAll = false}) =>
+ JSSyntaxRegExp(source,
+ multiLine: multiLine,
+ caseSensitive: caseSensitive,
+ unicode: unicode,
+ dotAll: dotAll);
+
+ @patch
+ static String escape(String text) => quoteStringForRegExp(text);
+}
+
+// Patch for 'identical' function.
+@patch
+bool identical(Object a, Object b) {
+ return JS<bool>('!', '(# == null ? # == null : # === #)', a, b, a, b);
+}
+
+@patch
+class StringBuffer {
+ String _contents;
+
+ @patch
+ StringBuffer([Object content = ""]) : _contents = '$content';
+
+ @patch
+ int get length => _contents.length;
+
+ @patch
+ void write(Object obj) {
+ _writeString('$obj');
+ }
+
+ @patch
+ void writeCharCode(int charCode) {
+ _writeString(String.fromCharCode(charCode));
+ }
+
+ @patch
+ void writeAll(Iterable objects, [String separator = ""]) {
+ _contents = _writeAll(_contents, objects, separator);
+ }
+
+ @patch
+ void writeln([Object obj = ""]) {
+ _writeString('$obj\n');
+ }
+
+ @patch
+ void clear() {
+ _contents = "";
+ }
+
+ @patch
+ String toString() => Primitives.flattenString(_contents);
+
+ void _writeString(str) {
+ _contents = Primitives.stringConcatUnchecked(_contents, str);
+ }
+
+ static String _writeAll(String string, Iterable objects, String separator) {
+ Iterator iterator = objects.iterator;
+ if (!iterator.moveNext()) return string;
+ if (separator.isEmpty) {
+ do {
+ string = _writeOne(string, iterator.current);
+ } while (iterator.moveNext());
+ } else {
+ string = _writeOne(string, iterator.current);
+ while (iterator.moveNext()) {
+ string = _writeOne(string, separator);
+ string = _writeOne(string, iterator.current);
+ }
+ }
+ return string;
+ }
+
+ static String _writeOne(String string, Object obj) {
+ return Primitives.stringConcatUnchecked(string, '$obj');
+ }
+}
+
+// TODO(jmesserly): kernel expects to find this in our SDK.
+class _CompileTimeError extends Error {
+ final String _errorMsg;
+ _CompileTimeError(this._errorMsg);
+ String toString() => _errorMsg;
+}
+
+@patch
+class NoSuchMethodError {
+ final Object _receiver;
+ final Symbol _memberName;
+ final List _arguments;
+ final Map<Symbol, dynamic> _namedArguments;
+ final List _existingArgumentNames;
+ final Invocation _invocation;
+
+ @patch
+ NoSuchMethodError(Object receiver, Symbol memberName,
+ List positionalArguments, Map<Symbol, dynamic> namedArguments,
+ [List existingArgumentNames = null])
+ : _receiver = receiver,
+ _memberName = memberName,
+ _arguments = positionalArguments,
+ _namedArguments = namedArguments,
+ _existingArgumentNames = existingArgumentNames,
+ _invocation = null;
+
+ @patch
+ NoSuchMethodError.withInvocation(Object receiver, Invocation invocation)
+ : _receiver = receiver,
+ _memberName = invocation.memberName,
+ _arguments = invocation.positionalArguments,
+ _namedArguments = invocation.namedArguments,
+ _existingArgumentNames = null,
+ _invocation = invocation;
+
+ @patch
+ String toString() {
+ StringBuffer sb = StringBuffer('');
+ String comma = '';
+ if (_arguments != null) {
+ for (var argument in _arguments) {
+ sb.write(comma);
+ sb.write(Error.safeToString(argument));
+ comma = ', ';
+ }
+ }
+ if (_namedArguments != null) {
+ _namedArguments.forEach((Symbol key, var value) {
+ sb.write(comma);
+ sb.write(_symbolToString(key));
+ sb.write(": ");
+ sb.write(Error.safeToString(value));
+ comma = ', ';
+ });
+ }
+ String memberName = _symbolToString(_memberName);
+ String receiverText = Error.safeToString(_receiver);
+ String actualParameters = '$sb';
+ var failureMessage = (_invocation is dart.InvocationImpl)
+ ? (_invocation as dart.InvocationImpl).failureMessage
+ : 'method not found';
+ if (_existingArgumentNames == null) {
+ return "NoSuchMethodError: '$memberName'\n"
+ "$failureMessage\n"
+ "Receiver: ${receiverText}\n"
+ "Arguments: [$actualParameters]";
+ } else {
+ String formalParameters = _existingArgumentNames.join(', ');
+ return "NoSuchMethodError: incorrect number of arguments passed to "
+ "method named '$memberName'\n"
+ "Receiver: ${receiverText}\n"
+ "Tried calling: $memberName($actualParameters)\n"
+ "Found: $memberName($formalParameters)";
+ }
+ }
+}
+
+@patch
+class Uri {
+ @patch
+ static Uri get base {
+ String uri = Primitives.currentUri();
+ if (uri != null) return Uri.parse(uri);
+ throw UnsupportedError("'Uri.base' is not supported");
+ }
+}
+
+@patch
+class _Uri {
+ @patch
+ static bool get _isWindows => _isWindowsCached;
+
+ static final bool _isWindowsCached = JS(
+ 'bool',
+ 'typeof process != "undefined" && '
+ 'Object.prototype.toString.call(process) == "[object process]" && '
+ 'process.platform == "win32"');
+
+ // Matches a String that _uriEncodes to itself regardless of the kind of
+ // component. This corresponds to [_unreservedTable], i.e. characters that
+ // are not encoded by any encoding table.
+ static final RegExp _needsNoEncoding = RegExp(r'^[\-\.0-9A-Z_a-z~]*$');
+
+ /**
+ * This is the internal implementation of JavaScript's encodeURI function.
+ * It encodes all characters in the string [text] except for those
+ * that appear in [canonicalTable], and returns the escaped string.
+ */
+ @patch
+ static String _uriEncode(List<int> canonicalTable, String text,
+ Encoding encoding, bool spaceToPlus) {
+ if (identical(encoding, utf8) && _needsNoEncoding.hasMatch(text)) {
+ return text;
+ }
+
+ // Encode the string into bytes then generate an ASCII only string
+ // by percent encoding selected bytes.
+ StringBuffer result = StringBuffer('');
+ var bytes = encoding.encode(text);
+ for (int i = 0; i < bytes.length; i++) {
+ int byte = bytes[i];
+ if (byte < 128 &&
+ ((canonicalTable[byte >> 4] & (1 << (byte & 0x0f))) != 0)) {
+ result.writeCharCode(byte);
+ } else if (spaceToPlus && byte == _SPACE) {
+ result.write('+');
+ } else {
+ const String hexDigits = '0123456789ABCDEF';
+ result.write('%');
+ result.write(hexDigits[(byte >> 4) & 0x0f]);
+ result.write(hexDigits[byte & 0x0f]);
+ }
+ }
+ return result.toString();
+ }
+}
+
+@patch
+class StackTrace {
+ @patch
+ @NoInline()
+ static StackTrace get current {
+ return dart.stackTrace(JS('', 'Error()'));
+ }
+}
+
+// TODO(jmesserly): this class is supposed to be obsolete in Strong Mode, but
+// the front-end crashes without it
+class _DuplicatedFieldInitializerError {
+ final String _name;
+
+ _DuplicatedFieldInitializerError(this._name);
+
+ toString() => "Error: field '$_name' is already initialized.";
+}
+
+// TODO(jmesserly): The rest of this core_patch.dart source should reside in an
+// included part file instead of being inlined. However, part files are not
+// properly supported here.
+
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// part of dart.core;
+
+int _max(int a, int b) => a > b ? a : b;
+int _min(int a, int b) => a < b ? a : b;
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Copyright (c) 2003-2005 Tom Wu
+ * Copyright (c) 2012 Adam Singer (adam@solvr.io)
+ * All Rights Reserved.
+ *
+ * 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" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following condition applies:
+ *
+ * All redistributions must retain an intact copy of this copyright notice
+ * and disclaimer.
+ */
+
+/**
+ * An implementation for the arbitrarily large integer.
+ *
+ * The integer number is represented by a sign, an array of 16-bit unsigned
+ * integers in little endian format, and a number of used digits in that array.
+ */
+class _BigIntImpl implements BigInt {
+ // Bits per digit.
+ static const int _digitBits = 16;
+ static const int _digitBase = 1 << _digitBits;
+ static const int _digitMask = (1 << _digitBits) - 1;
+
+ static final _BigIntImpl zero = _BigIntImpl._fromInt(0);
+ static final _BigIntImpl one = _BigIntImpl._fromInt(1);
+ static final _BigIntImpl two = _BigIntImpl._fromInt(2);
+
+ static final _BigIntImpl _minusOne = -one;
+ static final _BigIntImpl _bigInt10000 = _BigIntImpl._fromInt(10000);
+
+ // Result cache for last _divRem call.
+ // Result cache for last _divRem call.
+ static Uint16List _lastDividendDigits;
+ static int _lastDividendUsed;
+ static Uint16List _lastDivisorDigits;
+ static int _lastDivisorUsed;
+ static Uint16List _lastQuoRemDigits;
+ static int _lastQuoRemUsed;
+ static int _lastRemUsed;
+ static int _lastRem_nsh;
+
+ /// Whether this bigint is negative.
+ final bool _isNegative;
+
+ /// The unsigned digits of this bigint.
+ ///
+ /// The least significant digit is in slot 0.
+ /// The list may have more digits than needed. That is, `_digits.length` may
+ /// be strictly greater than `_used`.
+ final Uint16List _digits;
+
+ /// The number of used entries in [_digits].
+ ///
+ /// To avoid reallocating [Uint16List]s, lists that are too big are not
+ /// replaced.
+ final int _used;
+
+ /**
+ * Parses [source] as a, possibly signed, integer literal and returns its
+ * value.
+ *
+ * The [source] must be a non-empty sequence of base-[radix] digits,
+ * optionally prefixed with a minus or plus sign ('-' or '+').
+ *
+ * The [radix] must be in the range 2..36. The digits used are
+ * first the decimal digits 0..9, and then the letters 'a'..'z' with
+ * values 10 through 35. Also accepts upper-case letters with the same
+ * values as the lower-case ones.
+ *
+ * If no [radix] is given then it defaults to 10. In this case, the [source]
+ * digits may also start with `0x`, in which case the number is interpreted
+ * as a hexadecimal literal, which effectively means that the `0x` is ignored
+ * and the radix is instead set to 16.
+ *
+ * For any int `n` and radix `r`, it is guaranteed that
+ * `n == int.parse(n.toRadixString(r), radix: r)`.
+ *
+ * Throws a [FormatException] if the [source] is not a valid integer literal,
+ * optionally prefixed by a sign.
+ */
+ static _BigIntImpl parse(String source, {int radix}) {
+ var result = _tryParse(source, radix: radix);
+ if (result == null) {
+ throw FormatException("Could not parse BigInt", source);
+ }
+ return result;
+ }
+
+ /// Parses a decimal bigint literal.
+ ///
+ /// The [source] must not contain leading or trailing whitespace.
+ static _BigIntImpl _parseDecimal(String source, bool isNegative) {
+ const _0 = 48;
+
+ int part = 0;
+ _BigIntImpl result = zero;
+ // Read in the source 4 digits at a time.
+ // The first part may have a few leading virtual '0's to make the remaining
+ // parts all have exactly 4 digits.
+ int digitInPartCount = 4 - source.length.remainder(4);
+ if (digitInPartCount == 4) digitInPartCount = 0;
+ for (int i = 0; i < source.length; i++) {
+ part = part * 10 + source.codeUnitAt(i) - _0;
+ if (++digitInPartCount == 4) {
+ result = result * _bigInt10000 + _BigIntImpl._fromInt(part);
+ part = 0;
+ digitInPartCount = 0;
+ }
+ }
+ if (isNegative) return -result;
+ return result;
+ }
+
+ /// Returns the value of a given source digit.
+ ///
+ /// Source digits between "0" and "9" (inclusive) return their decimal value.
+ ///
+ /// Source digits between "a" and "z", or "A" and "Z" (inclusive) return
+ /// 10 + their position in the ASCII alphabet.
+ ///
+ /// The incoming [codeUnit] must be an ASCII code-unit.
+ static int _codeUnitToRadixValue(int codeUnit) {
+ // We know that the characters must be ASCII as otherwise the
+ // regexp wouldn't have matched. Lowercasing by doing `| 0x20` is thus
+ // guaranteed to be a safe operation, since it preserves digits
+ // and lower-cases ASCII letters.
+ const int _0 = 48;
+ const int _9 = 57;
+ const int _a = 97;
+ if (_0 <= codeUnit && codeUnit <= _9) return codeUnit - _0;
+ codeUnit |= 0x20;
+ var result = codeUnit - _a + 10;
+ return result;
+ }
+
+ /// Parses the given [source] string, starting at [startPos], as a hex
+ /// literal.
+ ///
+ /// If [isNegative] is true, negates the result before returning it.
+ ///
+ /// The [source] (substring) must be a valid hex literal.
+ static _BigIntImpl _parseHex(String source, int startPos, bool isNegative) {
+ int hexDigitsPerChunk = _digitBits ~/ 4;
+ int sourceLength = source.length - startPos;
+ int chunkCount = (sourceLength / hexDigitsPerChunk).ceil();
+ var digits = Uint16List(chunkCount);
+
+ int lastDigitLength = sourceLength - (chunkCount - 1) * hexDigitsPerChunk;
+ int digitIndex = digits.length - 1;
+ int i = startPos;
+ int chunk = 0;
+ for (int j = 0; j < lastDigitLength; j++) {
+ var digitValue = _codeUnitToRadixValue(source.codeUnitAt(i++));
+ if (digitValue >= 16) return null;
+ chunk = chunk * 16 + digitValue;
+ }
+ digits[digitIndex--] = chunk;
+
+ while (i < source.length) {
+ chunk = 0;
+ for (int j = 0; j < hexDigitsPerChunk; j++) {
+ var digitValue = _codeUnitToRadixValue(source.codeUnitAt(i++));
+ if (digitValue >= 16) return null;
+ chunk = chunk * 16 + digitValue;
+ }
+ digits[digitIndex--] = chunk;
+ }
+ if (digits.length == 1 && digits[0] == 0) return zero;
+ return _BigIntImpl._(isNegative, digits.length, digits);
+ }
+
+ /// Parses the given [source] as a [radix] literal.
+ ///
+ /// The [source] will be checked for invalid characters. If it is invalid,
+ /// this function returns `null`.
+ static _BigIntImpl _parseRadix(String source, int radix, bool isNegative) {
+ var result = zero;
+ var base = _BigIntImpl._fromInt(radix);
+ for (int i = 0; i < source.length; i++) {
+ var digitValue = _codeUnitToRadixValue(source.codeUnitAt(i));
+ if (digitValue >= radix) return null;
+ result = result * base + _BigIntImpl._fromInt(digitValue);
+ }
+ if (isNegative) return -result;
+ return result;
+ }
+
+ /// Tries to parse the given [source] as a [radix] literal.
+ ///
+ /// Returns the parsed big integer, or `null` if it failed.
+ ///
+ /// If the [radix] is `null` accepts decimal literals or `0x` hex literals.
+ static _BigIntImpl _tryParse(String source, {int radix}) {
+ if (source == "") return null;
+
+ var re = RegExp(r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
+ caseSensitive: false);
+ var match = re.firstMatch(source);
+ int signIndex = 1;
+ int hexIndex = 3;
+ int decimalIndex = 4;
+ int nonDecimalHexIndex = 5;
+ if (match == null) return null;
+
+ bool isNegative = match[signIndex] == "-";
+
+ String decimalMatch = match[decimalIndex];
+ String hexMatch = match[hexIndex];
+ String nonDecimalMatch = match[nonDecimalHexIndex];
+
+ if (radix == null) {
+ if (decimalMatch != null) {
+ // Cannot fail because we know that the digits are all decimal.
+ return _parseDecimal(decimalMatch, isNegative);
+ }
+ if (hexMatch != null) {
+ // Cannot fail because we know that the digits are all hex.
+ return _parseHex(hexMatch, 2, isNegative);
+ }
+ return null;
+ }
+
+ if (radix is! int) {
+ throw ArgumentError.value(radix, 'radix', 'is not an integer');
+ }
+ if (radix < 2 || radix > 36) {
+ throw RangeError.range(radix, 2, 36, 'radix');
+ }
+ if (radix == 10 && decimalMatch != null) {
+ return _parseDecimal(decimalMatch, isNegative);
+ }
+ if (radix == 16 && (decimalMatch != null || nonDecimalMatch != null)) {
+ return _parseHex(decimalMatch ?? nonDecimalMatch, 0, isNegative);
+ }
+
+ return _parseRadix(
+ decimalMatch ?? nonDecimalMatch ?? hexMatch, radix, isNegative);
+ }
+
+ /// Finds the amount significant digits in the provided [digits] array.
+ static int _normalize(int used, Uint16List digits) {
+ while (used > 0 && digits[used - 1] == 0) used--;
+ return used;
+ }
+
+ /// Factory returning an instance initialized with the given field values.
+ /// If the [digits] array contains leading 0s, the [used] value is adjusted
+ /// accordingly. The [digits] array is not modified.
+ _BigIntImpl._(bool isNegative, int used, Uint16List digits)
+ : this._normalized(isNegative, _normalize(used, digits), digits);
+
+ _BigIntImpl._normalized(bool isNegative, this._used, this._digits)
+ : _isNegative = _used == 0 ? false : isNegative;
+
+ /// Whether this big integer is zero.
+ bool get _isZero => _used == 0;
+
+ /// Allocates an array of the given [length] and copies the [digits] in the
+ /// range [from] to [to-1], starting at index 0, followed by leading zero
+ /// digits.
+ static Uint16List _cloneDigits(
+ Uint16List digits, int from, int to, int length) {
+ var resultDigits = Uint16List(length);
+ var n = to - from;
+ for (var i = 0; i < n; i++) {
+ resultDigits[i] = digits[from + i];
+ }
+ return resultDigits;
+ }
+
+ /// Allocates a big integer from the provided [value] number.
+ factory _BigIntImpl.from(num value) {
+ if (value == 0) return zero;
+ if (value == 1) return one;
+ if (value == 2) return two;
+
+ // Given this order dart2js will use the `_fromInt` for smaller value and
+ // then use the bit-manipulating `_fromDouble` for all other values.
+ if (value.abs() < 0x100000000) return _BigIntImpl._fromInt(value.toInt());
+ if (value is double) return _BigIntImpl._fromDouble(value);
+ return _BigIntImpl._fromInt(value);
+ }
+
+ factory _BigIntImpl._fromInt(int value) {
+ bool isNegative = value < 0;
+ assert(_digitBits == 16);
+ if (isNegative) {
+ // Handle the min 64-bit value differently, since its negation is not
+ // positive.
+ const int minInt64 = -0x80000000 * 0x100000000;
+ if (value == minInt64) {
+ var digits = Uint16List(4);
+ digits[3] = 0x8000;
+ return _BigIntImpl._(true, 4, digits);
+ }
+ value = -value;
+ }
+ if (value < _digitBase) {
+ var digits = Uint16List(1);
+ digits[0] = value;
+ return _BigIntImpl._(isNegative, 1, digits);
+ }
+ if (value <= 0xFFFFFFFF) {
+ var digits = Uint16List(2);
+ digits[0] = value & _digitMask;
+ digits[1] = value >> _digitBits;
+ return _BigIntImpl._(isNegative, 2, digits);
+ }
+
+ var bits = value.bitLength;
+ var digits = Uint16List((bits - 1) ~/ _digitBits + 1);
+ var i = 0;
+ while (value != 0) {
+ digits[i++] = value & _digitMask;
+ value = value ~/ _digitBase;
+ }
+ return _BigIntImpl._(isNegative, digits.length, digits);
+ }
+
+ /// An 8-byte Uint8List we can reuse for [_fromDouble] to avoid generating
+ /// garbage.
+ static final Uint8List _bitsForFromDouble = Uint8List(8);
+
+ factory _BigIntImpl._fromDouble(double value) {
+ const int exponentBias = 1075;
+
+ if (value.isNaN || value.isInfinite) {
+ throw ArgumentError("Value must be finite: $value");
+ }
+ bool isNegative = value < 0;
+ if (isNegative) value = -value;
+
+ value = value.floorToDouble();
+ if (value == 0) return zero;
+
+ var bits = _bitsForFromDouble;
+ for (int i = 0; i < 8; i++) {
+ bits[i] = 0;
+ }
+ bits.buffer.asByteData().setFloat64(0, value, Endian.little);
+ // The exponent is in bits 53..63.
+ var biasedExponent = (bits[7] << 4) + (bits[6] >> 4);
+ var exponent = biasedExponent - exponentBias;
+
+ assert(_digitBits == 16);
+ // The significant bits are in 0 .. 52.
+ var unshiftedDigits = Uint16List(4);
+ unshiftedDigits[0] = (bits[1] << 8) + bits[0];
+ unshiftedDigits[1] = (bits[3] << 8) + bits[2];
+ unshiftedDigits[2] = (bits[5] << 8) + bits[4];
+ // Don't forget to add the hidden bit.
+ unshiftedDigits[3] = 0x10 | (bits[6] & 0xF);
+
+ var unshiftedBig = _BigIntImpl._normalized(false, 4, unshiftedDigits);
+ _BigIntImpl absResult = unshiftedBig;
+ if (exponent < 0) {
+ absResult = unshiftedBig >> -exponent;
+ } else if (exponent > 0) {
+ absResult = unshiftedBig << exponent;
+ }
+ if (isNegative) return -absResult;
+ return absResult;
+ }
+
+ /**
+ * Return the negative value of this integer.
+ *
+ * The result of negating an integer always has the opposite sign, except
+ * for zero, which is its own negation.
+ */
+ _BigIntImpl operator -() {
+ if (_used == 0) return this;
+ return _BigIntImpl._(!_isNegative, _used, _digits);
+ }
+
+ /**
+ * Returns the absolute value of this integer.
+ *
+ * For any integer `x`, the result is the same as `x < 0 ? -x : x`.
+ */
+ _BigIntImpl abs() => _isNegative ? -this : this;
+
+ /// Returns this << n *_DIGIT_BITS.
+ _BigIntImpl _dlShift(int n) {
+ final used = _used;
+ if (used == 0) {
+ return zero;
+ }
+ final resultUsed = used + n;
+ final digits = _digits;
+ final resultDigits = Uint16List(resultUsed);
+ for (int i = used - 1; i >= 0; i--) {
+ resultDigits[i + n] = digits[i];
+ }
+ return _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+ }
+
+ /// Same as [_dlShift] but works on the decomposed big integers.
+ ///
+ /// Returns `resultUsed`.
+ ///
+ /// `resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] << n*_DIGIT_BITS`.
+ static int _dlShiftDigits(
+ Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+ if (xUsed == 0) {
+ return 0;
+ }
+ if (n == 0 && identical(resultDigits, xDigits)) {
+ return xUsed;
+ }
+ final resultUsed = xUsed + n;
+ for (int i = xUsed - 1; i >= 0; i--) {
+ resultDigits[i + n] = xDigits[i];
+ }
+ for (int i = n - 1; i >= 0; i--) {
+ resultDigits[i] = 0;
+ }
+ return resultUsed;
+ }
+
+ /// Returns `this >> n*_DIGIT_BITS`.
+ _BigIntImpl _drShift(int n) {
+ final used = _used;
+ if (used == 0) {
+ return zero;
+ }
+ final resultUsed = used - n;
+ if (resultUsed <= 0) {
+ return _isNegative ? _minusOne : zero;
+ }
+ final digits = _digits;
+ final resultDigits = Uint16List(resultUsed);
+ for (var i = n; i < used; i++) {
+ resultDigits[i - n] = digits[i];
+ }
+ final result = _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+ if (_isNegative) {
+ // Round down if any bit was shifted out.
+ for (var i = 0; i < n; i++) {
+ if (digits[i] != 0) {
+ return result - one;
+ }
+ }
+ }
+ return result;
+ }
+
+ /// Shifts the digits of [xDigits] into the right place in [resultDigits].
+ ///
+ /// `resultDigits[ds..xUsed+ds] = xDigits[0..xUsed-1] << (n % _DIGIT_BITS)`
+ /// where `ds = n ~/ _DIGIT_BITS`
+ ///
+ /// Does *not* clear digits below ds.
+ static void _lsh(
+ Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+ assert(xUsed > 0);
+ final digitShift = n ~/ _digitBits;
+ final bitShift = n % _digitBits;
+ final carryBitShift = _digitBits - bitShift;
+ final bitMask = (1 << carryBitShift) - 1;
+ var carry = 0;
+ for (int i = xUsed - 1; i >= 0; i--) {
+ final digit = xDigits[i];
+ resultDigits[i + digitShift + 1] = (digit >> carryBitShift) | carry;
+ carry = (digit & bitMask) << bitShift;
+ }
+ resultDigits[digitShift] = carry;
+ }
+
+ /**
+ * Shift the bits of this integer to the left by [shiftAmount].
+ *
+ * Shifting to the left makes the number larger, effectively multiplying
+ * the number by `pow(2, shiftIndex)`.
+ *
+ * There is no limit on the size of the result. It may be relevant to
+ * limit intermediate values by using the "and" operator with a suitable
+ * mask.
+ *
+ * It is an error if [shiftAmount] is negative.
+ */
+ _BigIntImpl operator <<(int shiftAmount) {
+ if (shiftAmount < 0) {
+ throw ArgumentError("shift-amount must be posititve $shiftAmount");
+ }
+ if (_isZero) return this;
+ final digitShift = shiftAmount ~/ _digitBits;
+ final bitShift = shiftAmount % _digitBits;
+ if (bitShift == 0) {
+ return _dlShift(digitShift);
+ }
+ var resultUsed = _used + digitShift + 1;
+ var resultDigits = Uint16List(resultUsed);
+ _lsh(_digits, _used, shiftAmount, resultDigits);
+ return _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+ }
+
+ // resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] << n.
+ // Returns resultUsed.
+ static int _lShiftDigits(
+ Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+ final digitsShift = n ~/ _digitBits;
+ final bitShift = n % _digitBits;
+ if (bitShift == 0) {
+ return _dlShiftDigits(xDigits, xUsed, digitsShift, resultDigits);
+ }
+ var resultUsed = xUsed + digitsShift + 1;
+ _lsh(xDigits, xUsed, n, resultDigits);
+ var i = digitsShift;
+ while (--i >= 0) {
+ resultDigits[i] = 0;
+ }
+ if (resultDigits[resultUsed - 1] == 0) {
+ resultUsed--; // Clamp result.
+ }
+ return resultUsed;
+ }
+
+ // resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] >> n.
+ static void _rsh(
+ Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+ assert(xUsed > 0);
+ final digitsShift = n ~/ _digitBits;
+ final bitShift = n % _digitBits;
+ final carryBitShift = _digitBits - bitShift;
+ final bitMask = (1 << bitShift) - 1;
+ var carry = xDigits[digitsShift] >> bitShift;
+ final last = xUsed - digitsShift - 1;
+ for (var i = 0; i < last; i++) {
+ final digit = xDigits[i + digitsShift + 1];
+ resultDigits[i] = ((digit & bitMask) << carryBitShift) | carry;
+ carry = digit >> bitShift;
+ }
+ resultDigits[last] = carry;
+ }
+
+ /**
+ * Shift the bits of this integer to the right by [shiftAmount].
+ *
+ * Shifting to the right makes the number smaller and drops the least
+ * significant bits, effectively doing an integer division by
+ *`pow(2, shiftIndex)`.
+ *
+ * It is an error if [shiftAmount] is negative.
+ */
+ _BigIntImpl operator >>(int shiftAmount) {
+ if (shiftAmount < 0) {
+ throw ArgumentError("shift-amount must be posititve $shiftAmount");
+ }
+ if (_isZero) return this;
+ final digitShift = shiftAmount ~/ _digitBits;
+ final bitShift = shiftAmount % _digitBits;
+ if (bitShift == 0) {
+ return _drShift(digitShift);
+ }
+ final used = _used;
+ final resultUsed = used - digitShift;
+ if (resultUsed <= 0) {
+ return _isNegative ? _minusOne : zero;
+ }
+ final digits = _digits;
+ final resultDigits = Uint16List(resultUsed);
+ _rsh(digits, used, shiftAmount, resultDigits);
+ final result = _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+ if (_isNegative) {
+ // Round down if any bit was shifted out.
+ if ((digits[digitShift] & ((1 << bitShift) - 1)) != 0) {
+ return result - one;
+ }
+ for (var i = 0; i < digitShift; i++) {
+ if (digits[i] != 0) {
+ return result - one;
+ }
+ }
+ }
+ return result;
+ }
+
+ /// Compares this to [other] taking the absolute value of both operands.
+ ///
+ /// Returns 0 if abs(this) == abs(other); a positive number if
+ /// abs(this) > abs(other); and a negative number if abs(this) < abs(other).
+ int _absCompare(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ return _compareDigits(_digits, _used, other._digits, other._used);
+ }
+
+ /**
+ * Compares this to `other`.
+ *
+ * Returns a negative number if `this` is less than `other`, zero if they are
+ * equal, and a positive number if `this` is greater than `other`.
+ */
+ int compareTo(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isNegative == other._isNegative) {
+ var result = _absCompare(other);
+ // Use 0 - result to avoid negative zero in JavaScript.
+ return _isNegative ? 0 - result : result;
+ }
+ return _isNegative ? -1 : 1;
+ }
+
+ /// Compares `digits[0..used-1]` with `otherDigits[0..otherUsed-1]`.
+ ///
+ /// Returns 0 if equal; a positive number if larger;
+ /// and a negative number if smaller.
+ static int _compareDigits(
+ Uint16List digits, int used, Uint16List otherDigits, int otherUsed) {
+ var result = used - otherUsed;
+ if (result == 0) {
+ for (int i = used - 1; i >= 0; i--) {
+ result = digits[i] - otherDigits[i];
+ if (result != 0) return result;
+ }
+ }
+ return result;
+ }
+
+ // resultDigits[0..used] = digits[0..used-1] + otherDigits[0..otherUsed-1].
+ // used >= otherUsed > 0.
+ static void _absAdd(Uint16List digits, int used, Uint16List otherDigits,
+ int otherUsed, Uint16List resultDigits) {
+ assert(used >= otherUsed && otherUsed > 0);
+ var carry = 0;
+ for (var i = 0; i < otherUsed; i++) {
+ carry += digits[i] + otherDigits[i];
+ resultDigits[i] = carry & _digitMask;
+ carry >>= _digitBits;
+ }
+ for (var i = otherUsed; i < used; i++) {
+ carry += digits[i];
+ resultDigits[i] = carry & _digitMask;
+ carry >>= _digitBits;
+ }
+ resultDigits[used] = carry;
+ }
+
+ // resultDigits[0..used-1] = digits[0..used-1] - otherDigits[0..otherUsed-1].
+ // used >= otherUsed > 0.
+ static void _absSub(Uint16List digits, int used, Uint16List otherDigits,
+ int otherUsed, Uint16List resultDigits) {
+ assert(used >= otherUsed && otherUsed > 0);
+
+ var carry = 0;
+ for (var i = 0; i < otherUsed; i++) {
+ carry += digits[i] - otherDigits[i];
+ resultDigits[i] = carry & _digitMask;
+ // Dart2js only supports unsigned shifts.
+ // Since the carry can only be -1 or 0 use this hack.
+ carry = 0 - ((carry >> _digitBits) & 1);
+ }
+ for (var i = otherUsed; i < used; i++) {
+ carry += digits[i];
+ resultDigits[i] = carry & _digitMask;
+ // Dart2js only supports unsigned shifts.
+ // Since the carry can only be -1 or 0 use this hack.
+ carry = 0 - ((carry >> _digitBits) & 1);
+ }
+ }
+
+ /// Returns `abs(this) + abs(other)` with sign set according to [isNegative].
+ _BigIntImpl _absAddSetSign(_BigIntImpl other, bool isNegative) {
+ var used = _used;
+ var otherUsed = other._used;
+ if (used < otherUsed) {
+ return other._absAddSetSign(this, isNegative);
+ }
+ if (used == 0) {
+ assert(!isNegative);
+ return zero;
+ }
+ if (otherUsed == 0) {
+ return _isNegative == isNegative ? this : -this;
+ }
+ var resultUsed = used + 1;
+ var resultDigits = Uint16List(resultUsed);
+ _absAdd(_digits, used, other._digits, otherUsed, resultDigits);
+ return _BigIntImpl._(isNegative, resultUsed, resultDigits);
+ }
+
+ /// Returns `abs(this) - abs(other)` with sign set according to [isNegative].
+ ///
+ /// Requirement: `abs(this) >= abs(other)`.
+ _BigIntImpl _absSubSetSign(_BigIntImpl other, bool isNegative) {
+ assert(_absCompare(other) >= 0);
+ var used = _used;
+ if (used == 0) {
+ assert(!isNegative);
+ return zero;
+ }
+ var otherUsed = other._used;
+ if (otherUsed == 0) {
+ return _isNegative == isNegative ? this : -this;
+ }
+ var resultDigits = Uint16List(used);
+ _absSub(_digits, used, other._digits, otherUsed, resultDigits);
+ return _BigIntImpl._(isNegative, used, resultDigits);
+ }
+
+ /// Returns `abs(this) & abs(other)` with sign set according to [isNegative].
+ _BigIntImpl _absAndSetSign(_BigIntImpl other, bool isNegative) {
+ var resultUsed = _min(_used, other._used);
+ var digits = _digits;
+ var otherDigits = other._digits;
+ var resultDigits = Uint16List(resultUsed);
+ for (var i = 0; i < resultUsed; i++) {
+ resultDigits[i] = digits[i] & otherDigits[i];
+ }
+ return _BigIntImpl._(isNegative, resultUsed, resultDigits);
+ }
+
+ /// Returns `abs(this) &~ abs(other)` with sign set according to [isNegative].
+ _BigIntImpl _absAndNotSetSign(_BigIntImpl other, bool isNegative) {
+ var resultUsed = _used;
+ var digits = _digits;
+ var otherDigits = other._digits;
+ var resultDigits = Uint16List(resultUsed);
+ var m = _min(resultUsed, other._used);
+ for (var i = 0; i < m; i++) {
+ resultDigits[i] = digits[i] & ~otherDigits[i];
+ }
+ for (var i = m; i < resultUsed; i++) {
+ resultDigits[i] = digits[i];
+ }
+ return _BigIntImpl._(isNegative, resultUsed, resultDigits);
+ }
+
+ /// Returns `abs(this) | abs(other)` with sign set according to [isNegative].
+ _BigIntImpl _absOrSetSign(_BigIntImpl other, bool isNegative) {
+ var used = _used;
+ var otherUsed = other._used;
+ var resultUsed = _max(used, otherUsed);
+ var digits = _digits;
+ var otherDigits = other._digits;
+ var resultDigits = Uint16List(resultUsed);
+ var l, m;
+ if (used < otherUsed) {
+ l = other;
+ m = used;
+ } else {
+ l = this;
+ m = otherUsed;
+ }
+ for (var i = 0; i < m; i++) {
+ resultDigits[i] = digits[i] | otherDigits[i];
+ }
+ var lDigits = l._digits;
+ for (var i = m; i < resultUsed; i++) {
+ resultDigits[i] = lDigits[i];
+ }
+ return _BigIntImpl._(isNegative, resultUsed, resultDigits);
+ }
+
+ /// Returns `abs(this) ^ abs(other)` with sign set according to [isNegative].
+ _BigIntImpl _absXorSetSign(_BigIntImpl other, bool isNegative) {
+ var used = _used;
+ var otherUsed = other._used;
+ var resultUsed = _max(used, otherUsed);
+ var digits = _digits;
+ var otherDigits = other._digits;
+ var resultDigits = Uint16List(resultUsed);
+ var l, m;
+ if (used < otherUsed) {
+ l = other;
+ m = used;
+ } else {
+ l = this;
+ m = otherUsed;
+ }
+ for (var i = 0; i < m; i++) {
+ resultDigits[i] = digits[i] ^ otherDigits[i];
+ }
+ var lDigits = l._digits;
+ for (var i = m; i < resultUsed; i++) {
+ resultDigits[i] = lDigits[i];
+ }
+ return _BigIntImpl._(isNegative, resultUsed, resultDigits);
+ }
+
+ /**
+ * Bit-wise and operator.
+ *
+ * Treating both `this` and [other] as sufficiently large two's component
+ * integers, the result is a number with only the bits set that are set in
+ * both `this` and [other]
+ *
+ * Of both operands are negative, the result is negative, otherwise
+ * the result is non-negative.
+ */
+ _BigIntImpl operator &(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isZero || other._isZero) return zero;
+ if (_isNegative == other._isNegative) {
+ if (_isNegative) {
+ // (-this) & (-other) == ~(this-1) & ~(other-1)
+ // == ~((this-1) | (other-1))
+ // == -(((this-1) | (other-1)) + 1)
+ _BigIntImpl this1 = _absSubSetSign(one, true);
+ _BigIntImpl other1 = other._absSubSetSign(one, true);
+ // Result cannot be zero if this and other are negative.
+ return this1._absOrSetSign(other1, true)._absAddSetSign(one, true);
+ }
+ return _absAndSetSign(other, false);
+ }
+ // _isNegative != other._isNegative
+ var p, n;
+ if (_isNegative) {
+ p = other;
+ n = this;
+ } else {
+ // & is symmetric.
+ p = this;
+ n = other;
+ }
+ // p & (-n) == p & ~(n-1) == p &~ (n-1)
+ var n1 = n._absSubSetSign(one, false);
+ return p._absAndNotSetSign(n1, false);
+ }
+
+ /**
+ * Bit-wise or operator.
+ *
+ * Treating both `this` and [other] as sufficiently large two's component
+ * integers, the result is a number with the bits set that are set in either
+ * of `this` and [other]
+ *
+ * If both operands are non-negative, the result is non-negative,
+ * otherwise the result us negative.
+ */
+ _BigIntImpl operator |(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isZero) return other;
+ if (other._isZero) return this;
+ if (_isNegative == other._isNegative) {
+ if (_isNegative) {
+ // (-this) | (-other) == ~(this-1) | ~(other-1)
+ // == ~((this-1) & (other-1))
+ // == -(((this-1) & (other-1)) + 1)
+ var this1 = _absSubSetSign(one, true);
+ var other1 = other._absSubSetSign(one, true);
+ // Result cannot be zero if this and a are negative.
+ return this1._absAndSetSign(other1, true)._absAddSetSign(one, true);
+ }
+ return _absOrSetSign(other, false);
+ }
+ // _neg != a._neg
+ var p, n;
+ if (_isNegative) {
+ p = other;
+ n = this;
+ } else {
+ // | is symmetric.
+ p = this;
+ n = other;
+ }
+ // p | (-n) == p | ~(n-1) == ~((n-1) &~ p) == -(~((n-1) &~ p) + 1)
+ var n1 = n._absSubSetSign(one, true);
+ // Result cannot be zero if only one of this or a is negative.
+ return n1._absAndNotSetSign(p, true)._absAddSetSign(one, true);
+ }
+
+ /**
+ * Bit-wise exclusive-or operator.
+ *
+ * Treating both `this` and [other] as sufficiently large two's component
+ * integers, the result is a number with the bits set that are set in one,
+ * but not both, of `this` and [other]
+ *
+ * If the operands have the same sign, the result is non-negative,
+ * otherwise the result is negative.
+ */
+ _BigIntImpl operator ^(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isZero) return other;
+ if (other._isZero) return this;
+ if (_isNegative == other._isNegative) {
+ if (_isNegative) {
+ // (-this) ^ (-other) == ~(this-1) ^ ~(other-1) == (this-1) ^ (other-1)
+ var this1 = _absSubSetSign(one, true);
+ var other1 = other._absSubSetSign(one, true);
+ return this1._absXorSetSign(other1, false);
+ }
+ return _absXorSetSign(other, false);
+ }
+ // _isNegative != a._isNegative
+ var p, n;
+ if (_isNegative) {
+ p = other;
+ n = this;
+ } else {
+ // ^ is symmetric.
+ p = this;
+ n = other;
+ }
+ // p ^ (-n) == p ^ ~(n-1) == ~(p ^ (n-1)) == -((p ^ (n-1)) + 1)
+ var n1 = n._absSubSetSign(one, true);
+ // Result cannot be zero if only one of this or a is negative.
+ return p._absXorSetSign(n1, true)._absAddSetSign(one, true);
+ }
+
+ /**
+ * The bit-wise negate operator.
+ *
+ * Treating `this` as a sufficiently large two's component integer,
+ * the result is a number with the opposite bits set.
+ *
+ * This maps any integer `x` to `-x - 1`.
+ */
+ _BigIntImpl operator ~() {
+ if (_isZero) return _minusOne;
+ if (_isNegative) {
+ // ~(-this) == ~(~(this-1)) == this-1
+ return _absSubSetSign(one, false);
+ }
+ // ~this == -this-1 == -(this+1)
+ // Result cannot be zero if this is positive.
+ return _absAddSetSign(one, true);
+ }
+
+ /// Addition operator.
+ _BigIntImpl operator +(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isZero) return other;
+ if (other._isZero) return this;
+ var isNegative = _isNegative;
+ if (isNegative == other._isNegative) {
+ // this + other == this + other
+ // (-this) + (-other) == -(this + other)
+ return _absAddSetSign(other, isNegative);
+ }
+ // this + (-other) == this - other == -(this - other)
+ // (-this) + other == other - this == -(this - other)
+ if (_absCompare(other) >= 0) {
+ return _absSubSetSign(other, isNegative);
+ }
+ return other._absSubSetSign(this, !isNegative);
+ }
+
+ /// Subtraction operator.
+ _BigIntImpl operator -(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isZero) return -other;
+ if (other._isZero) return this;
+ var isNegative = _isNegative;
+ if (isNegative != other._isNegative) {
+ // this - (-other) == this + other
+ // (-this) - other == -(this + other)
+ return _absAddSetSign(other, isNegative);
+ }
+ // this - other == this - a == -(this - other)
+ // (-this) - (-other) == other - this == -(this - other)
+ if (_absCompare(other) >= 0) {
+ return _absSubSetSign(other, isNegative);
+ }
+ return other._absSubSetSign(this, !isNegative);
+ }
+
+ /// Multiplies [x] with [multiplicandDigits] and adds the result to
+ /// [accumulatorDigits].
+ ///
+ /// The [multiplicandDigits] in the range [i] to [i]+[n]-1 are the
+ /// multiplicand digits.
+ ///
+ /// The [acculumatorDigits] in the range [j] to [j]+[n]-1 are the accumulator
+ /// digits.
+ ///
+ /// Adds the result of the multiplicand-digits * [x] to the accumulator.
+ ///
+ /// Concretely: `accumulatorDigits[j..j+n] += x * m_digits[i..i+n-1]`.
+ static void _mulAdd(int x, Uint16List multiplicandDigits, int i,
+ Uint16List accumulatorDigits, int j, int n) {
+ if (x == 0) {
+ // No-op if x is 0.
+ return;
+ }
+ int c = 0;
+ while (--n >= 0) {
+ int product = x * multiplicandDigits[i++];
+ int combined = product + accumulatorDigits[j] + c;
+ accumulatorDigits[j++] = combined & _digitMask;
+ // Note that this works with 53 bits, as the division will not lose
+ // bits.
+ c = combined ~/ _digitBase;
+ }
+ while (c != 0) {
+ int l = accumulatorDigits[j] + c;
+ accumulatorDigits[j++] = l & _digitMask;
+ c = l ~/ _digitBase;
+ }
+ }
+
+ /// Multiplication operator.
+ _BigIntImpl operator *(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ var used = _used;
+ var otherUsed = other._used;
+ if (used == 0 || otherUsed == 0) {
+ return zero;
+ }
+ var resultUsed = used + otherUsed;
+ var digits = _digits;
+ var otherDigits = other._digits;
+ var resultDigits = Uint16List(resultUsed);
+ var i = 0;
+ while (i < otherUsed) {
+ _mulAdd(otherDigits[i], digits, 0, resultDigits, i, used);
+ i++;
+ }
+ return _BigIntImpl._(
+ _isNegative != other._isNegative, resultUsed, resultDigits);
+ }
+
+ // r_digits[0..rUsed-1] = xDigits[0..xUsed-1]*otherDigits[0..otherUsed-1].
+ // Return resultUsed = xUsed + otherUsed.
+ static int _mulDigits(Uint16List xDigits, int xUsed, Uint16List otherDigits,
+ int otherUsed, Uint16List resultDigits) {
+ var resultUsed = xUsed + otherUsed;
+ var i = resultUsed;
+ assert(resultDigits.length >= i);
+ while (--i >= 0) {
+ resultDigits[i] = 0;
+ }
+ i = 0;
+ while (i < otherUsed) {
+ _mulAdd(otherDigits[i], xDigits, 0, resultDigits, i, xUsed);
+ i++;
+ }
+ return resultUsed;
+ }
+
+ /// Returns an estimate of `digits[i-1..i] ~/ topDigitDivisor`.
+ static int _estimateQuotientDigit(
+ int topDigitDivisor, Uint16List digits, int i) {
+ if (digits[i] == topDigitDivisor) return _digitMask;
+ var quotientDigit =
+ (digits[i] << _digitBits | digits[i - 1]) ~/ topDigitDivisor;
+ if (quotientDigit > _digitMask) return _digitMask;
+ return quotientDigit;
+ }
+
+ /// Returns `trunc(this / other)`, with `other != 0`.
+ _BigIntImpl _div(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ assert(other._used > 0);
+ if (_used < other._used) {
+ return zero;
+ }
+ _divRem(other);
+ // Return quotient, i.e.
+ // _lastQuoRem_digits[_lastRem_used.._lastQuoRem_used-1] with proper sign.
+ var lastQuo_used = _lastQuoRemUsed - _lastRemUsed;
+ var quo_digits = _cloneDigits(
+ _lastQuoRemDigits, _lastRemUsed, _lastQuoRemUsed, lastQuo_used);
+ var quo = _BigIntImpl._(false, lastQuo_used, quo_digits);
+ if ((_isNegative != other._isNegative) && (quo._used > 0)) {
+ quo = -quo;
+ }
+ return quo;
+ }
+
+ /// Returns `this - other * trunc(this / other)`, with `other != 0`.
+ _BigIntImpl _rem(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ assert(other._used > 0);
+ if (_used < other._used) {
+ return this;
+ }
+ _divRem(other);
+ // Return remainder, i.e.
+ // denormalized _lastQuoRem_digits[0.._lastRem_used-1] with proper sign.
+ var remDigits =
+ _cloneDigits(_lastQuoRemDigits, 0, _lastRemUsed, _lastRemUsed);
+ var rem = _BigIntImpl._(false, _lastRemUsed, remDigits);
+ if (_lastRem_nsh > 0) {
+ rem = rem >> _lastRem_nsh; // Denormalize remainder.
+ }
+ if (_isNegative && (rem._used > 0)) {
+ rem = -rem;
+ }
+ return rem;
+ }
+
+ /// Computes this ~/ other and this.remainder(other).
+ ///
+ /// Stores the result in [_lastQuoRemDigits], [_lastQuoRemUsed] and
+ /// [_lastRemUsed]. The [_lastQuoRemDigits] contains the digits of *both*, the
+ /// quotient and the remainder.
+ ///
+ /// Caches the input to avoid doing the work again when users write
+ /// `a ~/ b` followed by a `a % b`.
+ void _divRem(_BigIntImpl other) {
+ // Check if result is already cached.
+ if ((this._used == _lastDividendUsed) &&
+ (other._used == _lastDivisorUsed) &&
+ identical(this._digits, _lastDividendDigits) &&
+ identical(other._digits, _lastDivisorDigits)) {
+ return;
+ }
+ assert(_used >= other._used);
+
+ var nsh = _digitBits - other._digits[other._used - 1].bitLength;
+ // Concatenated positive quotient and normalized positive remainder.
+ // The resultDigits can have at most one more digit than the dividend.
+ Uint16List resultDigits;
+ int resultUsed;
+ // Normalized positive divisor.
+ // The normalized divisor has the most-significant bit of its most
+ // significant digit set.
+ // This makes estimating the quotient easier.
+ Uint16List yDigits;
+ int yUsed;
+ if (nsh > 0) {
+ yDigits = Uint16List(other._used + 5);
+ yUsed = _lShiftDigits(other._digits, other._used, nsh, yDigits);
+ resultDigits = Uint16List(_used + 5);
+ resultUsed = _lShiftDigits(_digits, _used, nsh, resultDigits);
+ } else {
+ yDigits = other._digits;
+ yUsed = other._used;
+ resultDigits = _cloneDigits(_digits, 0, _used, _used + 2);
+ resultUsed = _used;
+ }
+ var topDigitDivisor = yDigits[yUsed - 1];
+ var i = resultUsed;
+ var j = i - yUsed;
+ // tmpDigits is a temporary array of i (resultUsed) digits.
+ var tmpDigits = Uint16List(i);
+ var tmpUsed = _dlShiftDigits(yDigits, yUsed, j, tmpDigits);
+ // Explicit first division step in case normalized dividend is larger or
+ // equal to shifted normalized divisor.
+ if (_compareDigits(resultDigits, resultUsed, tmpDigits, tmpUsed) >= 0) {
+ assert(i == resultUsed);
+ resultDigits[resultUsed++] = 1; // Quotient = 1.
+ // Subtract divisor from remainder.
+ _absSub(resultDigits, resultUsed, tmpDigits, tmpUsed, resultDigits);
+ } else {
+ // Account for possible carry in _mulAdd step.
+ resultDigits[resultUsed++] = 0;
+ }
+
+ // Negate y so we can later use _mulAdd instead of non-existent _mulSub.
+ var nyDigits = Uint16List(yUsed + 2);
+ nyDigits[yUsed] = 1;
+ _absSub(nyDigits, yUsed + 1, yDigits, yUsed, nyDigits);
+ // nyDigits is read-only and has yUsed digits (possibly including several
+ // leading zeros).
+ // resultDigits is modified during iteration.
+ // resultDigits[0..yUsed-1] is the current remainder.
+ // resultDigits[yUsed..resultUsed-1] is the current quotient.
+ --i;
+
+ while (j > 0) {
+ var estimatedQuotientDigit =
+ _estimateQuotientDigit(topDigitDivisor, resultDigits, i);
+ j--;
+ _mulAdd(estimatedQuotientDigit, nyDigits, 0, resultDigits, j, yUsed);
+ if (resultDigits[i] < estimatedQuotientDigit) {
+ // Reusing the already existing tmpDigits array.
+ var tmpUsed = _dlShiftDigits(nyDigits, yUsed, j, tmpDigits);
+ _absSub(resultDigits, resultUsed, tmpDigits, tmpUsed, resultDigits);
+ while (resultDigits[i] < --estimatedQuotientDigit) {
+ _absSub(resultDigits, resultUsed, tmpDigits, tmpUsed, resultDigits);
+ }
+ }
+ i--;
+ }
+ // Cache result.
+ _lastDividendDigits = _digits;
+ _lastDividendUsed = _used;
+ _lastDivisorDigits = other._digits;
+ _lastDivisorUsed = other._used;
+ _lastQuoRemDigits = resultDigits;
+ _lastQuoRemUsed = resultUsed;
+ _lastRemUsed = yUsed;
+ _lastRem_nsh = nsh;
+ }
+
+ int get hashCode {
+ // This is the [Jenkins hash function][1] but using masking to keep
+ // values in SMI range.
+ //
+ // [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+
+ int combine(int hash, int value) {
+ hash = 0x1fffffff & (hash + value);
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+ return hash ^ (hash >> 6);
+ }
+
+ int finish(int hash) {
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+ hash = hash ^ (hash >> 11);
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+ }
+
+ if (_isZero) return 6707; // Just a random number.
+ var hash = _isNegative ? 83585 : 429689; // Also random.
+ for (int i = 0; i < _used; i++) {
+ hash = combine(hash, _digits[i]);
+ }
+ return finish(hash);
+ }
+
+ /**
+ * Test whether this value is numerically equal to `other`.
+ *
+ * If [other] is a [_BigIntImpl] returns whether the two operands have the same
+ * value.
+ *
+ * Returns false if `other` is not a [_BigIntImpl].
+ */
+ bool operator ==(Object other) =>
+ other is _BigIntImpl && compareTo(other) == 0;
+
+ /**
+ * Returns the minimum number of bits required to store this big integer.
+ *
+ * The number of bits excludes the sign bit, which gives the natural length
+ * for non-negative (unsigned) values. Negative values are complemented to
+ * return the bit position of the first bit that differs from the sign bit.
+ *
+ * To find the number of bits needed to store the value as a signed value,
+ * add one, i.e. use `x.bitLength + 1`.
+ *
+ * ```
+ * x.bitLength == (-x-1).bitLength
+ *
+ * new BigInt.from(3).bitLength == 2; // 00000011
+ * new BigInt.from(2).bitLength == 2; // 00000010
+ * new BigInt.from(1).bitLength == 1; // 00000001
+ * new BigInt.from(0).bitLength == 0; // 00000000
+ * new BigInt.from(-1).bitLength == 0; // 11111111
+ * new BigInt.from(-2).bitLength == 1; // 11111110
+ * new BigInt.from(-3).bitLength == 2; // 11111101
+ * new BigInt.from(-4).bitLength == 2; // 11111100
+ * ```
+ */
+ int get bitLength {
+ if (_used == 0) return 0;
+ if (_isNegative) return (~this).bitLength;
+ return _digitBits * (_used - 1) + _digits[_used - 1].bitLength;
+ }
+
+ /**
+ * Truncating division operator.
+ *
+ * Performs a truncating integer division, where the remainder is discarded.
+ *
+ * The remainder can be computed using the [remainder] method.
+ *
+ * Examples:
+ * ```
+ * var seven = new BigInt.from(7);
+ * var three = new BigInt.from(3);
+ * seven ~/ three; // => 2
+ * (-seven) ~/ three; // => -2
+ * seven ~/ -three; // => -2
+ * seven.remainder(three); // => 1
+ * (-seven).remainder(three); // => -1
+ * seven.remainder(-three); // => 1
+ * ```
+ */
+ _BigIntImpl operator ~/(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (other._used == 0) {
+ throw const IntegerDivisionByZeroException();
+ }
+ return _div(other);
+ }
+
+ /**
+ * Returns the remainder of the truncating division of `this` by [other].
+ *
+ * The result `r` of this operation satisfies:
+ * `this == (this ~/ other) * other + r`.
+ * As a consequence the remainder `r` has the same sign as the divider `this`.
+ */
+ _BigIntImpl remainder(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (other._used == 0) {
+ throw const IntegerDivisionByZeroException();
+ }
+ return _rem(other);
+ }
+
+ /// Division operator.
+ double operator /(BigInt other) => this.toDouble() / other.toDouble();
+
+ /** Relational less than operator. */
+ bool operator <(BigInt other) => compareTo(other) < 0;
+
+ /** Relational less than or equal operator. */
+ bool operator <=(BigInt other) => compareTo(other) <= 0;
+
+ /** Relational greater than operator. */
+ bool operator >(BigInt other) => compareTo(other) > 0;
+
+ /** Relational greater than or equal operator. */
+ bool operator >=(BigInt other) => compareTo(other) >= 0;
+
+ /**
+ * Euclidean modulo operator.
+ *
+ * Returns the remainder of the Euclidean division. The Euclidean division of
+ * two integers `a` and `b` yields two integers `q` and `r` such that
+ * `a == b * q + r` and `0 <= r < b.abs()`.
+ *
+ * The sign of the returned value `r` is always positive.
+ *
+ * See [remainder] for the remainder of the truncating division.
+ */
+ _BigIntImpl operator %(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (other._used == 0) {
+ throw const IntegerDivisionByZeroException();
+ }
+ var result = _rem(other);
+ if (result._isNegative) {
+ if (other._isNegative) {
+ result = result - other;
+ } else {
+ result = result + other;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the sign of this big integer.
+ *
+ * Returns 0 for zero, -1 for values less than zero and
+ * +1 for values greater than zero.
+ */
+ int get sign {
+ if (_used == 0) return 0;
+ return _isNegative ? -1 : 1;
+ }
+
+ /// Whether this big integer is even.
+ bool get isEven => _used == 0 || (_digits[0] & 1) == 0;
+
+ /// Whether this big integer is odd.
+ bool get isOdd => !isEven;
+
+ /// Whether this number is negative.
+ bool get isNegative => _isNegative;
+
+ _BigIntImpl pow(int exponent) {
+ if (exponent < 0) {
+ throw ArgumentError("Exponent must not be negative: $exponent");
+ }
+ if (exponent == 0) return one;
+
+ // Exponentiation by squaring.
+ var result = one;
+ var base = this;
+ while (exponent != 0) {
+ if ((exponent & 1) == 1) {
+ result *= base;
+ }
+ exponent >>= 1;
+ // Skip unnecessary operation.
+ if (exponent != 0) {
+ base *= base;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns this integer to the power of [exponent] modulo [modulus].
+ *
+ * The [exponent] must be non-negative and [modulus] must be
+ * positive.
+ */
+ _BigIntImpl modPow(BigInt bigExponent, BigInt bigModulus) {
+ _BigIntImpl exponent = bigExponent;
+ _BigIntImpl modulus = bigModulus;
+ if (exponent._isNegative) {
+ throw ArgumentError("exponent must be positive: $exponent");
+ }
+ if (modulus <= zero) {
+ throw ArgumentError("modulus must be strictly positive: $modulus");
+ }
+ if (exponent._isZero) return one;
+
+ final modulusUsed = modulus._used;
+ final modulusUsed2p4 = 2 * modulusUsed + 4;
+ final exponentBitlen = exponent.bitLength;
+ if (exponentBitlen <= 0) return one;
+ _BigIntReduction z = _BigIntClassic(modulus);
+ var resultDigits = Uint16List(modulusUsed2p4);
+ var result2Digits = Uint16List(modulusUsed2p4);
+ var gDigits = Uint16List(modulusUsed);
+ var gUsed = z.convert(this, gDigits);
+ // Initialize result with g.
+ // Copy leading zero if any.
+ for (int j = gUsed - 1; j >= 0; j--) {
+ resultDigits[j] = gDigits[j];
+ }
+ var resultUsed = gUsed;
+ var result2Used;
+ for (int i = exponentBitlen - 2; i >= 0; i--) {
+ result2Used = z.sqr(resultDigits, resultUsed, result2Digits);
+ if (!(exponent & (one << i))._isZero) {
+ resultUsed =
+ z.mul(result2Digits, result2Used, gDigits, gUsed, resultDigits);
+ } else {
+ // Swap result and result2.
+ var tmpDigits = resultDigits;
+ var tmpUsed = resultUsed;
+ resultDigits = result2Digits;
+ resultUsed = result2Used;
+ result2Digits = tmpDigits;
+ result2Used = tmpUsed;
+ }
+ }
+ return z.revert(resultDigits, resultUsed);
+ }
+
+ // If inv is false, returns gcd(x, y).
+ // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
+ // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
+ static _BigIntImpl _binaryGcd(_BigIntImpl x, _BigIntImpl y, bool inv) {
+ var xDigits = x._digits;
+ var yDigits = y._digits;
+ var xUsed = x._used;
+ var yUsed = y._used;
+ var maxUsed = xUsed > yUsed ? xUsed : yUsed;
+ var unshiftedMaxUsed = maxUsed; // Keep
+ xDigits = _cloneDigits(xDigits, 0, xUsed, maxUsed);
+ yDigits = _cloneDigits(yDigits, 0, yUsed, maxUsed);
+ int shiftAmount = 0;
+ if (inv) {
+ if ((yUsed == 1) && (yDigits[0] == 1)) return one;
+ if ((yUsed == 0) || (yDigits[0].isEven && xDigits[0].isEven)) {
+ throw Exception("Not coprime");
+ }
+ } else {
+ if (x._isZero) {
+ throw ArgumentError.value(0, "this", "must not be zero");
+ }
+ if (y._isZero) {
+ throw ArgumentError.value(0, "other", "must not be zero");
+ }
+ if (((xUsed == 1) && (xDigits[0] == 1)) ||
+ ((yUsed == 1) && (yDigits[0] == 1))) return one;
+ while (((xDigits[0] & 1) == 0) && ((yDigits[0] & 1) == 0)) {
+ _rsh(xDigits, xUsed, 1, xDigits);
+ _rsh(yDigits, yUsed, 1, yDigits);
+ shiftAmount++;
+ }
+ if (shiftAmount >= _digitBits) {
+ var digitShiftAmount = shiftAmount ~/ _digitBits;
+ xUsed -= digitShiftAmount;
+ yUsed -= digitShiftAmount;
+ maxUsed -= digitShiftAmount;
+ }
+ if ((yDigits[0] & 1) == 1) {
+ // Swap x and y.
+ var tmpDigits = xDigits;
+ var tmpUsed = xUsed;
+ xDigits = yDigits;
+ xUsed = yUsed;
+ yDigits = tmpDigits;
+ yUsed = tmpUsed;
+ }
+ }
+ var uDigits = _cloneDigits(xDigits, 0, xUsed, unshiftedMaxUsed);
+ var vDigits =
+ _cloneDigits(yDigits, 0, yUsed, unshiftedMaxUsed + 2); // +2 for lsh.
+ final bool ac = (xDigits[0] & 1) == 0;
+
+ // Variables a, b, c, and d require one more digit.
+ final abcdUsed = maxUsed + 1;
+ final abcdLen = abcdUsed + 2; // +2 to satisfy _absAdd.
+ var aDigits, bDigits, cDigits, dDigits;
+ bool aIsNegative, bIsNegative, cIsNegative, dIsNegative;
+ if (ac) {
+ aDigits = Uint16List(abcdLen);
+ aIsNegative = false;
+ aDigits[0] = 1;
+ cDigits = Uint16List(abcdLen);
+ cIsNegative = false;
+ }
+ bDigits = Uint16List(abcdLen);
+ bIsNegative = false;
+ dDigits = Uint16List(abcdLen);
+ dIsNegative = false;
+ dDigits[0] = 1;
+
+ while (true) {
+ while ((uDigits[0] & 1) == 0) {
+ _rsh(uDigits, maxUsed, 1, uDigits);
+ if (ac) {
+ if (((aDigits[0] & 1) == 1) || ((bDigits[0] & 1) == 1)) {
+ // a += y
+ if (aIsNegative) {
+ if ((aDigits[maxUsed] != 0) ||
+ (_compareDigits(aDigits, maxUsed, yDigits, maxUsed)) > 0) {
+ _absSub(aDigits, abcdUsed, yDigits, maxUsed, aDigits);
+ } else {
+ _absSub(yDigits, maxUsed, aDigits, maxUsed, aDigits);
+ aIsNegative = false;
+ }
+ } else {
+ _absAdd(aDigits, abcdUsed, yDigits, maxUsed, aDigits);
+ }
+ // b -= x
+ if (bIsNegative) {
+ _absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+ } else if ((bDigits[maxUsed] != 0) ||
+ (_compareDigits(bDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ _absSub(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+ } else {
+ _absSub(xDigits, maxUsed, bDigits, maxUsed, bDigits);
+ bIsNegative = true;
+ }
+ }
+ _rsh(aDigits, abcdUsed, 1, aDigits);
+ } else if ((bDigits[0] & 1) == 1) {
+ // b -= x
+ if (bIsNegative) {
+ _absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+ } else if ((bDigits[maxUsed] != 0) ||
+ (_compareDigits(bDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ _absSub(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+ } else {
+ _absSub(xDigits, maxUsed, bDigits, maxUsed, bDigits);
+ bIsNegative = true;
+ }
+ }
+ _rsh(bDigits, abcdUsed, 1, bDigits);
+ }
+ while ((vDigits[0] & 1) == 0) {
+ _rsh(vDigits, maxUsed, 1, vDigits);
+ if (ac) {
+ if (((cDigits[0] & 1) == 1) || ((dDigits[0] & 1) == 1)) {
+ // c += y
+ if (cIsNegative) {
+ if ((cDigits[maxUsed] != 0) ||
+ (_compareDigits(cDigits, maxUsed, yDigits, maxUsed) > 0)) {
+ _absSub(cDigits, abcdUsed, yDigits, maxUsed, cDigits);
+ } else {
+ _absSub(yDigits, maxUsed, cDigits, maxUsed, cDigits);
+ cIsNegative = false;
+ }
+ } else {
+ _absAdd(cDigits, abcdUsed, yDigits, maxUsed, cDigits);
+ }
+ // d -= x
+ if (dIsNegative) {
+ _absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+ } else if ((dDigits[maxUsed] != 0) ||
+ (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+ } else {
+ _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+ dIsNegative = true;
+ }
+ }
+ _rsh(cDigits, abcdUsed, 1, cDigits);
+ } else if ((dDigits[0] & 1) == 1) {
+ // d -= x
+ if (dIsNegative) {
+ _absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+ } else if ((dDigits[maxUsed] != 0) ||
+ (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+ } else {
+ _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+ dIsNegative = true;
+ }
+ }
+ _rsh(dDigits, abcdUsed, 1, dDigits);
+ }
+ if (_compareDigits(uDigits, maxUsed, vDigits, maxUsed) >= 0) {
+ // u -= v
+ _absSub(uDigits, maxUsed, vDigits, maxUsed, uDigits);
+ if (ac) {
+ // a -= c
+ if (aIsNegative == cIsNegative) {
+ var a_cmp_c = _compareDigits(aDigits, abcdUsed, cDigits, abcdUsed);
+ if (a_cmp_c > 0) {
+ _absSub(aDigits, abcdUsed, cDigits, abcdUsed, aDigits);
+ } else {
+ _absSub(cDigits, abcdUsed, aDigits, abcdUsed, aDigits);
+ aIsNegative = !aIsNegative && (a_cmp_c != 0);
+ }
+ } else {
+ _absAdd(aDigits, abcdUsed, cDigits, abcdUsed, aDigits);
+ }
+ }
+ // b -= d
+ if (bIsNegative == dIsNegative) {
+ var b_cmp_d = _compareDigits(bDigits, abcdUsed, dDigits, abcdUsed);
+ if (b_cmp_d > 0) {
+ _absSub(bDigits, abcdUsed, dDigits, abcdUsed, bDigits);
+ } else {
+ _absSub(dDigits, abcdUsed, bDigits, abcdUsed, bDigits);
+ bIsNegative = !bIsNegative && (b_cmp_d != 0);
+ }
+ } else {
+ _absAdd(bDigits, abcdUsed, dDigits, abcdUsed, bDigits);
+ }
+ } else {
+ // v -= u
+ _absSub(vDigits, maxUsed, uDigits, maxUsed, vDigits);
+ if (ac) {
+ // c -= a
+ if (cIsNegative == aIsNegative) {
+ var c_cmp_a = _compareDigits(cDigits, abcdUsed, aDigits, abcdUsed);
+ if (c_cmp_a > 0) {
+ _absSub(cDigits, abcdUsed, aDigits, abcdUsed, cDigits);
+ } else {
+ _absSub(aDigits, abcdUsed, cDigits, abcdUsed, cDigits);
+ cIsNegative = !cIsNegative && (c_cmp_a != 0);
+ }
+ } else {
+ _absAdd(cDigits, abcdUsed, aDigits, abcdUsed, cDigits);
+ }
+ }
+ // d -= b
+ if (dIsNegative == bIsNegative) {
+ var d_cmp_b = _compareDigits(dDigits, abcdUsed, bDigits, abcdUsed);
+ if (d_cmp_b > 0) {
+ _absSub(dDigits, abcdUsed, bDigits, abcdUsed, dDigits);
+ } else {
+ _absSub(bDigits, abcdUsed, dDigits, abcdUsed, dDigits);
+ dIsNegative = !dIsNegative && (d_cmp_b != 0);
+ }
+ } else {
+ _absAdd(dDigits, abcdUsed, bDigits, abcdUsed, dDigits);
+ }
+ }
+ // Exit loop if u == 0.
+ var i = maxUsed;
+ while ((i > 0) && (uDigits[i - 1] == 0)) --i;
+ if (i == 0) break;
+ }
+ if (!inv) {
+ if (shiftAmount > 0) {
+ maxUsed = _lShiftDigits(vDigits, maxUsed, shiftAmount, vDigits);
+ }
+ return _BigIntImpl._(false, maxUsed, vDigits);
+ }
+ // No inverse if v != 1.
+ var i = maxUsed - 1;
+ while ((i > 0) && (vDigits[i] == 0)) --i;
+ if ((i != 0) || (vDigits[0] != 1)) {
+ throw Exception("Not coprime");
+ }
+
+ if (dIsNegative) {
+ while ((dDigits[maxUsed] != 0) ||
+ (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ // d += x, d still negative
+ _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+ }
+ // d += x
+ _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+ dIsNegative = false;
+ } else {
+ while ((dDigits[maxUsed] != 0) ||
+ (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) >= 0)) {
+ // d -= x
+ _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+ }
+ }
+ return _BigIntImpl._(false, maxUsed, dDigits);
+ }
+
+ /**
+ * Returns the modular multiplicative inverse of this big integer
+ * modulo [modulus].
+ *
+ * The [modulus] must be positive.
+ *
+ * It is an error if no modular inverse exists.
+ */
+ // Returns 1/this % modulus, with modulus > 0.
+ _BigIntImpl modInverse(BigInt bigInt) {
+ _BigIntImpl modulus = bigInt;
+ if (modulus <= zero) {
+ throw ArgumentError("Modulus must be strictly positive: $modulus");
+ }
+ if (modulus == one) return zero;
+ var tmp = this;
+ if (tmp._isNegative || (tmp._absCompare(modulus) >= 0)) {
+ tmp %= modulus;
+ }
+ return _binaryGcd(modulus, tmp, true);
+ }
+
+ /**
+ * Returns the greatest common divisor of this big integer and [other].
+ *
+ * If either number is non-zero, the result is the numerically greatest
+ * integer dividing both `this` and `other`.
+ *
+ * The greatest common divisor is independent of the order,
+ * so `x.gcd(y)` is always the same as `y.gcd(x)`.
+ *
+ * For any integer `x`, `x.gcd(x)` is `x.abs()`.
+ *
+ * If both `this` and `other` is zero, the result is also zero.
+ */
+ _BigIntImpl gcd(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isZero) return other.abs();
+ if (other._isZero) return this.abs();
+ return _binaryGcd(this, other, false);
+ }
+
+ /**
+ * Returns the least significant [width] bits of this big integer as a
+ * non-negative number (i.e. unsigned representation). The returned value has
+ * zeros in all bit positions higher than [width].
+ *
+ * ```
+ * new BigInt.from(-1).toUnsigned(5) == 31 // 11111111 -> 00011111
+ * ```
+ *
+ * This operation can be used to simulate arithmetic from low level languages.
+ * For example, to increment an 8 bit quantity:
+ *
+ * ```
+ * q = (q + 1).toUnsigned(8);
+ * ```
+ *
+ * `q` will count from `0` up to `255` and then wrap around to `0`.
+ *
+ * If the input fits in [width] bits without truncation, the result is the
+ * same as the input. The minimum width needed to avoid truncation of `x` is
+ * given by `x.bitLength`, i.e.
+ *
+ * ```
+ * x == x.toUnsigned(x.bitLength);
+ * ```
+ */
+ _BigIntImpl toUnsigned(int width) {
+ return this & ((one << width) - one);
+ }
+
+ /**
+ * Returns the least significant [width] bits of this integer, extending the
+ * highest retained bit to the sign. This is the same as truncating the value
+ * to fit in [width] bits using an signed 2-s complement representation. The
+ * returned value has the same bit value in all positions higher than [width].
+ *
+ * ```
+ * var big15 = new BigInt.from(15);
+ * var big16 = new BigInt.from(16);
+ * var big239 = new BigInt.from(239);
+ * V--sign bit-V
+ * big16.toSigned(5) == -big16 // 00010000 -> 11110000
+ * big239.toSigned(5) == big15 // 11101111 -> 00001111
+ * ^ ^
+ * ```
+ *
+ * This operation can be used to simulate arithmetic from low level languages.
+ * For example, to increment an 8 bit signed quantity:
+ *
+ * ```
+ * q = (q + 1).toSigned(8);
+ * ```
+ *
+ * `q` will count from `0` up to `127`, wrap to `-128` and count back up to
+ * `127`.
+ *
+ * If the input value fits in [width] bits without truncation, the result is
+ * the same as the input. The minimum width needed to avoid truncation of `x`
+ * is `x.bitLength + 1`, i.e.
+ *
+ * ```
+ * x == x.toSigned(x.bitLength + 1);
+ * ```
+ */
+ _BigIntImpl toSigned(int width) {
+ // The value of binary number weights each bit by a power of two. The
+ // twos-complement value weights the sign bit negatively. We compute the
+ // value of the negative weighting by isolating the sign bit with the
+ // correct power of two weighting and subtracting it from the value of the
+ // lower bits.
+ var signMask = one << (width - 1);
+ return (this & (signMask - one)) - (this & signMask);
+ }
+
+ // Maximum number of digits that always fit in mantissa.
+ static const _simpleValidIntDigits = 53 ~/ _digitBits;
+
+ bool get isValidInt {
+ if (_used <= _simpleValidIntDigits) return true;
+ var asInt = toInt();
+ if (!asInt.toDouble().isFinite) return false;
+ return this == _BigIntImpl._fromInt(asInt);
+ }
+
+ int toInt() {
+ var result = 0;
+ for (int i = _used - 1; i >= 0; i--) {
+ result = result * _digitBase + _digits[i];
+ }
+ return _isNegative ? -result : result;
+ }
+
+ /**
+ * Returns this [_BigIntImpl] as a [double].
+ *
+ * If the number is not representable as a [double], an
+ * approximation is returned. For numerically large integers, the
+ * approximation may be infinite.
+ */
+ double toDouble() {
+ const int exponentBias = 1075;
+ // There are 11 bits for the exponent.
+ // 2047 (all bits set to 1) is reserved for infinity and NaN.
+ // When storing the exponent in the 11 bits, it is biased by exponentBias
+ // to support negative exponents.
+ const int maxDoubleExponent = 2046 - exponentBias;
+ if (_isZero) return 0.0;
+
+ // We fill the 53 bits little-endian.
+ var resultBits = Uint8List(8);
+
+ var length = _digitBits * (_used - 1) + _digits[_used - 1].bitLength;
+ if (length > maxDoubleExponent + 53) {
+ return _isNegative ? double.negativeInfinity : double.infinity;
+ }
+
+ // The most significant bit is for the sign.
+ if (_isNegative) resultBits[7] = 0x80;
+
+ // Write the exponent into bits 1..12:
+ var biasedExponent = length - 53 + exponentBias;
+ resultBits[6] = (biasedExponent & 0xF) << 4;
+ resultBits[7] |= biasedExponent >> 4;
+
+ int cachedBits = 0;
+ int cachedBitsLength = 0;
+ int digitIndex = _used - 1;
+ int readBits(int n) {
+ // Ensure that we have enough bits in [cachedBits].
+ while (cachedBitsLength < n) {
+ int nextDigit;
+ int nextDigitLength = _digitBits; // May get updated.
+ if (digitIndex < 0) {
+ nextDigit = 0;
+ digitIndex--;
+ } else {
+ nextDigit = _digits[digitIndex];
+ if (digitIndex == _used - 1) nextDigitLength = nextDigit.bitLength;
+ digitIndex--;
+ }
+ cachedBits = (cachedBits << nextDigitLength) + nextDigit;
+ cachedBitsLength += nextDigitLength;
+ }
+ // Read the top [n] bits.
+ var result = cachedBits >> (cachedBitsLength - n);
+ // Remove the bits from the cache.
+ cachedBits -= result << (cachedBitsLength - n);
+ cachedBitsLength -= n;
+ return result;
+ }
+
+ // The first leading 1 bit is implicit in the double-representation and can
+ // be discarded.
+ var leadingBits = readBits(5) & 0xF;
+ resultBits[6] |= leadingBits;
+
+ for (int i = 5; i >= 0; i--) {
+ // Get the remaining 48 bits.
+ resultBits[i] = readBits(8);
+ }
+
+ void roundUp() {
+ // Simply consists of adding 1 to the whole 64 bit "number".
+ // It will update the exponent, if necessary.
+ // It might even round up to infinity (which is what we want).
+ var carry = 1;
+ for (int i = 0; i < 8; i++) {
+ if (carry == 0) break;
+ var sum = resultBits[i] + carry;
+ resultBits[i] = sum & 0xFF;
+ carry = sum >> 8;
+ }
+ }
+
+ if (readBits(1) == 1) {
+ if (resultBits[0].isOdd) {
+ // Rounds to even all the time.
+ roundUp();
+ } else {
+ // Round up, if there is at least one other digit that is not 0.
+ if (cachedBits != 0) {
+ // There is already one in the cachedBits.
+ roundUp();
+ } else {
+ for (int i = digitIndex; digitIndex >= 0; i--) {
+ if (_digits[i] != 0) {
+ roundUp();
+ break;
+ }
+ }
+ }
+ }
+ }
+ return resultBits.buffer.asByteData().getFloat64(0, Endian.little);
+ }
+
+ /**
+ * Returns a String-representation of this integer.
+ *
+ * The returned string is parsable by [parse].
+ * For any `_BigIntImpl` `i`, it is guaranteed that
+ * `i == _BigIntImpl.parse(i.toString())`.
+ */
+ String toString() {
+ if (_used == 0) return "0";
+ if (_used == 1) {
+ if (_isNegative) return (-_digits[0]).toString();
+ return _digits[0].toString();
+ }
+
+ // Generate in chunks of 4 digits.
+ // The chunks are in reversed order.
+ var decimalDigitChunks = <String>[];
+ var rest = isNegative ? -this : this;
+ while (rest._used > 1) {
+ var digits4 = rest.remainder(_bigInt10000).toString();
+ decimalDigitChunks.add(digits4);
+ if (digits4.length == 1) decimalDigitChunks.add("000");
+ if (digits4.length == 2) decimalDigitChunks.add("00");
+ if (digits4.length == 3) decimalDigitChunks.add("0");
+ rest = rest ~/ _bigInt10000;
+ }
+ decimalDigitChunks.add(rest._digits[0].toString());
+ if (_isNegative) decimalDigitChunks.add("-");
+ return decimalDigitChunks.reversed.join();
+ }
+
+ int _toRadixCodeUnit(int digit) {
+ const int _0 = 48;
+ const int _a = 97;
+ if (digit < 10) return _0 + digit;
+ return _a + digit - 10;
+ }
+
+ /**
+ * Converts [this] to a string representation in the given [radix].
+ *
+ * In the string representation, lower-case letters are used for digits above
+ * '9', with 'a' being 10 an 'z' being 35.
+ *
+ * The [radix] argument must be an integer in the range 2 to 36.
+ */
+ String toRadixString(int radix) {
+ if (radix > 36) throw RangeError.range(radix, 2, 36);
+
+ if (_used == 0) return "0";
+
+ if (_used == 1) {
+ var digitString = _digits[0].toRadixString(radix);
+ if (_isNegative) return "-" + digitString;
+ return digitString;
+ }
+
+ if (radix == 16) return _toHexString();
+
+ var base = _BigIntImpl._fromInt(radix);
+ var reversedDigitCodeUnits = <int>[];
+ var rest = this.abs();
+ while (!rest._isZero) {
+ var digit = rest.remainder(base).toInt();
+ rest = rest ~/ base;
+ reversedDigitCodeUnits.add(_toRadixCodeUnit(digit));
+ }
+ var digitString = String.fromCharCodes(reversedDigitCodeUnits.reversed);
+ if (_isNegative) return "-" + digitString;
+ return digitString;
+ }
+
+ String _toHexString() {
+ var chars = <int>[];
+ for (int i = 0; i < _used - 1; i++) {
+ int chunk = _digits[i];
+ for (int j = 0; j < (_digitBits ~/ 4); j++) {
+ chars.add(_toRadixCodeUnit(chunk & 0xF));
+ chunk >>= 4;
+ }
+ }
+ var msbChunk = _digits[_used - 1];
+ while (msbChunk != 0) {
+ chars.add(_toRadixCodeUnit(msbChunk & 0xF));
+ msbChunk >>= 4;
+ }
+ if (_isNegative) {
+ const _dash = 45;
+ chars.add(_dash);
+ }
+ return String.fromCharCodes(chars.reversed);
+ }
+}
+
+// Interface for modular reduction.
+abstract class _BigIntReduction {
+ // Return the number of digits used by r_digits.
+ int convert(_BigIntImpl x, Uint16List r_digits);
+ int mul(Uint16List xDigits, int xUsed, Uint16List yDigits, int yUsed,
+ Uint16List resultDigits);
+ int sqr(Uint16List xDigits, int xUsed, Uint16List resultDigits);
+
+ // Return x reverted to _BigIntImpl.
+ _BigIntImpl revert(Uint16List xDigits, int xUsed);
+}
+
+// Modular reduction using "classic" algorithm.
+class _BigIntClassic implements _BigIntReduction {
+ final _BigIntImpl _modulus; // Modulus.
+ final _BigIntImpl _normalizedModulus; // Normalized _modulus.
+
+ _BigIntClassic(this._modulus)
+ : _normalizedModulus = _modulus <<
+ (_BigIntImpl._digitBits -
+ _modulus._digits[_modulus._used - 1].bitLength);
+
+ int convert(_BigIntImpl x, Uint16List resultDigits) {
+ var digits;
+ var used;
+ if (x._isNegative || x._absCompare(_modulus) >= 0) {
+ var remainder = x._rem(_modulus);
+ if (x._isNegative && remainder._used > 0) {
+ assert(remainder._isNegative);
+ remainder += _modulus;
+ }
+ assert(!remainder._isNegative);
+ used = remainder._used;
+ digits = remainder._digits;
+ } else {
+ used = x._used;
+ digits = x._digits;
+ }
+ var i = used; // Copy leading zero if any.
+ while (--i >= 0) {
+ resultDigits[i] = digits[i];
+ }
+ return used;
+ }
+
+ _BigIntImpl revert(Uint16List xDigits, int xUsed) {
+ return _BigIntImpl._(false, xUsed, xDigits);
+ }
+
+ int _reduce(Uint16List xDigits, int xUsed) {
+ if (xUsed < _modulus._used) {
+ return xUsed;
+ }
+ var reverted = revert(xDigits, xUsed);
+ var rem = reverted._rem(_normalizedModulus);
+ return convert(rem, xDigits);
+ }
+
+ int sqr(Uint16List xDigits, int xUsed, Uint16List resultDigits) {
+ var b = _BigIntImpl._(false, xUsed, xDigits);
+ var b2 = b * b;
+ for (int i = 0; i < b2._used; i++) {
+ resultDigits[i] = b2._digits[i];
+ }
+ for (int i = b2._used; i < 2 * xUsed; i++) {
+ resultDigits[i] = 0;
+ }
+ return _reduce(resultDigits, 2 * xUsed);
+ }
+
+ int mul(Uint16List xDigits, int xUsed, Uint16List yDigits, int yUsed,
+ Uint16List resultDigits) {
+ var resultUsed =
+ _BigIntImpl._mulDigits(xDigits, xUsed, yDigits, yUsed, resultDigits);
+ return _reduce(resultDigits, resultUsed);
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/developer_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/developer_patch.dart
new file mode 100644
index 0000000..7f5e4fe
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/developer_patch.dart
@@ -0,0 +1,216 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:developer library.
+
+import 'dart:_js_helper' show patch, ForceInline, ReifyFunctionTypes;
+import 'dart:_foreign_helper' show JS, JSExportName;
+import 'dart:_runtime' as dart;
+import 'dart:async';
+import 'dart:convert' show json;
+import 'dart:isolate';
+
+@patch
+@ForceInline()
+bool debugger({bool when = true, String message}) {
+ if (when) {
+ JS('', 'debugger');
+ }
+ return when;
+}
+
+@patch
+Object inspect(Object object) {
+ // Note: this log level does not show up by default in Chrome.
+ // This is used for communication with the debugger service.
+ JS('', 'console.debug("dart.developer.inspect", #)', object);
+ return object;
+}
+
+@patch
+void log(String message,
+ {DateTime time,
+ int sequenceNumber,
+ int level = 0,
+ String name = '',
+ Zone zone,
+ Object error,
+ StackTrace stackTrace}) {
+ Object items =
+ JS('!', '{ message: #, name: #, level: # }', message, name, level);
+ if (time != null) JS('', '#.time = #', items, time);
+ if (sequenceNumber != null) {
+ JS('', '#.sequenceNumber = #', items, sequenceNumber);
+ }
+ if (zone != null) JS('', '#.zone = #', items, zone);
+ if (error != null) JS('', '#.error = #', items, error);
+ if (stackTrace != null) JS('', '#.stackTrace = #', items, stackTrace);
+
+ JS('', 'console.debug("dart.developer.log", #)', items);
+}
+
+final _extensions = Map<String, ServiceExtensionHandler>();
+
+@patch
+ServiceExtensionHandler _lookupExtension(String method) {
+ return _extensions[method];
+}
+
+@patch
+_registerExtension(String method, ServiceExtensionHandler handler) {
+ _extensions[method] = handler;
+ JS('', 'console.debug("dart.developer.registerExtension", #)', method);
+}
+
+/// Returns a JS `Promise` that resolves with the result of invoking
+/// [methodName] with an [encodedJson] map as its parameters.
+///
+/// This is used by the VM Service Prototcol to invoke extensions registered
+/// with [registerExtension]. For example, in JS:
+///
+/// await sdk.developer.invokeExtension(
+/// . "ext.flutter.inspector.getRootWidget", '{"objectGroup":""}');
+///
+@JSExportName('invokeExtension')
+@ReifyFunctionTypes(false)
+_invokeExtension(String methodName, String encodedJson) {
+ // TODO(vsm): We should factor this out as future<->promise.
+ return JS('', 'new #.Promise(#)', dart.global_,
+ (Function(Object) resolve, Function(Object) reject) async {
+ try {
+ var method = _lookupExtension(methodName);
+ var parameters = (json.decode(encodedJson) as Map).cast<String, String>();
+ var result = await method(methodName, parameters);
+ resolve(result._toString());
+ } catch (e) {
+ // TODO(vsm): Reject or encode in result?
+ reject('$e');
+ }
+ });
+}
+
+@patch
+void _postEvent(String eventKind, String eventData) {
+ JS('', 'console.debug("dart.developer.postEvent", #, #)', eventKind,
+ eventData);
+}
+
+@patch
+bool _isDartStreamEnabled() {
+ return false;
+}
+
+@patch
+int _getTraceClock() {
+ // TODO.
+ return _clockValue++;
+}
+
+int _clockValue = 0;
+
+@patch
+int _getThreadCpuClock() {
+ return -1;
+}
+
+@patch
+void _reportCompleteEvent(int start, int startCpu, String category, String name,
+ String argumentsAsJson) {
+ // TODO.
+}
+
+@patch
+void _reportFlowEvent(int start, int startCpu, String category, String name,
+ int type, int id, String argumentsAsJson) {
+ // TODO.
+}
+
+@patch
+void _reportInstantEvent(
+ int start, String category, String name, String argumentsAsJson) {
+ // TODO.
+}
+
+@patch
+int _getNextAsyncId() {
+ return 0;
+}
+
+@patch
+void _reportTaskEvent(int start, int taskId, String phase, String category,
+ String name, String argumentsAsJson) {
+ // TODO.
+}
+
+@patch
+int _getServiceMajorVersion() {
+ return 0;
+}
+
+@patch
+int _getServiceMinorVersion() {
+ return 0;
+}
+
+@patch
+void _getServerInfo(SendPort sendPort) {
+ sendPort.send(null);
+}
+
+@patch
+void _webServerControl(SendPort sendPort, bool enable) {
+ sendPort.send(null);
+}
+
+@patch
+String _getIsolateIDFromSendPort(SendPort sendPort) {
+ return null;
+}
+
+@patch
+class UserTag {
+ @patch
+ factory UserTag(String label) = _FakeUserTag;
+
+ @patch
+ static UserTag get defaultTag => _FakeUserTag._defaultTag;
+}
+
+class _FakeUserTag implements UserTag {
+ static Map _instances = {};
+
+ _FakeUserTag.real(this.label);
+
+ factory _FakeUserTag(String label) {
+ // Canonicalize by name.
+ var existingTag = _instances[label];
+ if (existingTag != null) {
+ return existingTag;
+ }
+ // Throw an exception if we've reached the maximum number of user tags.
+ if (_instances.length == UserTag.MAX_USER_TAGS) {
+ throw UnsupportedError(
+ 'UserTag instance limit (${UserTag.MAX_USER_TAGS}) reached.');
+ }
+ // Create a new instance and add it to the instance map.
+ var instance = _FakeUserTag.real(label);
+ _instances[label] = instance;
+ return instance;
+ }
+
+ final String label;
+
+ UserTag makeCurrent() {
+ var old = _currentTag;
+ _currentTag = this;
+ return old;
+ }
+
+ static final UserTag _defaultTag = _FakeUserTag('Default');
+}
+
+var _currentTag = _FakeUserTag._defaultTag;
+
+@patch
+UserTag getCurrentTag() => _currentTag;
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/internal_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/internal_patch.dart
new file mode 100644
index 0000000..5e850bb
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/internal_patch.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:core' hide Symbol;
+import 'dart:core' as core show Symbol;
+import 'dart:_js_primitives' show printString;
+import 'dart:_js_helper' show patch;
+import 'dart:_interceptors' show JSArray;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_runtime' as dart;
+
+@patch
+class Symbol implements core.Symbol {
+ @patch
+ const Symbol(String name) : this._name = name;
+
+ @patch
+ int get hashCode {
+ int hash = JS('int|Null', '#._hashCode', this);
+ if (hash != null) return hash;
+ const arbitraryPrime = 664597;
+ hash = 0x1fffffff & (arbitraryPrime * _name.hashCode);
+ JS('', '#._hashCode = #', this, hash);
+ return hash;
+ }
+
+ @patch
+ toString() => 'Symbol("$_name")';
+
+ @patch
+ static String computeUnmangledName(Symbol symbol) => symbol._name;
+}
+
+@patch
+void printToConsole(String line) {
+ printString('$line');
+}
+
+@patch
+List<E> makeListFixedLength<E>(List<E> growableList) {
+ JSArray.markFixedList(growableList);
+ return growableList;
+}
+
+@patch
+List<E> makeFixedListUnmodifiable<E>(List<E> fixedLengthList) {
+ JSArray.markUnmodifiableList(fixedLengthList);
+ return fixedLengthList;
+}
+
+@patch
+Object extractTypeArguments<T>(T instance, Function extract) =>
+ dart.extractTypeArguments<T>(instance, extract);
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/io_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/io_patch.dart
new file mode 100644
index 0000000..61d031a
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/io_patch.dart
@@ -0,0 +1,690 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:_js_helper' show patch;
+import 'dart:async';
+import 'dart:convert';
+import 'dart:isolate' show SendPort;
+import 'dart:typed_data';
+
+@patch
+class _Directory {
+ @patch
+ static _current(_Namespace namespace) {
+ throw UnsupportedError("Directory._current");
+ }
+
+ @patch
+ static _setCurrent(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("Directory_SetCurrent");
+ }
+
+ @patch
+ static _createTemp(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("Directory._createTemp");
+ }
+
+ @patch
+ static String _systemTemp(_Namespace namespace) {
+ throw UnsupportedError("Directory._systemTemp");
+ }
+
+ @patch
+ static _exists(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("Directory._exists");
+ }
+
+ @patch
+ static _create(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("Directory._create");
+ }
+
+ @patch
+ static _deleteNative(
+ _Namespace namespace, Uint8List rawPath, bool recursive) {
+ throw UnsupportedError("Directory._deleteNative");
+ }
+
+ @patch
+ static _rename(_Namespace namespace, Uint8List rawPath, String newPath) {
+ throw UnsupportedError("Directory._rename");
+ }
+
+ @patch
+ static void _fillWithDirectoryListing(
+ _Namespace namespace,
+ List<FileSystemEntity> list,
+ Uint8List rawPath,
+ bool recursive,
+ bool followLinks) {
+ throw UnsupportedError("Directory._fillWithDirectoryListing");
+ }
+}
+
+@patch
+class _AsyncDirectoryListerOps {
+ @patch
+ factory _AsyncDirectoryListerOps(int pointer) {
+ throw UnsupportedError("Directory._list");
+ }
+}
+
+@patch
+class _EventHandler {
+ @patch
+ static void _sendData(Object sender, SendPort sendPort, int data) {
+ throw UnsupportedError("EventHandler._sendData");
+ }
+}
+
+@patch
+class FileStat {
+ @patch
+ static _statSync(_Namespace namespace, String path) {
+ throw UnsupportedError("FileStat.stat");
+ }
+}
+
+@patch
+class FileSystemEntity {
+ @patch
+ static _getTypeNative(
+ _Namespace namespace, Uint8List rawPath, bool followLinks) {
+ throw UnsupportedError("FileSystemEntity._getType");
+ }
+
+ @patch
+ static _identicalNative(_Namespace namespace, String path1, String path2) {
+ throw UnsupportedError("FileSystemEntity._identical");
+ }
+
+ @patch
+ static _resolveSymbolicLinks(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("FileSystemEntity._resolveSymbolicLinks");
+ }
+}
+
+@patch
+class _File {
+ @patch
+ static _exists(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("File._exists");
+ }
+
+ @patch
+ static _create(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("File._create");
+ }
+
+ @patch
+ static _createLink(_Namespace namespace, Uint8List rawPath, String target) {
+ throw UnsupportedError("File._createLink");
+ }
+
+ @patch
+ static _linkTarget(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("File._linkTarget");
+ }
+
+ @patch
+ static _deleteNative(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("File._deleteNative");
+ }
+
+ @patch
+ static _deleteLinkNative(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("File._deleteLinkNative");
+ }
+
+ @patch
+ static _rename(_Namespace namespace, Uint8List oldPath, String newPath) {
+ throw UnsupportedError("File._rename");
+ }
+
+ @patch
+ static _renameLink(_Namespace namespace, Uint8List oldPath, String newPath) {
+ throw UnsupportedError("File._renameLink");
+ }
+
+ @patch
+ static _copy(_Namespace namespace, Uint8List oldPath, String newPath) {
+ throw UnsupportedError("File._copy");
+ }
+
+ @patch
+ static _lengthFromPath(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("File._lengthFromPath");
+ }
+
+ @patch
+ static _lastModified(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("File._lastModified");
+ }
+
+ @patch
+ static _lastAccessed(_Namespace namespace, Uint8List rawPath) {
+ throw UnsupportedError("File._lastAccessed");
+ }
+
+ @patch
+ static _setLastModified(_Namespace namespace, Uint8List rawPath, int millis) {
+ throw UnsupportedError("File._setLastModified");
+ }
+
+ @patch
+ static _setLastAccessed(_Namespace namespace, Uint8List rawPath, int millis) {
+ throw UnsupportedError("File._setLastAccessed");
+ }
+
+ @patch
+ static _open(_Namespace namespace, Uint8List rawPath, int mode) {
+ throw UnsupportedError("File._open");
+ }
+
+ @patch
+ static int _openStdio(int fd) {
+ throw UnsupportedError("File._openStdio");
+ }
+}
+
+@patch
+class _Namespace {
+ @patch
+ static void _setupNamespace(var namespace) {
+ throw UnsupportedError("_Namespace");
+ }
+
+ @patch
+ static _Namespace get _namespace {
+ throw UnsupportedError("_Namespace");
+ }
+
+ @patch
+ static int get _namespacePointer {
+ throw UnsupportedError("_Namespace");
+ }
+}
+
+@patch
+class _RandomAccessFileOps {
+ @patch
+ factory _RandomAccessFileOps(int pointer) {
+ throw UnsupportedError("RandomAccessFile");
+ }
+}
+
+@patch
+class _IOCrypto {
+ @patch
+ static Uint8List getRandomBytes(int count) {
+ throw UnsupportedError("_IOCrypto.getRandomBytes");
+ }
+}
+
+@patch
+class _Platform {
+ @patch
+ static int _numberOfProcessors() {
+ throw UnsupportedError("Platform._numberOfProcessors");
+ }
+
+ @patch
+ static String _pathSeparator() {
+ throw UnsupportedError("Platform._pathSeparator");
+ }
+
+ @patch
+ static String _operatingSystem() {
+ throw UnsupportedError("Platform._operatingSystem");
+ }
+
+ @patch
+ static _operatingSystemVersion() {
+ throw UnsupportedError("Platform._operatingSystemVersion");
+ }
+
+ @patch
+ static _localHostname() {
+ throw UnsupportedError("Platform._localHostname");
+ }
+
+ @patch
+ static _executable() {
+ throw UnsupportedError("Platform._executable");
+ }
+
+ @patch
+ static _resolvedExecutable() {
+ throw UnsupportedError("Platform._resolvedExecutable");
+ }
+
+ @patch
+ static List<String> _executableArguments() {
+ throw UnsupportedError("Platform._executableArguments");
+ }
+
+ @patch
+ static String _packageRoot() {
+ throw UnsupportedError("Platform._packageRoot");
+ }
+
+ @patch
+ static String _packageConfig() {
+ throw UnsupportedError("Platform._packageConfig");
+ }
+
+ @patch
+ static _environment() {
+ throw UnsupportedError("Platform._environment");
+ }
+
+ @patch
+ static String _version() {
+ throw UnsupportedError("Platform._version");
+ }
+
+ @patch
+ static String _localeName() {
+ throw UnsupportedError("Platform._localeName");
+ }
+
+ @patch
+ static Uri _script() {
+ throw UnsupportedError("Platform._script");
+ }
+}
+
+@patch
+class _ProcessUtils {
+ @patch
+ static void _exit(int status) {
+ throw UnsupportedError("ProcessUtils._exit");
+ }
+
+ @patch
+ static void _setExitCode(int status) {
+ throw UnsupportedError("ProcessUtils._setExitCode");
+ }
+
+ @patch
+ static int _getExitCode() {
+ throw UnsupportedError("ProcessUtils._getExitCode");
+ }
+
+ @patch
+ static void _sleep(int millis) {
+ throw UnsupportedError("ProcessUtils._sleep");
+ }
+
+ @patch
+ static int _pid(Process process) {
+ throw UnsupportedError("ProcessUtils._pid");
+ }
+
+ @patch
+ static Stream<ProcessSignal> _watchSignal(ProcessSignal signal) {
+ throw UnsupportedError("ProcessUtils._watchSignal");
+ }
+}
+
+@patch
+class ProcessInfo {
+ @patch
+ static int get currentRss {
+ throw UnsupportedError("ProcessInfo.currentRss");
+ }
+
+ @patch
+ static int get maxRss {
+ throw UnsupportedError("ProcessInfo.maxRss");
+ }
+}
+
+@patch
+class Process {
+ @patch
+ static Future<Process> start(String executable, List<String> arguments,
+ {String workingDirectory,
+ Map<String, String> environment,
+ bool includeParentEnvironment = true,
+ bool runInShell = false,
+ ProcessStartMode mode = ProcessStartMode.normal}) {
+ throw UnsupportedError("Process.start");
+ }
+
+ @patch
+ static Future<ProcessResult> run(String executable, List<String> arguments,
+ {String workingDirectory,
+ Map<String, String> environment,
+ bool includeParentEnvironment = true,
+ bool runInShell = false,
+ Encoding stdoutEncoding = systemEncoding,
+ Encoding stderrEncoding = systemEncoding}) {
+ throw UnsupportedError("Process.run");
+ }
+
+ @patch
+ static ProcessResult runSync(String executable, List<String> arguments,
+ {String workingDirectory,
+ Map<String, String> environment,
+ bool includeParentEnvironment = true,
+ bool runInShell = false,
+ Encoding stdoutEncoding = systemEncoding,
+ Encoding stderrEncoding = systemEncoding}) {
+ throw UnsupportedError("Process.runSync");
+ }
+
+ @patch
+ static bool killPid(int pid, [ProcessSignal signal = ProcessSignal.sigterm]) {
+ throw UnsupportedError("Process.killPid");
+ }
+}
+
+@patch
+class InternetAddress {
+ @patch
+ static InternetAddress get LOOPBACK_IP_V4 {
+ throw UnsupportedError("InternetAddress.LOOPBACK_IP_V4");
+ }
+
+ @patch
+ static InternetAddress get LOOPBACK_IP_V6 {
+ throw UnsupportedError("InternetAddress.LOOPBACK_IP_V6");
+ }
+
+ @patch
+ static InternetAddress get ANY_IP_V4 {
+ throw UnsupportedError("InternetAddress.ANY_IP_V4");
+ }
+
+ @patch
+ static InternetAddress get ANY_IP_V6 {
+ throw UnsupportedError("InternetAddress.ANY_IP_V6");
+ }
+
+ @patch
+ factory InternetAddress(String address) {
+ throw UnsupportedError("InternetAddress");
+ }
+ @patch
+ static Future<List<InternetAddress>> lookup(String host,
+ {InternetAddressType type = InternetAddressType.any}) {
+ throw UnsupportedError("InternetAddress.lookup");
+ }
+
+ @patch
+ static InternetAddress _cloneWithNewHost(
+ InternetAddress address, String host) {
+ throw UnsupportedError("InternetAddress._cloneWithNewHost");
+ }
+}
+
+@patch
+class NetworkInterface {
+ @patch
+ static bool get listSupported {
+ throw UnsupportedError("NetworkInterface.listSupported");
+ }
+
+ @patch
+ static Future<List<NetworkInterface>> list(
+ {bool includeLoopback = false,
+ bool includeLinkLocal = false,
+ InternetAddressType type = InternetAddressType.any}) {
+ throw UnsupportedError("NetworkInterface.list");
+ }
+}
+
+@patch
+class RawServerSocket {
+ @patch
+ static Future<RawServerSocket> bind(address, int port,
+ {int backlog = 0, bool v6Only = false, bool shared = false}) {
+ throw UnsupportedError("RawServerSocket.bind");
+ }
+}
+
+@patch
+class ServerSocket {
+ @patch
+ static Future<ServerSocket> bind(address, int port,
+ {int backlog = 0, bool v6Only = false, bool shared = false}) {
+ throw UnsupportedError("ServerSocket.bind");
+ }
+}
+
+@patch
+class RawSocket {
+ @patch
+ static Future<RawSocket> connect(host, int port,
+ {sourceAddress, Duration timeout}) {
+ throw UnsupportedError("RawSocket constructor");
+ }
+
+ @patch
+ static Future<ConnectionTask<RawSocket>> startConnect(host, int port,
+ {sourceAddress}) {
+ throw UnsupportedError("RawSocket constructor");
+ }
+}
+
+@patch
+class Socket {
+ @patch
+ static Future<Socket> _connect(host, int port,
+ {sourceAddress, Duration timeout}) {
+ throw UnsupportedError("Socket constructor");
+ }
+
+ @patch
+ static Future<ConnectionTask<Socket>> _startConnect(host, int port,
+ {sourceAddress}) {
+ throw UnsupportedError("Socket constructor");
+ }
+}
+
+@patch
+class SecureSocket {
+ @patch
+ factory SecureSocket._(RawSecureSocket rawSocket) {
+ throw UnsupportedError("SecureSocket constructor");
+ }
+}
+
+@patch
+class RawSynchronousSocket {
+ @patch
+ static RawSynchronousSocket connectSync(host, int port) {
+ throw UnsupportedError("RawSynchronousSocket.connectSync");
+ }
+}
+
+@patch
+class RawSocketOption {
+ @patch
+ static int _getOptionValue(int key) {
+ throw UnsupportedError("RawSocketOption._getOptionValue");
+ }
+}
+
+@patch
+class SecurityContext {
+ @patch
+ factory SecurityContext({bool withTrustedRoots = false}) {
+ throw UnsupportedError("SecurityContext constructor");
+ }
+
+ @patch
+ static SecurityContext get defaultContext {
+ throw UnsupportedError("default SecurityContext getter");
+ }
+
+ @patch
+ static bool get alpnSupported {
+ throw UnsupportedError("SecurityContext alpnSupported getter");
+ }
+}
+
+@patch
+class X509Certificate {
+ @patch
+ factory X509Certificate._() {
+ throw UnsupportedError("X509Certificate constructor");
+ }
+}
+
+@patch
+class RawDatagramSocket {
+ @patch
+ static Future<RawDatagramSocket> bind(host, int port,
+ {bool reuseAddress = true, bool reusePort = false, int ttl = 1}) {
+ throw UnsupportedError("RawDatagramSocket.bind");
+ }
+}
+
+@patch
+class _SecureFilter {
+ @patch
+ factory _SecureFilter._() {
+ throw UnsupportedError("_SecureFilter._SecureFilter");
+ }
+}
+
+@patch
+class _StdIOUtils {
+ @patch
+ static Stdin _getStdioInputStream(int fd) {
+ throw UnsupportedError("StdIOUtils._getStdioInputStream");
+ }
+
+ @patch
+ static _getStdioOutputStream(int fd) {
+ throw UnsupportedError("StdIOUtils._getStdioOutputStream");
+ }
+
+ @patch
+ static int _socketType(Socket socket) {
+ throw UnsupportedError("StdIOUtils._socketType");
+ }
+
+ @patch
+ static _getStdioHandleType(int fd) {
+ throw UnsupportedError("StdIOUtils._getStdioHandleType");
+ }
+}
+
+@patch
+class _WindowsCodePageDecoder {
+ @patch
+ static String _decodeBytes(List<int> bytes) {
+ throw UnsupportedError("_WindowsCodePageDecoder._decodeBytes");
+ }
+}
+
+@patch
+class _WindowsCodePageEncoder {
+ @patch
+ static List<int> _encodeString(String string) {
+ throw UnsupportedError("_WindowsCodePageEncoder._encodeString");
+ }
+}
+
+@patch
+class RawZLibFilter {
+ @patch
+ static RawZLibFilter _makeZLibDeflateFilter(
+ bool gzip,
+ int level,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ List<int> dictionary,
+ bool raw) {
+ throw UnsupportedError("_newZLibDeflateFilter");
+ }
+
+ @patch
+ static RawZLibFilter _makeZLibInflateFilter(
+ int windowBits, List<int> dictionary, bool raw) {
+ throw UnsupportedError("_newZLibInflateFilter");
+ }
+}
+
+@patch
+class Stdin {
+ @patch
+ int readByteSync() {
+ throw UnsupportedError("Stdin.readByteSync");
+ }
+
+ @patch
+ bool get echoMode {
+ throw UnsupportedError("Stdin.echoMode");
+ }
+
+ @patch
+ void set echoMode(bool enabled) {
+ throw UnsupportedError("Stdin.echoMode");
+ }
+
+ @patch
+ bool get lineMode {
+ throw UnsupportedError("Stdin.lineMode");
+ }
+
+ @patch
+ void set lineMode(bool enabled) {
+ throw UnsupportedError("Stdin.lineMode");
+ }
+
+ @patch
+ bool get supportsAnsiEscapes {
+ throw UnsupportedError("Stdin.supportsAnsiEscapes");
+ }
+}
+
+@patch
+class Stdout {
+ @patch
+ bool _hasTerminal(int fd) {
+ throw UnsupportedError("Stdout.hasTerminal");
+ }
+
+ @patch
+ int _terminalColumns(int fd) {
+ throw UnsupportedError("Stdout.terminalColumns");
+ }
+
+ @patch
+ int _terminalLines(int fd) {
+ throw UnsupportedError("Stdout.terminalLines");
+ }
+
+ @patch
+ static bool _supportsAnsiEscapes(int fd) {
+ throw UnsupportedError("Stdout.supportsAnsiEscapes");
+ }
+}
+
+@patch
+class _FileSystemWatcher {
+ @patch
+ static Stream<FileSystemEvent> _watch(
+ String path, int events, bool recursive) {
+ throw UnsupportedError("_FileSystemWatcher.watch");
+ }
+
+ @patch
+ static bool get isSupported {
+ throw UnsupportedError("_FileSystemWatcher.isSupported");
+ }
+}
+
+@patch
+class _IOService {
+ @patch
+ static Future _dispatch(int request, List data) {
+ throw UnsupportedError("_IOService._dispatch");
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/isolate_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/isolate_patch.dart
new file mode 100644
index 0000000..f6aa73bb
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/isolate_patch.dart
@@ -0,0 +1,125 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for the dart:isolate library.
+
+import 'dart:_js_helper' show patch, NoReifyGeneric;
+import 'dart:async';
+import "dart:typed_data" show TypedData;
+
+@patch
+class Isolate {
+ // `current` must be a getter, not just a final field,
+ // to match the external declaration.
+ @patch
+ static Isolate get current => _unsupported();
+
+ @patch
+ String get debugName => _unsupported();
+
+ @patch
+ static Future<Uri> get packageRoot => _unsupported();
+
+ @patch
+ static Future<Uri> get packageConfig => _unsupported();
+
+ @patch
+ static Future<Uri> resolvePackageUri(Uri packageUri) => _unsupported();
+
+ @patch
+ static Future<Isolate> spawn<T>(void entryPoint(T message), T message,
+ {bool paused = false,
+ bool errorsAreFatal,
+ SendPort onExit,
+ SendPort onError}) =>
+ _unsupported();
+
+ @patch
+ static Future<Isolate> spawnUri(Uri uri, List<String> args, var message,
+ {bool paused = false,
+ SendPort onExit,
+ SendPort onError,
+ bool errorsAreFatal,
+ bool checked,
+ Map<String, String> environment,
+ Uri packageRoot,
+ Uri packageConfig,
+ bool automaticPackageResolution = false}) =>
+ _unsupported();
+
+ @patch
+ void _pause(Capability resumeCapability) => _unsupported();
+
+ @patch
+ void resume(Capability resumeCapability) => _unsupported();
+
+ @patch
+ void addOnExitListener(SendPort responsePort, {Object response}) =>
+ _unsupported();
+
+ @patch
+ void removeOnExitListener(SendPort responsePort) => _unsupported();
+
+ @patch
+ void setErrorsFatal(bool errorsAreFatal) => _unsupported();
+
+ @patch
+ void kill({int priority = beforeNextEvent}) => _unsupported();
+ @patch
+ void ping(SendPort responsePort,
+ {Object response, int priority = immediate}) =>
+ _unsupported();
+
+ @patch
+ void addErrorListener(SendPort port) => _unsupported();
+
+ @patch
+ void removeErrorListener(SendPort port) => _unsupported();
+}
+
+/** Default factory for receive ports. */
+@patch
+class ReceivePort {
+ @patch
+ factory ReceivePort() = _ReceivePort;
+
+ @patch
+ factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) =>
+ _unsupported();
+}
+
+/// ReceivePort is supported by dev_compiler because async test packages
+/// (async_helper, unittest) create a dummy receive port to keep the Dart VM
+/// alive.
+class _ReceivePort extends Stream implements ReceivePort {
+ close() {}
+
+ get sendPort => _unsupported();
+
+ listen(onData, {onError, onDone, cancelOnError}) => _unsupported();
+}
+
+@patch
+class RawReceivePort {
+ @patch
+ factory RawReceivePort([void handler(event)]) => _unsupported();
+}
+
+@patch
+class Capability {
+ @patch
+ factory Capability() => _unsupported();
+}
+
+@patch
+abstract class TransferableTypedData {
+ @patch
+ factory TransferableTypedData.fromList(List<TypedData> list) =>
+ _unsupported();
+}
+
+@NoReifyGeneric()
+T _unsupported<T>() {
+ throw UnsupportedError('dart:isolate is not supported on dart4web');
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/math_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/math_patch.dart
new file mode 100644
index 0000000..2ba4220
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/math_patch.dart
@@ -0,0 +1,348 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:math library.
+import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper' show patch, nullCheck, notNull;
+import 'dart:typed_data' show ByteData;
+
+@patch
+@notNull
+T min<T extends num>(@nullCheck T a, @nullCheck T b) =>
+ JS('-dynamic', r'Math.min(#, #)', a, b);
+
+@patch
+@notNull
+T max<T extends num>(@nullCheck T a, @nullCheck T b) =>
+ JS('-dynamic', r'Math.max(#, #)', a, b);
+
+@patch
+@notNull
+double sqrt(@nullCheck num x) => JS<num>('!', r'Math.sqrt(#)', x);
+
+@patch
+@notNull
+double sin(@nullCheck num radians) => JS<num>('!', r'Math.sin(#)', radians);
+
+@patch
+@notNull
+double cos(@nullCheck num radians) => JS<num>('!', r'Math.cos(#)', radians);
+
+@patch
+@notNull
+double tan(@nullCheck num radians) => JS<num>('!', r'Math.tan(#)', radians);
+
+@patch
+@notNull
+double acos(@nullCheck num x) => JS<num>('!', r'Math.acos(#)', x);
+
+@patch
+@notNull
+double asin(@nullCheck num x) => JS<num>('!', r'Math.asin(#)', x);
+
+@patch
+@notNull
+double atan(@nullCheck num x) => JS<num>('!', r'Math.atan(#)', x);
+
+@patch
+@notNull
+double atan2(@nullCheck num a, @nullCheck num b) =>
+ JS<num>('!', r'Math.atan2(#, #)', a, b);
+
+@patch
+@notNull
+double exp(@nullCheck num x) => JS<num>('!', r'Math.exp(#)', x);
+
+@patch
+@notNull
+double log(@nullCheck num x) => JS<num>('!', r'Math.log(#)', x);
+
+@patch
+@notNull
+num pow(@nullCheck num x, @nullCheck num exponent) =>
+ JS<num>('!', r'Math.pow(#, #)', x, exponent);
+
+const int _POW2_32 = 0x100000000;
+
+@patch
+class Random {
+ static Random _secureRandom;
+
+ @patch
+ factory Random([int seed]) =>
+ (seed == null) ? const _JSRandom() : _Random(seed);
+
+ @patch
+ factory Random.secure() => _secureRandom ??= _JSSecureRandom();
+}
+
+class _JSRandom implements Random {
+ // The Dart2JS implementation of Random doesn't use a seed.
+ const _JSRandom();
+
+ @notNull
+ int nextInt(int max) {
+ if (max <= 0 || max > _POW2_32) {
+ throw RangeError("max must be in range 0 < max ≤ 2^32, was $max");
+ }
+ return JS("int", "(Math.random() * #) >>> 0", max);
+ }
+
+ /**
+ * Generates a positive random floating point value uniformly distributed on
+ * the range from 0.0, inclusive, to 1.0, exclusive.
+ */
+ @notNull
+ double nextDouble() => JS("double", "Math.random()");
+
+ /**
+ * Generates a random boolean value.
+ */
+ @notNull
+ bool nextBool() => JS("bool", "Math.random() < 0.5");
+}
+
+class _Random implements Random {
+ // Constants used by the algorithm or masking.
+ static const double _POW2_53_D = 1.0 * (0x20000000000000);
+ static const double _POW2_27_D = 1.0 * (1 << 27);
+ static const int _MASK32 = 0xFFFFFFFF;
+
+ // State comprised of two unsigned 32 bit integers.
+ @notNull
+ int _lo = 0;
+ @notNull
+ int _hi = 0;
+
+ // Implements:
+ // uint64_t hash = 0;
+ // do {
+ // hash = hash * 1037 ^ mix64((uint64_t)seed);
+ // seed >>= 64;
+ // } while (seed != 0 && seed != -1); // Limits for pos/neg seed.
+ // if (hash == 0) {
+ // hash = 0x5A17;
+ // }
+ // _lo = hash & _MASK_32;
+ // _hi = hash >> 32;
+ // and then does four _nextState calls to shuffle bits around.
+ _Random(int seed) {
+ int empty_seed = 0;
+ if (seed < 0) {
+ empty_seed = -1;
+ }
+ do {
+ int low = seed & _MASK32;
+ seed = (seed - low) ~/ _POW2_32;
+ int high = seed & _MASK32;
+ seed = (seed - high) ~/ _POW2_32;
+
+ // Thomas Wang's 64-bit mix function.
+ // http://www.concentric.net/~Ttwang/tech/inthash.htm
+ // via. http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
+
+ // key = ~key + (key << 21);
+ int tmplow = low << 21;
+ int tmphigh = (high << 21) | (low >> 11);
+ tmplow = (~low & _MASK32) + tmplow;
+ low = tmplow & _MASK32;
+ high = (~high + tmphigh + ((tmplow - low) ~/ 0x100000000)) & _MASK32;
+ // key = key ^ (key >> 24).
+ tmphigh = high >> 24;
+ tmplow = (low >> 24) | (high << 8);
+ low ^= tmplow;
+ high ^= tmphigh;
+ // key = key * 265
+ tmplow = low * 265;
+ low = tmplow & _MASK32;
+ high = (high * 265 + (tmplow - low) ~/ 0x100000000) & _MASK32;
+ // key = key ^ (key >> 14);
+ tmphigh = high >> 14;
+ tmplow = (low >> 14) | (high << 18);
+ low ^= tmplow;
+ high ^= tmphigh;
+ // key = key * 21
+ tmplow = low * 21;
+ low = tmplow & _MASK32;
+ high = (high * 21 + (tmplow - low) ~/ 0x100000000) & _MASK32;
+ // key = key ^ (key >> 28).
+ tmphigh = high >> 28;
+ tmplow = (low >> 28) | (high << 4);
+ low ^= tmplow;
+ high ^= tmphigh;
+ // key = key + (key << 31);
+ tmplow = low << 31;
+ tmphigh = (high << 31) | (low >> 1);
+ tmplow += low;
+ low = tmplow & _MASK32;
+ high = (high + tmphigh + (tmplow - low) ~/ 0x100000000) & _MASK32;
+ // Mix end.
+
+ // seed = seed * 1037 ^ key;
+ tmplow = _lo * 1037;
+ _lo = tmplow & _MASK32;
+ _hi = (_hi * 1037 + (tmplow - _lo) ~/ 0x100000000) & _MASK32;
+ _lo ^= low;
+ _hi ^= high;
+ } while (seed != empty_seed);
+
+ if (_hi == 0 && _lo == 0) {
+ _lo = 0x5A17;
+ }
+ _nextState();
+ _nextState();
+ _nextState();
+ _nextState();
+ }
+
+ // The algorithm used here is Multiply with Carry (MWC) with a Base b = 2^32.
+ // http://en.wikipedia.org/wiki/Multiply-with-carry
+ // The constant A (0xFFFFDA61) is selected from "Numerical Recipes 3rd
+ // Edition" p.348 B1.
+
+ // Implements:
+ // var state = (A * _lo + _hi) & _MASK_64;
+ // _lo = state & _MASK_32;
+ // _hi = state >> 32;
+ void _nextState() {
+ // Simulate (0xFFFFDA61 * lo + hi) without overflowing 53 bits.
+ int tmpHi = 0xFFFF0000 * _lo; // At most 48 bits of significant result.
+ int tmpHiLo = tmpHi & _MASK32; // Get the lower 32 bits.
+ int tmpHiHi = tmpHi - tmpHiLo; // And just the upper 32 bits.
+ int tmpLo = 0xDA61 * _lo;
+ int tmpLoLo = tmpLo & _MASK32;
+ int tmpLoHi = tmpLo - tmpLoLo;
+
+ int newLo = tmpLoLo + tmpHiLo + _hi;
+ _lo = newLo & _MASK32;
+ int newLoHi = newLo - _lo;
+ _hi = ((tmpLoHi + tmpHiHi + newLoHi) ~/ _POW2_32) & _MASK32;
+ assert(_lo < _POW2_32);
+ assert(_hi < _POW2_32);
+ }
+
+ @notNull
+ int nextInt(@nullCheck int max) {
+ if (max <= 0 || max > _POW2_32) {
+ throw RangeError("max must be in range 0 < max ≤ 2^32, was $max");
+ }
+ if ((max & (max - 1)) == 0) {
+ // Fast case for powers of two.
+ _nextState();
+ return _lo & (max - 1);
+ }
+
+ int rnd32;
+ int result;
+ do {
+ _nextState();
+ rnd32 = _lo;
+ result = rnd32.remainder(max); // % max;
+ } while ((rnd32 - result + max) >= _POW2_32);
+ return result;
+ }
+
+ @notNull
+ double nextDouble() {
+ _nextState();
+ int bits26 = _lo & ((1 << 26) - 1);
+ _nextState();
+ int bits27 = _lo & ((1 << 27) - 1);
+ return (bits26 * _POW2_27_D + bits27) / _POW2_53_D;
+ }
+
+ @notNull
+ bool nextBool() {
+ _nextState();
+ return (_lo & 1) == 0;
+ }
+}
+
+class _JSSecureRandom implements Random {
+ // Reused buffer with room enough for a double.
+ final _buffer = ByteData(8);
+
+ _JSSecureRandom() {
+ var crypto = JS("", "self.crypto");
+ if (crypto != null) {
+ var getRandomValues = JS("", "#.getRandomValues", crypto);
+ if (getRandomValues != null) {
+ return;
+ }
+ }
+ throw UnsupportedError(
+ "No source of cryptographically secure random numbers available.");
+ }
+
+ /// Fill _buffer from [start] to `start + length` with random bytes.
+ void _getRandomBytes(int start, int length) {
+ JS("void", "crypto.getRandomValues(#)",
+ _buffer.buffer.asUint8List(start, length));
+ }
+
+ @notNull
+ bool nextBool() {
+ _getRandomBytes(0, 1);
+ return _buffer.getUint8(0).isOdd;
+ }
+
+ @notNull
+ double nextDouble() {
+ _getRandomBytes(1, 7);
+ // Set top bits 12 of double to 0x3FF which is the exponent for numbers
+ // between 1.0 and 2.0.
+ _buffer.setUint8(0, 0x3F);
+ int highByte = _buffer.getUint8(1);
+ _buffer.setUint8(1, highByte | 0xF0);
+
+ // Buffer now contains double in the range [1.0-2.0)
+ // with 52 bits of entropy (not 53).
+ // To get 53 bits, we extract the 53rd bit from higthByte before
+ // overwriting it, and add that as a least significant bit.
+ // The getFloat64 method is big-endian as default.
+ double result = _buffer.getFloat64(0) - 1.0;
+ if (highByte & 0x10 != 0) {
+ result += 1.1102230246251565e-16; // pow(2,-53).
+ }
+ return result;
+ }
+
+ @notNull
+ int nextInt(@nullCheck int max) {
+ if (max <= 0 || max > _POW2_32) {
+ throw RangeError("max must be in range 0 < max ≤ 2^32, was $max");
+ }
+ int byteCount = 1;
+ if (max > 0xFF) {
+ byteCount++;
+ if (max > 0xFFFF) {
+ byteCount++;
+ if (max > 0xFFFFFF) {
+ byteCount++;
+ }
+ }
+ }
+ _buffer.setUint32(0, 0);
+ int start = 4 - byteCount;
+ int randomLimit = pow(256, byteCount);
+ while (true) {
+ _getRandomBytes(start, byteCount);
+ // The getUint32 method is big-endian as default.
+ int random = _buffer.getUint32(0);
+ if (max & (max - 1) == 0) {
+ // Max is power of 2.
+ return random & (max - 1);
+ }
+ int result = random.remainder(max);
+ // Ensure results have equal probability by rejecting values in the
+ // last range of k*max .. 256**byteCount.
+ // TODO: Consider picking a higher byte count if the last range is a
+ // significant portion of the entire range - a 50% chance of having
+ // to use two more bytes is no worse than always using one more.
+ if (random - result + max < randomLimit) {
+ return result;
+ }
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart
new file mode 100644
index 0000000..e3b015b
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch library for dart:mirrors.
+
+import 'dart:_js_helper' show patch;
+import 'dart:_js_mirrors' as js;
+import 'dart:_runtime' as dart;
+
+@patch
+class MirrorSystem {
+ @patch
+ LibraryMirror findLibrary(Symbol libraryName) {
+ return libraries.values
+ .singleWhere((library) => library.simpleName == libraryName);
+ }
+
+ @patch
+ static String getName(Symbol symbol) => js.getName(symbol);
+
+ @patch
+ static Symbol getSymbol(String name, [LibraryMirror library]) {
+ return js.getSymbol(name, library);
+ }
+}
+
+@patch
+MirrorSystem currentMirrorSystem() => js.currentJsMirrorSystem;
+
+@patch
+InstanceMirror reflect(Object reflectee) => js.reflect(reflectee);
+
+@patch
+ClassMirror reflectClass(Type key) {
+ if (key is! Type || key == dynamic) {
+ throw ArgumentError('$key does not denote a class');
+ }
+ TypeMirror tm = reflectType(key);
+ if (tm is! ClassMirror) {
+ throw ArgumentError("$key does not denote a class");
+ }
+ return (tm as ClassMirror).originalDeclaration;
+}
+
+@patch
+TypeMirror reflectType(Type type, [List<Type> typeArguments]) {
+ if (typeArguments != null) {
+ type = _instantiateClass(type, typeArguments);
+ }
+ return js.reflectType(type);
+}
+
+/// Instantiates the generic class [type] with [typeArguments] and returns the
+/// result.
+///
+/// [type] may be instantiated with type arguments already. In that case, they
+/// are ignored. For example calling this function with `(List<int>, [String])`
+/// and `(List<dynamic>, [String])` will produce `List<String>` in both cases.
+Type _instantiateClass(Type type, List<Type> typeArguments) {
+ var unwrapped = dart.unwrapType(type);
+ var genericClass = dart.getGenericClass(unwrapped);
+ if (genericClass == null) {
+ throw ArgumentError('Type `$type` must be generic to apply '
+ 'type arguments: `$typeArguments`.');
+ }
+
+ var typeArgsLenth = typeArguments.length;
+ var unwrappedArgs = List(typeArgsLenth);
+ for (int i = 0; i < typeArgsLenth; i++) {
+ unwrappedArgs[i] = dart.unwrapType(typeArguments[i]);
+ }
+ var typeFormals = dart.getGenericTypeFormals(genericClass);
+ if (typeFormals.length != typeArgsLenth) {
+ throw ArgumentError('Type `$type` has ${typeFormals.length} type '
+ 'parameters, but $typeArgsLenth type arguments were '
+ 'passed: `$typeArguments`.');
+ }
+ // TODO(jmesserly): this does not validate bounds, as we don't have them
+ // available at runtime. Consider storing them when dart:mirrors is enabled.
+ return dart.wrapType(dart.instantiateClass(genericClass, unwrappedArgs));
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart
new file mode 100644
index 0000000..f1e2dc1
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart
@@ -0,0 +1,191 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+import 'dart:_js_helper' show patch;
+import 'dart:_native_typed_data';
+
+@patch
+class ByteData {
+ @patch
+ factory ByteData(int length) = NativeByteData;
+}
+
+@patch
+class Float32List {
+ @patch
+ factory Float32List(int length) = NativeFloat32List;
+
+ @patch
+ factory Float32List.fromList(List<double> elements) =
+ NativeFloat32List.fromList;
+}
+
+@patch
+class Float64List {
+ @patch
+ factory Float64List(int length) = NativeFloat64List;
+
+ @patch
+ factory Float64List.fromList(List<double> elements) =
+ NativeFloat64List.fromList;
+}
+
+@patch
+class Int16List {
+ @patch
+ factory Int16List(int length) = NativeInt16List;
+
+ @patch
+ factory Int16List.fromList(List<int> elements) = NativeInt16List.fromList;
+}
+
+@patch
+class Int32List {
+ @patch
+ factory Int32List(int length) = NativeInt32List;
+
+ @patch
+ factory Int32List.fromList(List<int> elements) = NativeInt32List.fromList;
+}
+
+@patch
+class Int8List {
+ @patch
+ factory Int8List(int length) = NativeInt8List;
+
+ @patch
+ factory Int8List.fromList(List<int> elements) = NativeInt8List.fromList;
+}
+
+@patch
+class Uint32List {
+ @patch
+ factory Uint32List(int length) = NativeUint32List;
+
+ @patch
+ factory Uint32List.fromList(List<int> elements) = NativeUint32List.fromList;
+}
+
+@patch
+class Uint16List {
+ @patch
+ factory Uint16List(int length) = NativeUint16List;
+
+ @patch
+ factory Uint16List.fromList(List<int> elements) = NativeUint16List.fromList;
+}
+
+@patch
+class Uint8ClampedList {
+ @patch
+ factory Uint8ClampedList(int length) = NativeUint8ClampedList;
+
+ @patch
+ factory Uint8ClampedList.fromList(List<int> elements) =
+ NativeUint8ClampedList.fromList;
+}
+
+@patch
+class Uint8List {
+ @patch
+ factory Uint8List(int length) = NativeUint8List;
+
+ @patch
+ factory Uint8List.fromList(List<int> elements) = NativeUint8List.fromList;
+}
+
+@patch
+class Int64List {
+ @patch
+ factory Int64List(int length) {
+ throw UnsupportedError("Int64List not supported by dart2js.");
+ }
+
+ @patch
+ factory Int64List.fromList(List<int> elements) {
+ throw UnsupportedError("Int64List not supported by dart2js.");
+ }
+}
+
+@patch
+class Uint64List {
+ @patch
+ factory Uint64List(int length) {
+ throw UnsupportedError("Uint64List not supported by dart2js.");
+ }
+
+ @patch
+ factory Uint64List.fromList(List<int> elements) {
+ throw UnsupportedError("Uint64List not supported by dart2js.");
+ }
+}
+
+@patch
+class Int32x4List {
+ @patch
+ factory Int32x4List(int length) = NativeInt32x4List;
+
+ @patch
+ factory Int32x4List.fromList(List<Int32x4> elements) =
+ NativeInt32x4List.fromList;
+}
+
+@patch
+class Float32x4List {
+ @patch
+ factory Float32x4List(int length) = NativeFloat32x4List;
+
+ @patch
+ factory Float32x4List.fromList(List<Float32x4> elements) =
+ NativeFloat32x4List.fromList;
+}
+
+@patch
+class Float64x2List {
+ @patch
+ factory Float64x2List(int length) = NativeFloat64x2List;
+
+ @patch
+ factory Float64x2List.fromList(List<Float64x2> elements) =
+ NativeFloat64x2List.fromList;
+}
+
+@patch
+class Float32x4 {
+ @patch
+ factory Float32x4(double x, double y, double z, double w) = NativeFloat32x4;
+ @patch
+ factory Float32x4.splat(double v) = NativeFloat32x4.splat;
+ @patch
+ factory Float32x4.zero() = NativeFloat32x4.zero;
+ @patch
+ factory Float32x4.fromInt32x4Bits(Int32x4 x) =
+ NativeFloat32x4.fromInt32x4Bits;
+ @patch
+ factory Float32x4.fromFloat64x2(Float64x2 v) = NativeFloat32x4.fromFloat64x2;
+}
+
+@patch
+class Int32x4 {
+ @patch
+ factory Int32x4(int x, int y, int z, int w) = NativeInt32x4;
+ @patch
+ factory Int32x4.bool(bool x, bool y, bool z, bool w) = NativeInt32x4.bool;
+ @patch
+ factory Int32x4.fromFloat32x4Bits(Float32x4 x) =
+ NativeInt32x4.fromFloat32x4Bits;
+}
+
+@patch
+class Float64x2 {
+ @patch
+ factory Float64x2(double x, double y) = NativeFloat64x2;
+ @patch
+ factory Float64x2.splat(double v) = NativeFloat64x2.splat;
+ @patch
+ factory Float64x2.zero() = NativeFloat64x2.zero;
+ @patch
+ factory Float64x2.fromFloat32x4(Float32x4 v) = NativeFloat64x2.fromFloat32x4;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/annotations.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/annotations.dart
new file mode 100644
index 0000000..bc437da
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/annotations.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._js_helper;
+
+/// Tells the optimizing compiler to always inline the annotated method.
+class ForceInline {
+ const ForceInline();
+}
+
+class _NotNull {
+ const _NotNull();
+}
+
+/// Marks a variable or API to be non-nullable.
+/// ****CAUTION******
+/// This is currently unchecked, and hence should never be used
+/// on any public interface where user code could subclass, implement,
+/// or otherwise cause the contract to be violated.
+/// TODO(leafp): Consider adding static checking and exposing
+/// this to user code.
+const notNull = _NotNull();
+
+/// Marks a generic function or static method API to be not reified.
+/// ****CAUTION******
+/// This is currently unchecked, and hence should be used very carefully for
+/// internal SDK APIs only.
+class NoReifyGeneric {
+ const NoReifyGeneric();
+}
+
+/// Enables/disables reification of functions within the body of this function.
+/// ****CAUTION******
+/// This is currently unchecked, and hence should be used very carefully for
+/// internal SDK APIs only.
+class ReifyFunctionTypes {
+ final bool value;
+ const ReifyFunctionTypes(this.value);
+}
+
+class _NullCheck {
+ const _NullCheck();
+}
+
+/// Annotation indicating the parameter should default to the JavaScript
+/// undefined constant.
+const undefined = _Undefined();
+
+class _Undefined {
+ const _Undefined();
+}
+
+/// Tells the development compiler to check a variable for null at its
+/// declaration point, and then to assume that the variable is non-null
+/// from that point forward.
+/// ****CAUTION******
+/// This is currently unchecked, and hence will not catch re-assignments
+/// of a variable with null
+const nullCheck = _NullCheck();
+
+/// Tells the optimizing compiler that the annotated method cannot throw.
+/// Requires @NoInline() to function correctly.
+class NoThrows {
+ const NoThrows();
+}
+
+/// Tells the optimizing compiler to not inline the annotated method.
+class NoInline {
+ const NoInline();
+}
+
+/// Marks a class as native and defines its JavaScript name(s).
+class Native {
+ final String name;
+ const Native(this.name);
+}
+
+class JsPeerInterface {
+ /// The JavaScript type that we should match the API of.
+ /// Used for classes where Dart subclasses should be callable from JavaScript
+ /// matching the JavaScript calling conventions.
+ final String name;
+ const JsPeerInterface({this.name});
+}
+
+/// A Dart interface may only be implemented by a native JavaScript object
+/// if it is marked with this annotation.
+class SupportJsExtensionMethods {
+ const SupportJsExtensionMethods();
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/custom_hash_map.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/custom_hash_map.dart
new file mode 100644
index 0000000..c7c920d
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/custom_hash_map.dart
@@ -0,0 +1,197 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._js_helper;
+
+class CustomKeyHashMap<K, V> extends CustomHashMap<K, V> {
+ final _Predicate<Object> _validKey;
+ CustomKeyHashMap(_Equality<K> equals, _Hasher<K> hashCode, this._validKey)
+ : super(equals, hashCode);
+
+ @override
+ @notNull
+ bool containsKey(Object key) {
+ if (!_validKey(key)) return false;
+ return super.containsKey(key);
+ }
+
+ @override
+ V operator [](Object key) {
+ if (!_validKey(key)) return null;
+ return super[key];
+ }
+
+ @override
+ V remove(Object key) {
+ if (!_validKey(key)) return null;
+ return super.remove(key);
+ }
+}
+
+class CustomHashMap<K, V> extends InternalMap<K, V> {
+ /// The backing store for this map.
+ @notNull
+ final _map = JS('', 'new Map()');
+
+ /// Our map used to map keys onto the canonical key that is stored in [_map].
+ @notNull
+ final _keyMap = JS('', 'new Map()');
+
+ // We track the number of modifications done to the key set of the
+ // hash map to be able to throw when the map is modified while being
+ // iterated over.
+ //
+ // Value cycles after 2^30 modifications so that modification counts are
+ // always unboxed (Smi) values. Modification detection will be missed if you
+ // make exactly some multiple of 2^30 modifications between advances of an
+ // iterator.
+ @notNull
+ int _modifications = 0;
+
+ final _Equality<K> _equals;
+ final _Hasher<K> _hashCode;
+
+ CustomHashMap(this._equals, this._hashCode);
+
+ @notNull
+ int get length => JS<int>('!', '#.size', _map);
+
+ @notNull
+ bool get isEmpty => JS<bool>('!', '#.size == 0', _map);
+
+ @notNull
+ bool get isNotEmpty => JS<bool>('!', '#.size != 0', _map);
+
+ Iterable<K> get keys => _JSMapIterable<K>(this, true);
+ Iterable<V> get values => _JSMapIterable<V>(this, false);
+
+ @notNull
+ bool containsKey(Object key) {
+ if (key is K) {
+ var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
+ if (buckets != null) {
+ var equals = _equals;
+ for (int i = 0, n = JS<int>('!', '#.length', buckets); i < n; i++) {
+ K k = JS('', '#[#]', buckets, i);
+ if (equals(k, key)) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool containsValue(Object value) {
+ for (var v in JS('', '#.values()', _map)) {
+ if (value == v) return true;
+ }
+ return false;
+ }
+
+ void addAll(Map<K, V> other) {
+ other.forEach((K key, V value) {
+ this[key] = value;
+ });
+ }
+
+ V operator [](Object key) {
+ if (key is K) {
+ var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
+ if (buckets != null) {
+ var equals = _equals;
+ for (int i = 0, n = JS<int>('!', '#.length', buckets); i < n; i++) {
+ K k = JS('', '#[#]', buckets, i);
+ if (equals(k, key)) {
+ V value = JS('', '#.get(#)', _map, k);
+ return value == null ? null : value; // coerce undefined to null.
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ void operator []=(K key, V value) {
+ var keyMap = _keyMap;
+ int hash = JS('!', '# & 0x3ffffff', _hashCode(key));
+ var buckets = JS('', '#.get(#)', keyMap, hash);
+ if (buckets == null) {
+ JS('', '#.set(#, [#])', keyMap, hash, key);
+ } else {
+ var equals = _equals;
+ for (int i = 0, n = JS<int>('!', '#.length', buckets);;) {
+ K k = JS('', '#[#]', buckets, i);
+ if (equals(k, key)) {
+ key = k;
+ break;
+ }
+ if (++i >= n) {
+ JS('', '#.push(#)', buckets, key);
+ break;
+ }
+ }
+ }
+ JS('', '#.set(#, #)', _map, key, value);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+
+ V putIfAbsent(K key, V ifAbsent()) {
+ var keyMap = _keyMap;
+ int hash = JS('!', '# & 0x3ffffff', _hashCode(key));
+ var buckets = JS('', '#.get(#)', keyMap, hash);
+ if (buckets == null) {
+ JS('', '#.set(#, [#])', keyMap, hash, key);
+ } else {
+ var equals = _equals;
+ for (int i = 0, n = JS<int>('!', '#.length', buckets); i < n; i++) {
+ K k = JS('', '#[#]', buckets, i);
+ if (equals(k, key)) return JS('', '#.get(#)', _map, k);
+ }
+ JS('', '#.push(#)', buckets, key);
+ }
+ V value = ifAbsent();
+ if (value == null) value = null; // coerce undefined to null.
+ JS('', '#.set(#, #)', _map, key, value);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ return value;
+ }
+
+ V remove(Object key) {
+ if (key is K) {
+ int hash = JS('!', '# & 0x3ffffff', _hashCode(key));
+ var keyMap = _keyMap;
+ var buckets = JS('', '#.get(#)', keyMap, hash);
+ if (buckets == null) return null; // not found
+ var equals = _equals;
+ for (int i = 0, n = JS<int>('!', '#.length', buckets); i < n; i++) {
+ K k = JS('', '#[#]', buckets, i);
+ if (equals(k, key)) {
+ if (n == 1) {
+ JS('', '#.delete(#)', keyMap, hash);
+ } else {
+ JS('', '#.splice(#, 1)', buckets, i);
+ }
+ var map = _map;
+ V value = JS('', '#.get(#)', map, k);
+ JS('', '#.delete(#)', map, k);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ return value == null ? null : value; // coerce undefined to null.
+ }
+ }
+ }
+ return null;
+ }
+
+ void clear() {
+ var map = _map;
+ if (JS<int>('!', '#.size', map) > 0) {
+ JS('', '#.clear()', map);
+ JS('', '#.clear()', _keyMap);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ }
+}
+
+typedef bool _Equality<K>(K a, K b);
+typedef int _Hasher<K>(K object);
+typedef bool _Predicate<T>(T value);
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart
new file mode 100644
index 0000000..8fe2fa6
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart
@@ -0,0 +1,537 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This library defines the operations that define and manipulate Dart
+/// classes. Included in this are:
+/// - Generics
+/// - Class metadata
+/// - Extension methods
+///
+
+// TODO(leafp): Consider splitting some of this out.
+part of dart._runtime;
+
+/// Returns a new type that mixes members from base and the mixin.
+void applyMixin(to, from) {
+ JS('', '#[#] = #', to, _mixin, from);
+ var toProto = JS('', '#.prototype', to);
+ var fromProto = JS('', '#.prototype', from);
+ _copyMembers(toProto, fromProto);
+ _mixinSignature(to, from, _methodSig);
+ _mixinSignature(to, from, _fieldSig);
+ _mixinSignature(to, from, _getterSig);
+ _mixinSignature(to, from, _setterSig);
+ var mixinOnFn = JS('', '#[#]', from, mixinOn);
+ if (mixinOnFn != null) {
+ var proto = JS('', '#(#.__proto__).prototype', mixinOnFn, to);
+ _copyMembers(toProto, proto);
+ }
+}
+
+void _copyMembers(to, from) {
+ var names = getOwnNamesAndSymbols(from);
+ for (int i = 0, n = JS('!', '#.length', names); i < n; ++i) {
+ String name = JS('', '#[#]', names, i);
+ if (name == 'constructor') continue;
+ _copyMember(to, from, name);
+ }
+ return to;
+}
+
+void _copyMember(to, from, name) {
+ var desc = getOwnPropertyDescriptor(from, name);
+ if (JS('!', '# == Symbol.iterator', name)) {
+ // On native types, Symbol.iterator may already be present.
+ // TODO(jmesserly): investigate if we still need this.
+ // If so, we need to find a better solution.
+ // See https://github.com/dart-lang/sdk/issues/28324
+ var existing = getOwnPropertyDescriptor(to, name);
+ if (existing != null) {
+ if (JS('!', '#.writable', existing)) {
+ JS('', '#[#] = #.value', to, name, desc);
+ }
+ return;
+ }
+ }
+ var getter = JS('', '#.get', desc);
+ var setter = JS('', '#.set', desc);
+ if (getter != null) {
+ if (setter == null) {
+ var obj = JS(
+ '',
+ '#.set = { __proto__: #.__proto__, '
+ 'set [#](x) { return super[#] = x; } }',
+ desc,
+ to,
+ name,
+ name);
+ JS('', '#.set = #.set', desc, getOwnPropertyDescriptor(obj, name));
+ }
+ } else if (setter != null) {
+ if (getter == null) {
+ var obj = JS(
+ '',
+ '#.get = { __proto__: #.__proto__, '
+ 'get [#]() { return super[#]; } }',
+ desc,
+ to,
+ name,
+ name);
+ JS('', '#.get = #.get', desc, getOwnPropertyDescriptor(obj, name));
+ }
+ }
+ defineProperty(to, name, desc);
+}
+
+void _mixinSignature(to, from, kind) {
+ JS('', '#[#] = #', to, kind, () {
+ var baseMembers = _getMembers(JS('', '#.__proto__', to), kind);
+ var fromMembers = _getMembers(from, kind);
+ if (fromMembers == null) return baseMembers;
+ var toSignature = JS('', '{ __proto__: # }', baseMembers);
+ copyProperties(toSignature, fromMembers);
+ return toSignature;
+ });
+}
+
+final _mixin = JS('', 'Symbol("mixin")');
+
+getMixin(clazz) => JS('', 'Object.hasOwnProperty.call(#, #) ? #[#] : null',
+ clazz, _mixin, clazz, _mixin);
+
+final mixinOn = JS('', 'Symbol("mixinOn")');
+
+@JSExportName('implements')
+final implements_ = JS('', 'Symbol("implements")');
+
+List Function() getImplements(clazz) => JS(
+ '',
+ 'Object.hasOwnProperty.call(#, #) ? #[#] : null',
+ clazz,
+ implements_,
+ clazz,
+ implements_);
+
+/// The Symbol for storing type arguments on a specialized generic type.
+final _typeArguments = JS('', 'Symbol("typeArguments")');
+
+final _originalDeclaration = JS('', 'Symbol("originalDeclaration")');
+
+final mixinNew = JS('', 'Symbol("dart.mixinNew")');
+
+/// Memoize a generic type constructor function.
+generic(typeConstructor, setBaseClass) => JS('', '''(() => {
+ let length = $typeConstructor.length;
+ if (length < 1) {
+ $throwInternalError('must have at least one generic type argument');
+ }
+ let resultMap = new Map();
+ // TODO(vsm): Rethink how to clear the resultMap on hot restart.
+ // A simple clear via:
+ // _cacheMaps.push(resultMap);
+ // will break (a) we hoist type expressions in generated code and
+ // (b) we don't clear those type expressions in the presence of a
+ // hot restart. Not clearing this map (as we're doing now) should
+ // not affect correctness, but can result in a memory leak across
+ // multiple restarts.
+ function makeGenericType(...args) {
+ if (args.length != length && args.length != 0) {
+ $throwInternalError('requires ' + length + ' or 0 type arguments');
+ }
+ while (args.length < length) args.push($dynamic);
+
+ let value = resultMap;
+ for (let i = 0; i < length; i++) {
+ let arg = args[i];
+ if (arg == null) {
+ $throwInternalError('type arguments should not be null: '
+ + $typeConstructor);
+ }
+ let map = value;
+ value = map.get(arg);
+ if (value === void 0) {
+ if (i + 1 == length) {
+ value = $typeConstructor.apply(null, args);
+ // Save the type constructor and arguments for reflection.
+ if (value) {
+ value[$_typeArguments] = args;
+ value[$_originalDeclaration] = makeGenericType;
+ }
+ map.set(arg, value);
+ if ($setBaseClass != null) $setBaseClass.apply(null, args);
+ } else {
+ value = new Map();
+ map.set(arg, value);
+ }
+ }
+ }
+ return value;
+ }
+ makeGenericType[$_genericTypeCtor] = $typeConstructor;
+ return makeGenericType;
+})()''');
+
+getGenericClass(type) => safeGetOwnProperty(type, _originalDeclaration);
+
+List getGenericArgs(type) =>
+ JS('List', '#', safeGetOwnProperty(type, _typeArguments));
+
+List<TypeVariable> getGenericTypeFormals(genericClass) {
+ return _typeFormalsFromFunction(getGenericTypeCtor(genericClass));
+}
+
+Object instantiateClass(Object genericClass, List<Object> typeArgs) {
+ return JS('', '#.apply(null, #)', genericClass, typeArgs);
+}
+
+final _constructorSig = JS('', 'Symbol("sigCtor")');
+final _methodSig = JS('', 'Symbol("sigMethod")');
+final _fieldSig = JS('', 'Symbol("sigField")');
+final _getterSig = JS('', 'Symbol("sigGetter")');
+final _setterSig = JS('', 'Symbol("sigSetter")');
+final _staticMethodSig = JS('', 'Symbol("sigStaticMethod")');
+final _staticFieldSig = JS('', 'Symbol("sigStaticField")');
+final _staticGetterSig = JS('', 'Symbol("sigStaticGetter")');
+final _staticSetterSig = JS('', 'Symbol("sigStaticSetter")');
+final _genericTypeCtor = JS('', 'Symbol("genericType")');
+final _libraryUri = JS('', 'Symbol("libraryUri")');
+
+getConstructors(value) => _getMembers(value, _constructorSig);
+getMethods(value) => _getMembers(value, _methodSig);
+getFields(value) => _getMembers(value, _fieldSig);
+getGetters(value) => _getMembers(value, _getterSig);
+getSetters(value) => _getMembers(value, _setterSig);
+getStaticMethods(value) => _getMembers(value, _staticMethodSig);
+getStaticFields(value) => _getMembers(value, _staticFieldSig);
+getStaticGetters(value) => _getMembers(value, _staticGetterSig);
+getStaticSetters(value) => _getMembers(value, _staticSetterSig);
+
+getGenericTypeCtor(value) => JS('', '#[#]', value, _genericTypeCtor);
+
+/// Get the type of a method from an object using the stored signature
+getType(obj) =>
+ JS('', '# == null ? # : #.__proto__.constructor', obj, Object, obj);
+
+getLibraryUri(value) => JS('', '#[#]', value, _libraryUri);
+setLibraryUri(f, uri) => JS('', '#[#] = #', f, _libraryUri, uri);
+
+bool isJsInterop(obj) {
+ if (obj == null) return false;
+ if (JS('!', 'typeof # === "function"', obj)) {
+ // A function is a Dart function if it has runtime type information.
+ return JS('!', '#[#] == null', obj, _runtimeType);
+ }
+ // Primitive types are not JS interop types.
+ if (JS('!', 'typeof # !== "object"', obj)) return false;
+
+ // Extension types are not considered JS interop types.
+ // Note that it is still possible to call typed JS interop methods on
+ // extension types but the calls must be statically typed.
+ if (JS('!', '#[#] != null', obj, _extensionType)) return false;
+ return JS('!', '!($obj instanceof $Object)');
+}
+
+/// Get the type of a method from a type using the stored signature
+getMethodType(type, name) {
+ var m = getMethods(type);
+ return m != null ? JS('', '#[#]', m, name) : null;
+}
+
+/// Gets the type of the corresponding setter (this includes writable fields).
+getSetterType(type, name) {
+ var setters = getSetters(type);
+ if (setters != null) {
+ var type = JS('', '#[#]', setters, name);
+ if (type != null) {
+ if (JS('!', '# instanceof Array', type)) {
+ // The type has metadata attached. Pull out just the type.
+ // TODO(jmesserly): remove when we remove mirrors
+ return JS('', '#[0]', type);
+ }
+ return type;
+ }
+ }
+ var fields = getFields(type);
+ if (fields != null) {
+ var fieldInfo = JS('', '#[#]', fields, name);
+ if (fieldInfo != null && JS<bool>('!', '!#.isFinal', fieldInfo)) {
+ return JS('', '#.type', fieldInfo);
+ }
+ }
+ return null;
+}
+
+finalFieldType(type, metadata) =>
+ JS('', '{ type: #, isFinal: true, metadata: # }', type, metadata);
+
+fieldType(type, metadata) =>
+ JS('', '{ type: #, isFinal: false, metadata: # }', type, metadata);
+
+/// Get the type of a constructor from a class using the stored signature
+/// If name is undefined, returns the type of the default constructor
+/// Returns undefined if the constructor is not found.
+classGetConstructorType(cls, name) {
+ if (cls == null) return null;
+ if (name == null) name = 'new';
+ var ctors = getConstructors(cls);
+ return ctors != null ? JS('', '#[#]', ctors, name) : null;
+}
+
+void setMethodSignature(f, sigF) => JS('', '#[#] = #', f, _methodSig, sigF);
+void setFieldSignature(f, sigF) => JS('', '#[#] = #', f, _fieldSig, sigF);
+void setGetterSignature(f, sigF) => JS('', '#[#] = #', f, _getterSig, sigF);
+void setSetterSignature(f, sigF) => JS('', '#[#] = #', f, _setterSig, sigF);
+
+// Set up the constructor signature field on the constructor
+void setConstructorSignature(f, sigF) =>
+ JS('', '#[#] = #', f, _constructorSig, sigF);
+
+// Set up the static signature field on the constructor
+void setStaticMethodSignature(f, sigF) =>
+ JS('', '#[#] = #', f, _staticMethodSig, sigF);
+
+void setStaticFieldSignature(f, sigF) =>
+ JS('', '#[#] = #', f, _staticFieldSig, sigF);
+
+void setStaticGetterSignature(f, sigF) =>
+ JS('', '#[#] = #', f, _staticGetterSig, sigF);
+
+void setStaticSetterSignature(f, sigF) =>
+ JS('', '#[#] = #', f, _staticSetterSig, sigF);
+
+_getMembers(type, kind) {
+ var sig = JS('', '#[#]', type, kind);
+ return JS<bool>('!', 'typeof # == "function"', sig)
+ ? JS('', '#[#] = #()', type, kind, sig)
+ : sig;
+}
+
+bool _hasMember(type, kind, name) {
+ var sig = _getMembers(type, kind);
+ return sig != null && JS<bool>('!', '# in #', name, sig);
+}
+
+bool hasMethod(type, name) => _hasMember(type, _methodSig, name);
+bool hasGetter(type, name) => _hasMember(type, _getterSig, name);
+bool hasSetter(type, name) => _hasMember(type, _setterSig, name);
+bool hasField(type, name) => _hasMember(type, _fieldSig, name);
+
+final _extensionType = JS('', 'Symbol("extensionType")');
+
+final dartx = JS('', 'dartx');
+
+/// Install properties in prototype-first order. Properties / descriptors from
+/// more specific types should overwrite ones from less specific types.
+void _installProperties(jsProto, dartType, installedParent) {
+ if (JS('!', '# === #', dartType, Object)) {
+ _installPropertiesForObject(jsProto);
+ return;
+ }
+ // If the extension methods of the parent have been installed on the parent
+ // of [jsProto], the methods will be available via prototype inheritance.
+ var dartSupertype = JS('', '#.__proto__', dartType);
+ if (JS('!', '# !== #', dartSupertype, installedParent)) {
+ _installProperties(jsProto, dartSupertype, installedParent);
+ }
+
+ var dartProto = JS('', '#.prototype', dartType);
+ copyTheseProperties(jsProto, dartProto, getOwnPropertySymbols(dartProto));
+}
+
+void _installPropertiesForObject(jsProto) {
+ // core.Object members need to be copied from the non-symbol name to the
+ // symbol name.
+ var coreObjProto = JS('', '#.prototype', Object);
+ var names = getOwnPropertyNames(coreObjProto);
+ for (int i = 0, n = JS('!', '#.length', names); i < n; ++i) {
+ var name = JS<String>('!', '#[#]', names, i);
+ if (name == 'constructor') continue;
+ var desc = getOwnPropertyDescriptor(coreObjProto, name);
+ defineProperty(jsProto, JS('', '#.#', dartx, name), desc);
+ }
+}
+
+void _installPropertiesForGlobalObject(jsProto) {
+ _installPropertiesForObject(jsProto);
+ // Use JS toString for JS objects, rather than the Dart one.
+ JS('', '#[dartx.toString] = function() { return this.toString(); }', jsProto);
+ identityEquals ??= JS('', '#[dartx._equals]', jsProto);
+}
+
+final _extensionMap = JS('', 'new Map()');
+
+_applyExtension(jsType, dartExtType) {
+ // TODO(vsm): Not all registered js types are real.
+ if (jsType == null) return;
+ var jsProto = JS('', '#.prototype', jsType);
+ if (jsProto == null) return;
+
+ if (JS('!', '# === #', dartExtType, Object)) {
+ _installPropertiesForGlobalObject(jsProto);
+ return;
+ }
+
+ _installProperties(
+ jsProto, dartExtType, JS('', '#[#]', jsProto, _extensionType));
+
+ // Mark the JS type's instances so we can easily check for extensions.
+ if (JS('!', '# !== #', dartExtType, JSFunction)) {
+ JS('', '#[#] = #', jsProto, _extensionType, dartExtType);
+ }
+ JS('', '#[#] = #[#]', jsType, _methodSig, dartExtType, _methodSig);
+ JS('', '#[#] = #[#]', jsType, _fieldSig, dartExtType, _fieldSig);
+ JS('', '#[#] = #[#]', jsType, _getterSig, dartExtType, _getterSig);
+ JS('', '#[#] = #[#]', jsType, _setterSig, dartExtType, _setterSig);
+}
+
+/// Apply the previously registered extension to the type of [nativeObject].
+/// This is intended for types that are not available to polyfill at startup.
+applyExtension(name, nativeObject) {
+ var dartExtType = JS('', '#.get(#)', _extensionMap, name);
+ var jsType = JS('', '#.constructor', nativeObject);
+ _applyExtension(jsType, dartExtType);
+}
+
+/// Apply all registered extensions to a window. This is intended for
+/// different frames, where registrations need to be reapplied.
+applyAllExtensions(global) {
+ JS('', '#.forEach((dartExtType, name) => #(#[name], dartExtType))',
+ _extensionMap, _applyExtension, global);
+}
+
+/// Copy symbols from the prototype of the source to destination.
+/// These are the only properties safe to copy onto an existing public
+/// JavaScript class.
+registerExtension(name, dartExtType) {
+ JS('', '#.set(#, #)', _extensionMap, name, dartExtType);
+ var jsType = JS('', '#[#]', global_, name);
+ _applyExtension(jsType, dartExtType);
+}
+
+///
+/// Mark a concrete type as implementing extension methods.
+/// For example: `class MyIter implements Iterable`.
+///
+/// This takes a list of names, which are the extension methods implemented.
+/// It will add a forwarder, so the extension method name redirects to the
+/// normal Dart method name. For example:
+///
+/// defineExtensionMembers(MyType, ['add', 'remove']);
+///
+/// Results in:
+///
+/// MyType.prototype[dartx.add] = MyType.prototype.add;
+/// MyType.prototype[dartx.remove] = MyType.prototype.remove;
+///
+// TODO(jmesserly): essentially this gives two names to the same method.
+// This benefit is roughly equivalent call performance either way, but the
+// cost is we need to call defineExtensionMembers any time a subclass
+// overrides one of these methods.
+defineExtensionMethods(type, Iterable memberNames) {
+ var proto = JS('', '#.prototype', type);
+ for (var name in memberNames) {
+ JS('', '#[dartx.#] = #[#]', proto, name, proto, name);
+ }
+}
+
+/// Like [defineExtensionMethods], but for getter/setter pairs.
+defineExtensionAccessors(type, Iterable memberNames) {
+ var proto = JS('', '#.prototype', type);
+ for (var name in memberNames) {
+ // Find the member. It should always exist (or we have a compiler bug).
+ var member;
+ var p = proto;
+ for (;; p = JS('', '#.__proto__', p)) {
+ member = getOwnPropertyDescriptor(p, name);
+ if (member != null) break;
+ }
+ defineProperty(proto, JS('', 'dartx[#]', name), member);
+ }
+}
+
+definePrimitiveHashCode(proto) {
+ defineProperty(proto, identityHashCode_,
+ getOwnPropertyDescriptor(proto, extensionSymbol('hashCode')));
+}
+
+/// Link the extension to the type it's extending as a base class.
+setBaseClass(derived, base) {
+ JS('', '#.prototype.__proto__ = #.prototype', derived, base);
+ // We use __proto__ to track the superclass hierarchy (see isSubtypeOf).
+ JS('', '#.__proto__ = #', derived, base);
+}
+
+/// Like [setBaseClass], but for generic extension types such as `JSArray<E>`.
+setExtensionBaseClass(dartType, jsType) {
+ // Mark the generic type as an extension type and link the prototype objects.
+ var dartProto = JS('', '#.prototype', dartType);
+ JS('', '#[#] = #', dartProto, _extensionType, dartType);
+ JS('', '#.__proto__ = #.prototype', dartProto, jsType);
+}
+
+/// Adds type test predicates to a class/interface type [ctor], using the
+/// provided [isClass] JS Symbol.
+///
+/// This will operate quickly for non-generic types, native extension types,
+/// as well as matching exact generic type arguments:
+///
+/// class C<T> {}
+/// class D extends C<int> {}
+/// main() { dynamic d = new D(); d as C<int>; }
+///
+addTypeTests(ctor, isClass) {
+ if (isClass == null) isClass = JS('', 'Symbol("_is_" + ctor.name)');
+ // TODO(jmesserly): since we know we're dealing with class/interface types,
+ // we can optimize this rather than go through the generic `dart.is` helpers.
+ JS('', '#.prototype[#] = true', ctor, isClass);
+ JS(
+ '',
+ '''#.is = function is_C(obj) {
+ return obj != null && (obj[#] || #(obj, this));
+ }''',
+ ctor,
+ isClass,
+ instanceOf);
+ JS(
+ '',
+ '''#.as = function as_C(obj) {
+ if (obj == null || obj[#]) return obj;
+ return #(obj, this, false);
+ }''',
+ ctor,
+ isClass,
+ cast);
+ JS(
+ '',
+ '''#._check = function check_C(obj) {
+ if (obj == null || obj[#]) return obj;
+ return #(obj, this, true);
+ }''',
+ ctor,
+ isClass,
+ cast);
+}
+
+// TODO(jmesserly): should we do this for all interfaces?
+
+/// The well known symbol for testing `is Future`
+final isFuture = JS('', 'Symbol("_is_Future")');
+
+/// The well known symbol for testing `is Iterable`
+final isIterable = JS('', 'Symbol("_is_Iterable")');
+
+/// The well known symbol for testing `is List`
+final isList = JS('', 'Symbol("_is_List")');
+
+/// The well known symbol for testing `is Map`
+final isMap = JS('', 'Symbol("_is_Map")');
+
+/// The well known symbol for testing `is Stream`
+final isStream = JS('', 'Symbol("_is_Stream")');
+
+/// The well known symbol for testing `is StreamSubscription`
+final isStreamSubscription = JS('', 'Symbol("_is_StreamSubscription")');
+
+/// The default `operator ==` that calls [identical].
+var identityEquals;
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
new file mode 100644
index 0000000..f875336
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
@@ -0,0 +1,271 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._runtime;
+
+// We need to set these properties while the sdk is only partially initialized
+// so we cannot use regular Dart fields.
+// The default values for these properties are set when the global_ final field
+// in runtime.dart is initialized.
+
+argumentError(value) {
+ throw ArgumentError.value(value);
+}
+
+throwUnimplementedError(String message) {
+ throw UnimplementedError(message);
+}
+
+// TODO(nshahan) Cleanup embeded strings and extract file location at runtime
+// from the stacktrace.
+assertFailed(String message,
+ [String fileUri, int line, int column, String conditionSource]) {
+ throw AssertionErrorImpl(message, fileUri, line, column, conditionSource);
+}
+
+throwCyclicInitializationError([Object field]) {
+ throw CyclicInitializationError(field);
+}
+
+throwNullValueError() {
+ // TODO(vsm): Per spec, we should throw an NSM here. Technically, we ought
+ // to thread through method info, but that uglifies the code and can't
+ // actually be queried ... it only affects how the error is printed.
+ throw NoSuchMethodError(
+ null, Symbol('<Unexpected Null Value>'), null, null, null);
+}
+
+castError(obj, expectedType, [@notNull bool isImplicit = false]) {
+ var actualType = getReifiedType(obj);
+ var message = _castErrorMessage(actualType, expectedType);
+ var error = isImplicit ? TypeErrorImpl(message) : CastErrorImpl(message);
+ throw error;
+}
+
+String _castErrorMessage(from, to) {
+ // If both types are generic classes, see if we can infer generic type
+ // arguments for `from` that would allow the subtype relation to work.
+ var fromClass = getGenericClass(from);
+ if (fromClass != null) {
+ var fromTypeFormals = getGenericTypeFormals(fromClass);
+ var fromType = instantiateClass(fromClass, fromTypeFormals);
+ var inferrer = _TypeInferrer(fromTypeFormals);
+ if (inferrer.trySubtypeMatch(fromType, to)) {
+ var inferredTypes = inferrer.getInferredTypes();
+ if (inferredTypes != null) {
+ var inferred = instantiateClass(fromClass, inferredTypes);
+ return "Type '${typeName(from)}' should be '${typeName(inferred)}' "
+ "to implement expected type '${typeName(to)}'.";
+ }
+ }
+ }
+ return "Expected a value of type '${typeName(to)}', "
+ "but got one of type '${typeName(from)}'";
+}
+
+/// The symbol that references the thrown Dart Object (typically but not
+/// necessarily an [Error] or [Exception]), used by the [exception] function.
+final Object _thrownValue = JS('', 'Symbol("_thrownValue")');
+
+/// For a Dart [Error], this provides access to the JS Error object that
+/// contains the stack trace if the error was thrown.
+final Object _jsError = JS('', 'Symbol("_jsError")');
+
+/// Gets the thrown Dart Object from an [error] caught by a JS catch.
+///
+/// If the throw originated in Dart, the result will typically be an [Error]
+/// or [Exception], but it could be any Dart object.
+///
+/// If the throw originated in JavaScript, then there is not a corresponding
+/// Dart value, so we just return the error object.
+Object getThrown(Object error) {
+ if (error != null) {
+ // Get the Dart thrown value, if any.
+ var value = JS('', '#[#]', error, _thrownValue);
+ if (value != null) return value;
+ }
+ // Otherwise return the original object.
+ return error;
+}
+
+final _stackTrace = JS('', 'Symbol("_stackTrace")');
+
+/// Returns the stack trace from an [error] caught by a JS catch.
+///
+/// If the throw originated in Dart, we should always have JS Error
+/// (see [throw_]) so we can create a Dart [StackTrace] from that (or return a
+/// previously created instance).
+///
+/// If the throw originated in JavaScript and was an `Error`, then we can get
+/// the corresponding stack trace the same way we do for Dart throws. If the
+/// throw object was not an Error, then we don't have a JS trace, so we create
+/// one here.
+StackTrace stackTrace(Object error) {
+ if (JS<bool>('!', '!(# instanceof Error)', error)) {
+ // We caught something that isn't a JS Error.
+ //
+ // We should only hit this path when a non-Error was thrown from JS. In
+ // case, there is no stack trace available, so create one here.
+ return _StackTrace.missing(error);
+ }
+
+ // If we've already created the Dart stack trace object, return it.
+ StackTrace trace = JS('', '#[#]', error, _stackTrace);
+ if (trace != null) return trace;
+
+ // Otherwise create the Dart stack trace (by parsing the JS stack), and
+ // cache it so we don't repeat the parsing/allocation.
+ return JS('', '#[#] = #', error, _stackTrace, _StackTrace(error));
+}
+
+StackTrace stackTraceForError(Error error) {
+ return stackTrace(JS('', '#[#]', error, _jsError));
+}
+
+/// Implements `rethrow` of [error], allowing rethrow in an expression context.
+///
+/// Note: [error] must be the raw JS error caught in the JS catch, not the
+/// unwrapped value returned by [getThrown].
+@JSExportName('rethrow')
+void rethrow_(Object error) {
+ JS('', 'throw #', error);
+}
+
+/// Subclass of JS `Error` that wraps a thrown Dart object, and evaluates the
+/// message lazily by calling `toString()` on the wrapped Dart object.
+///
+/// Also creates a pointer from the thrown Dart object to the JS Error
+/// (via [_jsError]). This is used to implement [Error.stackTrace], but also
+/// provides a way to recover the stack trace if we lose track of it.
+/// [Error] requires preserving the original stack trace if an error is
+/// rethrown, so we only update the pointer if it wasn't already set.
+///
+/// TODO(jmesserly): Dart Errors should simply be JS Errors.
+final Object DartError = JS(
+ '!',
+ '''class DartError extends Error {
+ constructor(error) {
+ super();
+ if (error == null) error = #;
+ this[#] = error;
+ if (error != null && typeof error == "object" && error[#] == null) {
+ error[#] = this;
+ }
+ }
+ get message() {
+ return #(this[#]);
+ }
+ }''',
+ NullThrownError(),
+ _thrownValue,
+ _jsError,
+ _jsError,
+ _toString,
+ _thrownValue);
+
+/// Subclass of [DartError] for cases where we're rethrowing with a different,
+/// original Dart StackTrace object.
+///
+/// This includes the original stack trace in the JS Error message so it doesn't
+/// get lost if the exception reaches JS.
+final Object RethrownDartError = JS(
+ '!',
+ '''class RethrownDartError extends # {
+ constructor(error, stackTrace) {
+ super(error);
+ this[#] = stackTrace;
+ }
+ get message() {
+ return super.message + "\\n " + #(this[#]) + "\\n";
+ }
+ }''',
+ DartError,
+ _stackTrace,
+ _toString,
+ _stackTrace);
+
+/// Implements `throw` of [exception], allowing for throw in an expression
+/// context, and capturing the current stack trace.
+@JSExportName('throw')
+void throw_(Object exception) {
+ /// Wrap the object so we capture a new stack trace, and so it will print
+ /// nicely from JS, as if it were a normal JS error.
+ JS('', 'throw new #(#)', DartError, exception);
+}
+
+/// Returns a JS error for throwing the Dart [exception] Object and using the
+/// provided stack [trace].
+///
+/// This is used by dart:async to rethrow unhandled errors in [Zone]s, and by
+/// `async`/`async*` to rethrow errors from Futures/Streams into the generator
+/// (so a try/catch in there can catch it).
+///
+/// If the exception and trace originated from the same Dart throw, then we can
+/// simply return the original JS Error. Otherwise, we have to create a new JS
+/// Error. The new error will have the correct Dart trace, but it will not have
+/// the correct JS stack trace (visible if JavaScript ends up handling it). To
+/// fix that, we use [RethrownDartError] to preserve the Dart trace and make
+/// sure it gets displayed in the JS error message.
+///
+/// If the stack trace is null, this will preserve the original stack trace
+/// on the exception, if available, otherwise it will capture the current stack
+/// trace.
+Object createErrorWithStack(Object exception, StackTrace trace) {
+ if (trace == null) {
+ var error = JS('', '#[#]', exception, _jsError);
+ return error != null ? error : JS('', 'new #(#)', DartError, exception);
+ }
+ if (trace is _StackTrace) {
+ /// Optimization: if this stack trace and exception already have a matching
+ /// Error, we can just rethrow it.
+ var originalError = trace._jsError;
+ if (identical(exception, getThrown(originalError))) {
+ return originalError;
+ }
+ }
+ return JS('', 'new #(#, #)', RethrownDartError, exception, trace);
+}
+
+// This is a utility function: it is only intended to be called from dev
+// tools.
+void stackPrint(Object error) {
+ JS('', 'console.log(#.stack ? #.stack : "No stack trace for: " + #)', error,
+ error, error);
+}
+
+class _StackTrace implements StackTrace {
+ final Object _jsError;
+ final Object _jsObjectMissingTrace;
+ String _trace;
+
+ _StackTrace(this._jsError) : _jsObjectMissingTrace = null;
+
+ _StackTrace.missing(Object caughtObj)
+ : _jsObjectMissingTrace = caughtObj != null ? caughtObj : 'null',
+ _jsError = JS('', 'Error()');
+
+ String toString() {
+ if (_trace != null) return _trace;
+
+ var e = _jsError;
+ String trace = '';
+ if (e != null && JS<bool>('!', 'typeof # === "object"', e)) {
+ trace = e is NativeError ? e.dartStack() : JS<String>('', '#.stack', e);
+ if (trace != null && stackTraceMapper != null) {
+ trace = stackTraceMapper(trace);
+ }
+ }
+ if (trace.isEmpty || _jsObjectMissingTrace != null) {
+ String jsToString;
+ try {
+ jsToString = JS('', '"" + #', _jsObjectMissingTrace);
+ } catch (_) {
+ jsToString = '<error converting JS object to string>';
+ }
+ trace = 'Non-error `$jsToString` thrown by JS does not have stack trace.'
+ '\nCaught in Dart at:\n\n$trace';
+ }
+ return _trace = trace;
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
new file mode 100644
index 0000000..e388cd6
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
@@ -0,0 +1,725 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This library defines runtime operations on objects used by the code
+/// generator.
+part of dart._runtime;
+
+// TODO(jmesserly): remove this in favor of _Invocation.
+class InvocationImpl extends Invocation {
+ final Symbol memberName;
+ final List positionalArguments;
+ final Map<Symbol, dynamic> namedArguments;
+ final List<Type> typeArguments;
+ final bool isMethod;
+ final bool isGetter;
+ final bool isSetter;
+ final String failureMessage;
+
+ InvocationImpl(memberName, List<Object> positionalArguments,
+ {namedArguments,
+ List typeArguments,
+ this.isMethod = false,
+ this.isGetter = false,
+ this.isSetter = false,
+ this.failureMessage = 'method not found'})
+ : memberName =
+ isSetter ? _setterSymbol(memberName) : _dartSymbol(memberName),
+ positionalArguments = List.unmodifiable(positionalArguments),
+ namedArguments = _namedArgsToSymbols(namedArguments),
+ typeArguments = typeArguments == null
+ ? const []
+ : List.unmodifiable(typeArguments.map(wrapType));
+
+ static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) {
+ if (namedArgs == null) return const {};
+ return Map.unmodifiable(Map.fromIterable(getOwnPropertyNames(namedArgs),
+ key: _dartSymbol, value: (k) => JS('', '#[#]', namedArgs, k)));
+ }
+}
+
+/// Given an object and a method name, tear off the method.
+/// Sets the runtime type of the torn off method appropriately,
+/// and also binds the object.
+///
+/// If the optional `f` argument is passed in, it will be used as the method.
+/// This supports cases like `super.foo` where we need to tear off the method
+/// from the superclass, not from the `obj` directly.
+// TODO(leafp): Consider caching the tearoff on the object?
+bind(obj, name, method) {
+ if (obj == null) obj = jsNull;
+ if (method == null) method = JS('', '#[#]', obj, name);
+ var f = JS('', '#.bind(#)', method, obj);
+ // TODO(jmesserly): canonicalize tearoffs.
+ JS('', '#._boundObject = #', f, obj);
+ JS('', '#._boundMethod = #', f, method);
+ JS('', '#[#] = #', f, _runtimeType, getMethodType(getType(obj), name));
+ return f;
+}
+
+/// Binds the `call` method of an interface type, handling null.
+///
+/// Essentially this works like `obj?.call`. It also handles the needs of
+/// [dsend]/[dcall], returning `null` if no method was found with the given
+/// canonical member [name].
+///
+/// [name] is typically `"call"` but it could be the [extensionSymbol] for
+/// `call`, if we define it on a native type, and [obj] is known statially to be
+/// a native type/interface with `call`.
+bindCall(obj, name) {
+ if (obj == null) return null;
+ var ftype = getMethodType(getType(obj), name);
+ if (ftype == null) return null;
+ var method = JS('', '#[#]', obj, name);
+ var f = JS('', '#.bind(#)', method, obj);
+ // TODO(jmesserly): canonicalize tearoffs.
+ JS('', '#._boundObject = #', f, obj);
+ JS('', '#._boundMethod = #', f, method);
+ JS('', '#[#] = #', f, _runtimeType, ftype);
+ return f;
+}
+
+/// Instantiate a generic method.
+///
+/// We need to apply the type arguments both to the function, as well as its
+/// associated function type.
+gbind(f, @rest List typeArgs) {
+ GenericFunctionType type = JS('!', '#[#]', f, _runtimeType);
+ type.checkBounds(typeArgs);
+ // Create a JS wrapper function that will also pass the type arguments, and
+ // tag it with the instantiated function type.
+ var result =
+ JS('', '(...args) => #.apply(null, #.concat(args))', f, typeArgs);
+ return fn(result, type.instantiate(typeArgs));
+}
+
+dloadRepl(obj, field) => dload(obj, replNameLookup(obj, field), false);
+
+// Warning: dload, dput, and dsend assume they are never called on methods
+// implemented by the Object base class as those methods can always be
+// statically resolved.
+dload(obj, field, [@undefined mirrors]) {
+ if (JS('!', 'typeof # == "function" && # == "call"', obj, field)) {
+ return obj;
+ }
+ var f = _canonicalMember(obj, field);
+
+ trackCall(obj);
+ if (f != null) {
+ var type = getType(obj);
+
+ if (hasField(type, f) || hasGetter(type, f)) return JS('', '#[#]', obj, f);
+ if (hasMethod(type, f)) return bind(obj, f, null);
+
+ // Always allow for JS interop objects.
+ if (!JS<bool>('!', '#', mirrors) && isJsInterop(obj)) {
+ return JS('', '#[#]', obj, f);
+ }
+ }
+ return noSuchMethod(obj, InvocationImpl(field, JS('', '[]'), isGetter: true));
+}
+
+// Version of dload that matches legacy mirrors behavior for JS types.
+dloadMirror(obj, field) => dload(obj, field, true);
+
+_stripGenericArguments(type) {
+ var genericClass = getGenericClass(type);
+ if (genericClass != null) return JS('', '#()', genericClass);
+ return type;
+}
+
+// Version of dput that matches legacy Dart 1 type check rules and mirrors
+// behavior for JS types.
+// TODO(jacobr): remove the type checking rules workaround when mirrors based
+// PageLoader code can generate the correct reified generic types.
+dputMirror(obj, field, value) => dput(obj, field, value, true);
+
+dputRepl(obj, field, value) =>
+ dput(obj, replNameLookup(obj, field), value, false);
+
+dput(obj, field, value, [@undefined mirrors]) {
+ var f = _canonicalMember(obj, field);
+ trackCall(obj);
+ if (f != null) {
+ var setterType = getSetterType(getType(obj), f);
+ if (setterType != null) {
+ if (JS('!', '#', mirrors))
+ setterType = _stripGenericArguments(setterType);
+ return JS('', '#[#] = #._check(#)', obj, f, setterType, value);
+ }
+ // Always allow for JS interop objects.
+ if (!JS<bool>('!', '#', mirrors) && isJsInterop(obj)) {
+ return JS('', '#[#] = #', obj, f, value);
+ }
+ }
+ noSuchMethod(
+ obj, InvocationImpl(field, JS('', '[#]', value), isSetter: true));
+ return value;
+}
+
+/// Returns an error message if function of a given [type] can't be applied to
+/// [actuals] and [namedActuals].
+///
+/// Returns `null` if all checks pass.
+String _argumentErrors(FunctionType type, List actuals, namedActuals) {
+ // Check for too few required arguments.
+ int actualsCount = JS('!', '#.length', actuals);
+ var required = type.args;
+ int requiredCount = JS('!', '#.length', required);
+ if (actualsCount < requiredCount) {
+ return 'Dynamic call with too few arguments. '
+ 'Expected: $requiredCount Actual: $actualsCount';
+ }
+
+ // Check for too many postional arguments.
+ var extras = actualsCount - requiredCount;
+ var optionals = type.optionals;
+ if (extras > JS<int>('!', '#.length', optionals)) {
+ return 'Dynamic call with too many arguments. '
+ 'Expected: $requiredCount Actual: $actualsCount';
+ }
+
+ // Check if we have invalid named arguments.
+ Iterable names;
+ var named = type.named;
+ if (namedActuals != null) {
+ names = getOwnPropertyNames(namedActuals);
+ for (var name in names) {
+ if (!JS('!', '#.hasOwnProperty(#)', named, name)) {
+ return "Dynamic call with unexpected named argument '$name'.";
+ }
+ }
+ }
+ // Now that we know the signature matches, we can perform type checks.
+ for (var i = 0; i < requiredCount; ++i) {
+ JS('', '#[#]._check(#[#])', required, i, actuals, i);
+ }
+ for (var i = 0; i < extras; ++i) {
+ JS('', '#[#]._check(#[#])', optionals, i, actuals, i + requiredCount);
+ }
+ if (names != null) {
+ for (var name in names) {
+ JS('', '#[#]._check(#[#])', named, name, namedActuals, name);
+ }
+ }
+ return null;
+}
+
+_toSymbolName(symbol) => JS('', '''(() => {
+ let str = $symbol.toString();
+ // Strip leading 'Symbol(' and trailing ')'
+ return str.substring(7, str.length-1);
+ })()''');
+
+_toDisplayName(name) => JS('', '''(() => {
+ // Names starting with _ are escaped names used to disambiguate Dart and
+ // JS names.
+ if ($name[0] === '_') {
+ // Inverse of
+ switch($name) {
+ case '_get':
+ return '[]';
+ case '_set':
+ return '[]=';
+ case '_negate':
+ return 'unary-';
+ case '_constructor':
+ case '_prototype':
+ return $name.substring(1);
+ }
+ }
+ return $name;
+ })()''');
+
+Symbol _dartSymbol(name) {
+ return (JS<bool>('!', 'typeof # === "symbol"', name))
+ ? JS('Symbol', '#(new #.new(#, #))', const_, PrivateSymbol,
+ _toSymbolName(name), name)
+ : JS('Symbol', '#(new #.new(#))', const_, internal.Symbol,
+ _toDisplayName(name));
+}
+
+Symbol _setterSymbol(name) {
+ return (JS<bool>('!', 'typeof # === "symbol"', name))
+ ? JS('Symbol', '#(new #.new(# + "=", #))', const_, PrivateSymbol,
+ _toSymbolName(name), name)
+ : JS('Symbol', '#(new #.new(# + "="))', const_, internal.Symbol,
+ _toDisplayName(name));
+}
+
+_checkAndCall(f, ftype, obj, typeArgs, args, named, displayName) =>
+ JS('', '''(() => {
+ $trackCall($obj);
+
+ let originalTarget = obj === void 0 ? f : obj;
+
+ function callNSM(errorMessage) {
+ return $noSuchMethod(originalTarget, new $InvocationImpl.new(
+ $displayName, $args, {
+ namedArguments: $named,
+ typeArguments: $typeArgs,
+ isMethod: true,
+ failureMessage: errorMessage
+ }));
+ }
+ if ($f == null) return callNSM('Dynamic call of null.');
+ if (!($f instanceof Function)) {
+ // We're not a function (and hence not a method either)
+ // Grab the `call` method if it's not a function.
+ if ($f != null) {
+ // Getting the member succeeded, so update the originalTarget.
+ // (we're now trying `call()` on `f`, so we want to call its nSM rather
+ // than the original target's nSM).
+ originalTarget = f;
+ $f = ${bindCall(f, _canonicalMember(f, 'call'))};
+ $ftype = null;
+ $displayName = "call";
+ }
+ if ($f == null) return callNSM(
+ "Dynamic call of object has no instance method 'call'.");
+ }
+ // If f is a function, but not a method (no method type)
+ // then it should have been a function valued field, so
+ // get the type from the function.
+ if ($ftype == null) $ftype = $f[$_runtimeType];
+
+ if ($ftype == null) {
+ // TODO(leafp): Allow JS objects to go through?
+ if ($typeArgs != null) {
+ // TODO(jmesserly): is there a sensible way to handle these?
+ $throwTypeError('call to JS object `' + $obj +
+ '` with type arguments <' + $typeArgs + '> is not supported.');
+ }
+
+ if ($named != null) $args.push($named);
+ return $f.apply($obj, $args);
+ }
+
+ // TODO(vsm): Remove when we no longer need mirrors metadata.
+ // An array is used to encode annotations attached to the type.
+ if ($ftype instanceof Array) $ftype = $ftype[0];
+
+ // Apply type arguments
+ if ($ftype instanceof $GenericFunctionType) {
+ let formalCount = $ftype.formalCount;
+
+ if ($typeArgs == null) {
+ $typeArgs = $ftype.instantiateDefaultBounds();
+ } else if ($typeArgs.length != formalCount) {
+ return callNSM('Dynamic call with incorrect number of type arguments. ' +
+ 'Expected: ' + formalCount + ' Actual: ' + $typeArgs.length);
+ } else {
+ $ftype.checkBounds($typeArgs);
+ }
+ $ftype = $ftype.instantiate($typeArgs);
+ } else if ($typeArgs != null) {
+ return callNSM('Dynamic call with unexpected type arguments. ' +
+ 'Expected: 0 Actual: ' + $typeArgs.length);
+ }
+ let errorMessage = $_argumentErrors($ftype, $args, $named);
+ if (errorMessage == null) {
+ if ($typeArgs != null) $args = $typeArgs.concat($args);
+ if ($named != null) $args.push($named);
+ return $f.apply($obj, $args);
+ }
+ return callNSM(errorMessage);
+})()''');
+
+dcall(f, args, [@undefined named]) => _checkAndCall(
+ f, null, JS('', 'void 0'), null, args, named, JS('', 'f.name'));
+
+dgcall(f, typeArgs, args, [@undefined named]) =>
+ _checkAndCall(f, null, JS('', 'void 0'), typeArgs, args, named, 'call');
+
+/// Helper for REPL dynamic invocation variants that make a best effort to
+/// enable accessing private members across library boundaries.
+replNameLookup(object, field) => JS('', '''(() => {
+ let rawField = $field;
+ if (typeof(field) == 'symbol') {
+ // test if the specified field exists in which case it is safe to use it.
+ if ($field in $object) return $field;
+
+ // Symbol is from a different library. Make a best effort to
+ $field = $field.toString();
+ $field = $field.substring('Symbol('.length, field.length - 1);
+
+ } else if ($field.charAt(0) != '_') {
+ // Not a private member so default call path is safe.
+ return $field;
+ }
+
+ // If the exact field name is present, invoke callback with it.
+ if ($field in $object) return $field;
+
+ // TODO(jacobr): warn if there are multiple private members with the same
+ // name which could happen if super classes in different libraries have
+ // the same private member name.
+ let proto = $object;
+ while (proto !== null) {
+ // Private field (indicated with "_").
+ let symbols = Object.getOwnPropertySymbols(proto);
+ let target = 'Symbol(' + $field + ')';
+
+ for (let s = 0; s < symbols.length; s++) {
+ let sym = symbols[s];
+ if (target == sym.toString()) return sym;
+ }
+ proto = proto.__proto__;
+ }
+ // We didn't find a plausible alternate private symbol so just fall back
+ // to the regular field.
+ return rawField;
+})()''');
+
+/// Shared code for dsend, dindex, and dsetindex.
+callMethod(obj, name, typeArgs, args, named, displayName) {
+ if (JS('!', 'typeof # == "function" && # == "call"', obj, name)) {
+ return dgcall(obj, typeArgs, args, named);
+ }
+ var symbol = _canonicalMember(obj, name);
+ if (symbol == null) {
+ return noSuchMethod(obj, InvocationImpl(displayName, args, isMethod: true));
+ }
+ var f = obj != null ? JS('', '#[#]', obj, symbol) : null;
+ var type = getType(obj);
+ var ftype = getMethodType(type, symbol);
+ // No such method if dart object and ftype is missing.
+ return _checkAndCall(f, ftype, obj, typeArgs, args, named, displayName);
+}
+
+dsend(obj, method, args, [@undefined named]) =>
+ callMethod(obj, method, null, args, named, method);
+
+dgsend(obj, typeArgs, method, args, [@undefined named]) =>
+ callMethod(obj, method, typeArgs, args, named, method);
+
+dsendRepl(obj, method, args, [@undefined named]) =>
+ callMethod(obj, replNameLookup(obj, method), null, args, named, method);
+
+dgsendRepl(obj, typeArgs, method, args, [@undefined named]) =>
+ callMethod(obj, replNameLookup(obj, method), typeArgs, args, named, method);
+
+dindex(obj, index) => callMethod(obj, '_get', null, [index], null, '[]');
+
+dsetindex(obj, index, value) =>
+ callMethod(obj, '_set', null, [index, value], null, '[]=');
+
+@notNull
+@JSExportName('is')
+bool instanceOf(obj, type) {
+ if (obj == null) {
+ return identical(type, unwrapType(Null)) || _isTop(type);
+ }
+ return isSubtypeOf(getReifiedType(obj), type);
+}
+
+@JSExportName('as')
+cast(obj, type, @notNull bool isImplicit) {
+ if (obj == null) return obj;
+ var actual = getReifiedType(obj);
+ if (isSubtypeOf(actual, type)) {
+ return obj;
+ }
+ return castError(obj, type, isImplicit);
+}
+
+bool test(bool obj) {
+ if (obj == null) _throwBooleanConversionError();
+ return obj;
+}
+
+bool dtest(obj) {
+ if (obj is! bool) booleanConversionFailed(obj);
+ return obj;
+}
+
+void _throwBooleanConversionError() => throw BooleanConversionAssertionError();
+
+void booleanConversionFailed(obj) {
+ var actual = typeName(getReifiedType(test(obj)));
+ throw TypeErrorImpl("type '$actual' is not a 'bool' in boolean expression");
+}
+
+asInt(obj) {
+ if (obj == null) return null;
+
+ if (JS('!', 'Math.floor(#) != #', obj, obj)) {
+ castError(obj, JS('', '#', int), false);
+ }
+ return obj;
+}
+
+/// Checks that `x` is not null or undefined.
+//
+// TODO(jmesserly): inline this, either by generating it as a function into
+// the module, or via some other pattern such as:
+//
+// <expr> || nullErr()
+// (t0 = <expr>) != null ? t0 : nullErr()
+@JSExportName('notNull')
+_notNull(x) {
+ if (x == null) throwNullValueError();
+ return x;
+}
+
+/// The global constant map table.
+final constantMaps = JS('', 'new Map()');
+
+// TODO(leafp): This table gets quite large in apps.
+// Keeping the paths is probably expensive. It would probably
+// be more space efficient to just use a direct hash table with
+// an appropriately defined structural equality function.
+Object _lookupNonTerminal(Object map, Object key) {
+ var result = JS('', '#.get(#)', map, key);
+ if (result != null) return result;
+ JS('', '#.set(#, # = new Map())', map, key, result);
+ return result;
+}
+
+Map<K, V> constMap<K, V>(JSArray elements) {
+ var count = elements.length;
+ var map = _lookupNonTerminal(constantMaps, count);
+ for (var i = 0; i < count; i++) {
+ map = _lookupNonTerminal(map, JS('', '#[#]', elements, i));
+ }
+ map = _lookupNonTerminal(map, K);
+ var result = JS('', '#.get(#)', map, V);
+ if (result != null) return result;
+ result = ImmutableMap<K, V>.from(elements);
+ JS('', '#.set(#, #)', map, V, result);
+ return result;
+}
+
+final constantSets = JS('', 'new Map()');
+var _immutableSetConstructor;
+
+// We cannot invoke private class constructors directly in Dart.
+Set<E> _createImmutableSet<E>(JSArray<E> elements) {
+ _immutableSetConstructor ??=
+ JS('', '#.#', getLibrary('dart:collection'), '_ImmutableSet\$');
+ return JS('', 'new (#(#)).from(#)', _immutableSetConstructor, E, elements);
+}
+
+Set<E> constSet<E>(JSArray<E> elements) {
+ var count = elements.length;
+ var map = _lookupNonTerminal(constantSets, count);
+ for (var i = 0; i < count; i++) {
+ map = _lookupNonTerminal(map, JS('', '#[#]', elements, i));
+ }
+ var result = JS('', '#.get(#)', map, E);
+ if (result != null) return result;
+ result = _createImmutableSet<E>(elements);
+ JS('', '#.set(#, #)', map, E, result);
+ return result;
+}
+
+bool dassert(value) {
+ if (JS('!', '# != null && #[#] instanceof #', value, value, _runtimeType,
+ AbstractFunctionType)) {
+ value = dcall(value, []);
+ }
+ return dtest(value);
+}
+
+final _value = JS('', 'Symbol("_value")');
+
+///
+/// Looks up a sequence of [keys] in [map], recursively, and
+/// returns the result. If the value is not found, [valueFn] will be called to
+/// add it. For example:
+///
+/// let map = new Map();
+/// putIfAbsent(map, [1, 2, 'hi ', 'there '], () => 'world');
+///
+/// ... will create a Map with a structure like:
+///
+/// { 1: { 2: { 'hi ': { 'there ': 'world' } } } }
+///
+multiKeyPutIfAbsent(map, keys, valueFn) => JS('', '''(() => {
+ for (let k of $keys) {
+ let value = $map.get(k);
+ if (!value) {
+ // TODO(jmesserly): most of these maps are very small (e.g. 1 item),
+ // so it may be worth optimizing for that.
+ $map.set(k, value = new Map());
+ }
+ $map = value;
+ }
+ if ($map.has($_value)) return $map.get($_value);
+ let value = $valueFn();
+ $map.set($_value, value);
+ return value;
+})()''');
+
+/// The global constant table.
+/// This maps the number of names in the object (n)
+/// to a path of length 2*n of maps indexed by the name and
+/// and value of the field. The final map is
+/// indexed by runtime type, and contains the canonical
+/// version of the object.
+final constants = JS('', 'new Map()');
+
+///
+/// Canonicalize a constant object.
+///
+/// Preconditions:
+/// - `obj` is an objects or array, not a primitive.
+/// - nested values of the object are themselves already canonicalized.
+///
+@JSExportName('const')
+const_(obj) => JS('', '''(() => {
+ let names = $getOwnNamesAndSymbols($obj);
+ let count = names.length;
+ // Index by count. All of the paths through this map
+ // will have 2*count length.
+ let map = $_lookupNonTerminal($constants, count);
+ // TODO(jmesserly): there's no guarantee in JS that names/symbols are
+ // returned in the same order.
+ //
+ // We could probably get the same order if we're judicious about
+ // initializing fields in a consistent order across all const constructors.
+ // Alternatively we need a way to sort them to make consistent.
+ //
+ // Right now we use the (name,value) pairs in sequence, which prevents
+ // an object with incorrect field values being returned, but won't
+ // canonicalize correctly if key order is different.
+ //
+ // See issue https://github.com/dart-lang/sdk/issues/30876
+ for (let i = 0; i < count; i++) {
+ let name = names[i];
+ map = $_lookupNonTerminal(map, name);
+ map = $_lookupNonTerminal(map, $obj[name]);
+ }
+ // TODO(leafp): It may be the case that the reified type
+ // is always one of the keys already used above?
+ let type = $getReifiedType($obj);
+ let value = map.get(type);
+ if (value) return value;
+ map.set(type, $obj);
+ return $obj;
+})()''');
+
+/// The global constant list table.
+/// This maps the number of elements in the list (n)
+/// to a path of length n of maps indexed by the value
+/// of the field. The final map is indexed by the element
+/// type and contains the canonical version of the list.
+final constantLists = JS('', 'new Map()');
+
+/// Canonicalize a constant list
+constList(elements, elementType) => JS('', '''(() => {
+ let count = $elements.length;
+ let map = $_lookupNonTerminal($constantLists, count);
+ for (let i = 0; i < count; i++) {
+ map = $_lookupNonTerminal(map, elements[i]);
+ }
+ let value = map.get($elementType);
+ if (value) return value;
+
+ ${getGenericClass(JSArray)}($elementType).unmodifiable($elements);
+ map.set($elementType, elements);
+ return elements;
+})()''');
+
+constFn(x) => JS('', '() => x');
+
+/// Gets the extension symbol given a member [name].
+///
+/// This is inlined by the compiler when used with a literal string.
+extensionSymbol(String name) => JS('', 'dartx[#]', name);
+
+// The following are helpers for Object methods when the receiver
+// may be null. These should only be generated by the compiler.
+bool equals(x, y) {
+ // We handle `y == null` inside our generated operator methods, to keep this
+ // function minimal.
+ // This pattern resulted from performance testing; it found that dispatching
+ // was the fastest solution, even for primitive types.
+ return JS('!', '# == null ? # == null : #[#](#)', x, y, x,
+ extensionSymbol('_equals'), y);
+}
+
+int hashCode(obj) {
+ return obj == null ? 0 : JS('!', '#[#]', obj, extensionSymbol('hashCode'));
+}
+
+@JSExportName('toString')
+String _toString(obj) {
+ if (obj == null) return "null";
+ if (obj is String) return obj;
+ return JS('!', '#[#]()', obj, extensionSymbol('toString'));
+}
+
+/// Converts to a non-null [String], equivalent to
+/// `dart.notNull(dart.toString(obj))`.
+///
+/// This is commonly used in string interpolation.
+@notNull
+String str(obj) {
+ if (obj == null) return "null";
+ if (obj is String) return obj;
+ return _notNull(JS('!', '#[#]()', obj, extensionSymbol('toString')));
+}
+
+// TODO(jmesserly): is the argument type verified statically?
+noSuchMethod(obj, Invocation invocation) {
+ if (obj == null) defaultNoSuchMethod(obj, invocation);
+ return JS('', '#[#](#)', obj, extensionSymbol('noSuchMethod'), invocation);
+}
+
+/// The default implementation of `noSuchMethod` to match `Object.noSuchMethod`.
+defaultNoSuchMethod(obj, Invocation i) {
+ throw NoSuchMethodError.withInvocation(obj, i);
+}
+
+runtimeType(obj) {
+ return obj == null ? Null : JS('', '#[dartx.runtimeType]', obj);
+}
+
+final identityHashCode_ = JS('', 'Symbol("_identityHashCode")');
+
+/// Adapts a Dart `get iterator` into a JS `[Symbol.iterator]`.
+// TODO(jmesserly): instead of an adaptor, we could compile Dart iterators
+// natively implementing the JS iterator protocol. This would allow us to
+// optimize them a bit.
+final JsIterator = JS('', '''
+ class JsIterator {
+ constructor(dartIterator) {
+ this.dartIterator = dartIterator;
+ }
+ next() {
+ let i = this.dartIterator;
+ let done = !i.moveNext();
+ return { done: done, value: done ? void 0 : i.current };
+ }
+ }
+''');
+
+_canonicalMember(obj, name) {
+ // Private names are symbols and are already canonical.
+ if (JS('!', 'typeof # === "symbol"', name)) return name;
+
+ if (obj != null && JS<bool>('!', '#[#] != null', obj, _extensionType)) {
+ return JS('', 'dartx.#', name);
+ }
+
+ // Check for certain names that we can't use in JS
+ if (JS('!', '# == "constructor" || # == "prototype"', name, name)) {
+ JS('', '# = "+" + #', name, name);
+ }
+ return name;
+}
+
+/// Emulates the implicit "loadLibrary" function provided by a deferred library.
+///
+/// Libraries are not actually deferred in DDC, so this just returns a future
+/// that completes immediately.
+Future loadLibrary() => Future.value();
+
+/// Defines lazy statics.
+void defineLazy(to, from) {
+ for (var name in getOwnNamesAndSymbols(from)) {
+ defineLazyField(to, name, getOwnPropertyDescriptor(from, name));
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart
new file mode 100644
index 0000000..11ea1ae
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart
@@ -0,0 +1,222 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This library defines the association between runtime objects and
+/// runtime types.
+part of dart._runtime;
+
+/// Runtime type information. This module defines the mapping from
+/// runtime objects to their runtime type information. See the types
+/// module for the definition of how type information is represented.
+///
+/// There are two kinds of objects that represent "types" at runtime. A
+/// "runtime type" contains all of the data needed to implement the runtime
+/// type checking inserted by the compiler. These objects fall into four
+/// categories:
+///
+/// - Things represented by javascript primitives, such as
+/// null, numbers, booleans, strings, and symbols. For these
+/// we map directly from the javascript type (given by typeof)
+/// to the appropriate class type from core, which serves as their
+/// rtti.
+///
+/// - Functions, which are represented by javascript functions.
+/// Representations of Dart functions always have a
+/// _runtimeType property attached to them with the appropriate
+/// rtti.
+///
+/// - Objects (instances) which are represented by instances of
+/// javascript (ES6) classes. Their types are given by their
+/// classes, and the rtti is accessed by projecting out their
+/// constructor field.
+///
+/// - Types objects, which are represented as described in the types
+/// module. Types always have a _runtimeType property attached to
+/// them with the appropriate rtti. The rtti for these is always
+/// core.Type. TODO(leafp): consider the possibility that we can
+/// reliably recognize type objects and map directly to core.Type
+/// rather than attaching this property everywhere.
+///
+/// The other kind of object representing a "type" is the instances of the
+/// dart:core Type class. These are the user visible objects you get by calling
+/// "runtimeType" on an object or using a class literal expression. These are
+/// different from the above objects, and are created by calling `wrapType()`
+/// on a runtime type.
+
+/// Tag a closure with a type.
+///
+/// `dart.fn(closure, type)` marks [closure] with the provided runtime [type].
+fn(closure, type) {
+ JS('', '#[#] = #', closure, _runtimeType, type);
+ return closure;
+}
+
+/// Tag a closure with a type that's computed lazily.
+///
+/// `dart.fn(closure, type)` marks [closure] with a getter that uses
+/// [computeType] to return the runtime type.
+///
+/// The getter/setter replaces the property with a value property, so the
+/// resulting function is compatible with [fn] and the type can be set again
+/// safely.
+lazyFn(closure, Object Function() computeType) {
+ defineAccessor(closure, _runtimeType,
+ get: () => defineValue(closure, _runtimeType, computeType()),
+ set: (value) => defineValue(closure, _runtimeType, value),
+ configurable: true);
+ return closure;
+}
+
+// TODO(vsm): How should we encode the runtime type?
+final _runtimeType = JS('', 'Symbol("_runtimeType")');
+
+final _moduleName = JS('', 'Symbol("_moduleName")');
+
+getFunctionType(obj) {
+ // TODO(vsm): Encode this properly on the function for Dart-generated code.
+ var args = JS<List>('!', 'Array(#.length).fill(#)', obj, dynamic);
+ return fnType(bottom, args, JS('', 'void 0'));
+}
+
+/// Returns the runtime representation of the type of obj.
+///
+/// The resulting object is used internally for runtime type checking. This is
+/// different from the user-visible Type object returned by calling
+/// `runtimeType` on some Dart object.
+getReifiedType(obj) {
+ switch (JS<String>('!', 'typeof #', obj)) {
+ case "object":
+ if (obj == null) return JS('', '#', Null);
+ if (JS('!', '# instanceof #', obj, Object)) {
+ return JS('', '#.constructor', obj);
+ }
+ var result = JS('', '#[#]', obj, _extensionType);
+ if (result == null) return JS('', '#', jsobject);
+ return result;
+ case "function":
+ // All Dart functions and callable classes must set _runtimeType
+ var result = JS('', '#[#]', obj, _runtimeType);
+ if (result != null) return result;
+ return JS('', '#', jsobject);
+ case "undefined":
+ return JS('', '#', Null);
+ case "number":
+ return JS('', 'Math.floor(#) == # ? # : #', obj, obj, int, double);
+ case "boolean":
+ return JS('', '#', bool);
+ case "string":
+ return JS('', '#', String);
+ case "symbol":
+ default:
+ return JS('', '#', jsobject);
+ }
+}
+
+/// Return the module name for a raw library object.
+String getModuleName(Object module) => JS('', '#[#]', module, _moduleName);
+
+final _loadedModules = JS('', 'new Map()');
+final _loadedPartMaps = JS('', 'new Map()');
+final _loadedSourceMaps = JS('', 'new Map()');
+
+List<String> getModuleNames() {
+ return JSArray<String>.of(JS('', 'Array.from(#.keys())', _loadedModules));
+}
+
+String getSourceMap(String moduleName) {
+ return JS('!', '#.get(#)', _loadedSourceMaps, moduleName);
+}
+
+/// Return all library objects in the specified module.
+getModuleLibraries(String name) {
+ var module = JS('', '#.get(#)', _loadedModules, name);
+ if (module == null) return null;
+ JS('', '#[#] = #', module, _moduleName, name);
+ return module;
+}
+
+/// Return the part map for a specific module.
+getModulePartMap(String name) => JS('', '#.get(#)', _loadedPartMaps, name);
+
+/// Track all libraries
+void trackLibraries(
+ String moduleName, Object libraries, Object parts, String sourceMap) {
+ if (parts is String) {
+ // Added for backwards compatibility.
+ // package:build_web_compilers currently invokes this without [parts]
+ // in its bootstrap code.
+ sourceMap = parts as String;
+ parts = JS('', '{}');
+ }
+ JS('', '#.set(#, #)', _loadedSourceMaps, moduleName, sourceMap);
+ JS('', '#.set(#, #)', _loadedModules, moduleName, libraries);
+ JS('', '#.set(#, #)', _loadedPartMaps, moduleName, parts);
+}
+
+List<String> _libraries;
+Map<String, Object> _libraryObjects;
+Map<String, List<String>> _parts;
+
+_computeLibraryMetadata() {
+ _libraries = [];
+ _libraryObjects = {};
+ _parts = {};
+ var modules = getModuleNames();
+ for (var name in modules) {
+ // Add libraries from each module.
+ var module = getModuleLibraries(name);
+ var libraries = getOwnPropertyNames(module).cast<String>();
+ _libraries.addAll(libraries);
+ for (var library in libraries) {
+ _libraryObjects[library] = JS('', '#.#', module, library);
+ }
+
+ // Add parts from each module.
+ var partMap = getModulePartMap(name);
+ libraries = getOwnPropertyNames(partMap).cast<String>();
+ for (var library in libraries) {
+ _parts[library] = List.from(JS('List', '#.#', partMap, library));
+ }
+ }
+}
+
+/// Returns the JS library object for a given library [uri] or
+/// undefined / null if it isn't loaded. Top-level types and
+/// methods are available on this object.
+Object getLibrary(String uri) {
+ if (_libraryObjects == null) {
+ _computeLibraryMetadata();
+ }
+ return _libraryObjects[uri];
+}
+
+/// Returns a JSArray of library uris (e.g,
+/// ['dart:core', 'dart:_internal', ..., 'package:foo/bar.dart', ... 'main.dart'])
+/// loaded in this application.
+List<String> getLibraries() {
+ if (_libraries == null) {
+ _computeLibraryMetadata();
+ }
+ return _libraries;
+}
+
+/// Returns a JSArray of part uris for a given [libraryUri].
+/// The part uris will be relative to the [libraryUri].
+///
+/// E.g., invoking `getParts('package:intl/intl.dart')` returns (as of this
+/// writing): ```
+/// ["src/intl/bidi_formatter.dart", "src/intl/bidi_utils.dart",
+/// "src/intl/compact_number_format.dart", "src/intl/date_format.dart",
+/// "src/intl/date_format_field.dart", "src/intl/date_format_helpers.dart",
+/// "src/intl/number_format.dart"]
+/// ```
+///
+/// If [libraryUri] doesn't map to a library or maps to a library with no
+/// parts, an empty list is returned.
+List<String> getParts(String libraryUri) {
+ if (_parts == null) {
+ _computeLibraryMetadata();
+ }
+ return _parts[libraryUri] ?? [];
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart
new file mode 100644
index 0000000..99e1ab9
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart
@@ -0,0 +1,210 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@ReifyFunctionTypes(false)
+library dart._runtime;
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'dart:_debugger' show stackTraceMapper, trackCall;
+import 'dart:_foreign_helper' show JS, JSExportName, rest, spread;
+import 'dart:_interceptors' show JSArray, jsNull, JSFunction, NativeError;
+import 'dart:_internal' as internal show Symbol;
+import 'dart:_js_helper'
+ show
+ AssertionErrorImpl,
+ BooleanConversionAssertionError,
+ CastErrorImpl,
+ DartIterator,
+ TypeErrorImpl,
+ JsLinkedHashMap,
+ ImmutableMap,
+ PrivateSymbol,
+ ReifyFunctionTypes,
+ NoReifyGeneric,
+ notNull,
+ undefined;
+
+export 'dart:_debugger' show getDynamicStats, clearDynamicStats, trackCall;
+
+part 'utils.dart';
+part 'classes.dart';
+part 'rtti.dart';
+part 'types.dart';
+part 'errors.dart';
+part 'operations.dart';
+
+// TODO(vsm): Move polyfill code to dart:html.
+// Note, native extensions are registered onto types in dart.global.
+// This polyfill needs to run before the corresponding dart:html code is run.
+final _polyfilled = JS('', 'Symbol("_polyfilled")');
+
+bool polyfill(window) => JS('', '''(() => {
+ if ($window[$_polyfilled]) return false;
+ $window[$_polyfilled] = true;
+
+ if (typeof $window.NodeList !== "undefined") {
+ // TODO(vsm): Do we still need these?
+ $window.NodeList.prototype.get = function(i) { return this[i]; };
+ $window.NamedNodeMap.prototype.get = function(i) { return this[i]; };
+ $window.DOMTokenList.prototype.get = function(i) { return this[i]; };
+ $window.HTMLCollection.prototype.get = function(i) { return this[i]; };
+
+ // Expose constructors for DOM types dart:html needs to assume are
+ // available on window.
+ if (typeof $window.PannerNode == "undefined") {
+ let audioContext;
+ if (typeof $window.AudioContext == "undefined" &&
+ (typeof $window.webkitAudioContext != "undefined")) {
+ audioContext = new $window.webkitAudioContext();
+ } else {
+ audioContext = new $window.AudioContext();
+ $window.StereoPannerNode =
+ audioContext.createStereoPanner().constructor;
+ }
+ $window.PannerNode = audioContext.createPanner().constructor;
+ }
+ if (typeof $window.AudioSourceNode == "undefined") {
+ $window.AudioSourceNode = MediaElementAudioSourceNode.__proto__;
+ }
+ if (typeof $window.FontFaceSet == "undefined") {
+ // CSS Font Loading is not supported on Edge.
+ if (typeof $window.document.fonts != "undefined") {
+ $window.FontFaceSet = $window.document.fonts.__proto__.constructor;
+ }
+ }
+ if (typeof $window.MemoryInfo == "undefined") {
+ if (typeof $window.performance.memory != "undefined") {
+ $window.MemoryInfo = $window.performance.memory.constructor;
+ }
+ }
+ if (typeof $window.Geolocation == "undefined") {
+ $window.Geolocation == $window.navigator.geolocation.constructor;
+ }
+ if (typeof $window.Animation == "undefined") {
+ let d = $window.document.createElement('div');
+ if (typeof d.animate != "undefined") {
+ $window.Animation = d.animate(d).constructor;
+ }
+ }
+ if (typeof $window.SourceBufferList == "undefined") {
+ if ('MediaSource' in $window) {
+ $window.SourceBufferList =
+ new $window.MediaSource().sourceBuffers.constructor;
+ }
+ }
+ if (typeof $window.SpeechRecognition == "undefined") {
+ $window.SpeechRecognition = $window.webkitSpeechRecognition;
+ $window.SpeechRecognitionError = $window.webkitSpeechRecognitionError;
+ $window.SpeechRecognitionEvent = $window.webkitSpeechRecognitionEvent;
+ }
+ }
+ return true;
+})()''');
+
+@JSExportName('global')
+final global_ = JS('', '''
+ function () {
+ // Find global object.
+ var globalState = (typeof window != "undefined") ? window
+ : (typeof global != "undefined") ? global
+ : (typeof self != "undefined") ? self : null;
+ if (!globalState) {
+ // Some platforms (e.g., d8) do not define any of the above. The
+ // following is a non-CSP safe way to access the global object:
+ globalState = new Function('return this;')();
+ }
+
+ $polyfill(globalState);
+
+ // By default, stack traces cutoff at 10. Set the limit to Infinity for
+ // better debugging.
+ if (globalState.Error) {
+ globalState.Error.stackTraceLimit = Infinity;
+ }
+
+ // These settings must be configured before the application starts so that
+ // user code runs with the correct configuration.
+ let settings = 'ddcSettings' in globalState ? globalState.ddcSettings : {};
+
+ $trackProfile(
+ 'trackProfile' in settings ? settings.trackProfile : false);
+
+ return globalState;
+ }()
+''');
+
+void trackProfile(bool flag) {
+ JS('', 'dart.__trackProfile = #', flag);
+}
+
+final JsSymbol = JS('', 'Symbol');
+
+/// The prototype used for all Dart libraries.
+///
+/// This makes it easy to identify Dart library objects, and also improves
+/// performance (JS engines such as V8 tend to assume `Object.create(null)` is
+/// used for a Map, so they don't optimize it as they normally would for
+/// class-like objects).
+///
+/// The `dart.library` field is set by the compiler during SDK bootstrapping
+/// (because it is needed for dart:_runtime itself), so we don't need to
+/// initialize it here. The name `dart.library` is used because it reads nicely,
+/// for example:
+///
+/// const my_library = Object.create(dart.library);
+///
+Object libraryPrototype = JS('', 'dart.library');
+
+// TODO(vsm): Remove once this flag we've removed the ability to
+// whitelist / fallback on the old behavior.
+bool startAsyncSynchronously = true;
+void setStartAsyncSynchronously([bool value = true]) {
+ startAsyncSynchronously = value;
+}
+
+/// A list of all JS Maps used for caching results, such as by [isSubtypeOf] and
+/// [generic].
+///
+/// This is used by [hotRestart] to ensure we don't leak types from previous
+/// libraries.
+@notNull
+final List<Object> _cacheMaps = JS('!', '[]');
+
+/// A list of functions to reset static fields back to their uninitialized
+/// state.
+///
+/// This is populated by [defineLazyField], and only contains the list of fields
+/// that have actually been initialized.
+@notNull
+final List<void Function()> _resetFields = JS('', '[]');
+
+/// Clears out runtime state in `dartdevc` so we can hot-restart.
+///
+/// This should be called when the user requests a hot-restart, when the UI is
+/// handling that user action.
+void hotRestart() {
+ // TODO(jmesserly): we need to prevent all pending callbacks from firing.
+ for (var f in _resetFields) f();
+ _resetFields.clear();
+ for (var m in _cacheMaps) JS('', '#.clear()', m);
+ _cacheMaps.clear();
+ JS('', '#.clear()', constantMaps);
+}
+
+/// Marks enqueuing an async operation.
+///
+/// This will be called by library code when enqueuing an async operation
+/// controlled by the JavaScript event handler.
+///
+/// It will also call [removeAsyncCallback] when Dart callback is about to be
+/// executed (note this is called *before* the callback executes, so more
+/// async operations could be added from that).
+void Function() addAsyncCallback = JS('', 'function() {}');
+
+/// Marks leaving a javascript async operation.
+///
+/// See [addAsyncCallback].
+void Function() removeAsyncCallback = JS('', 'function() {}');
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
new file mode 100644
index 0000000..3175eeb
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -0,0 +1,1438 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This library defines the representation of runtime types.
+part of dart._runtime;
+
+final metadata = JS('', 'Symbol("metadata")');
+
+/// Types in dart are represented internally at runtime as follows.
+///
+/// - Normal nominal types, produced from classes, are represented
+/// at runtime by the JS class of which they are an instance.
+/// If the type is the result of instantiating a generic class,
+/// then the "classes" module manages the association between the
+/// instantiated class and the original class declaration
+/// and the type arguments with which it was instantiated. This
+/// association can be queried via the "classes" module".
+///
+/// - All other types are represented as instances of class [DartType],
+/// defined in this module.
+/// - Dynamic, Void, and Bottom are singleton instances of sentinal
+/// classes.
+/// - Function types are instances of subclasses of AbstractFunctionType.
+///
+/// Function types are represented in one of two ways:
+/// - As an instance of FunctionType. These are eagerly computed.
+/// - As an instance of TypeDef. The TypeDef representation lazily
+/// computes an instance of FunctionType, and delegates to that instance.
+///
+/// These above "runtime types" are what is used for implementing DDC's
+/// internal type checks. These objects are distinct from the objects exposed
+/// to user code by class literals and calling `Object.runtimeType`. In DDC,
+/// the latter are represented by instances of WrappedType which contain a
+/// real runtime type internally. This ensures that the returned object only
+/// exposes the API that Type defines:
+///
+/// get String name;
+/// String toString();
+///
+/// These "runtime types" have methods for performing type checks. The methods
+/// have the following JavaScript names which are designed to not collide with
+/// static methods, which are also placed 'on' the class constructor function.
+///
+/// T.is(o): Implements 'o is T'.
+/// T.as(o): Implements 'o as T'.
+/// T._check(o): Implements the type assertion of 'T x = o;'
+///
+/// By convention, we used named JavaScript functions for these methods with the
+/// name 'is_X', 'as_X' and 'check_X' for various X to indicate the type or the
+/// implementation strategy for the test (e.g 'is_String', 'is_G' for generic
+/// types, etc.)
+// TODO(jmesserly): we shouldn't implement Type here. It should be moved down
+// to AbstractFunctionType.
+class DartType implements Type {
+ String get name => this.toString();
+
+ // TODO(jmesserly): these should never be reached, can be make them abstract?
+ @notNull
+ @JSExportName('is')
+ bool is_T(object) => instanceOf(object, this);
+
+ @JSExportName('as')
+ as_T(object) => cast(object, this, false);
+
+ @JSExportName('_check')
+ check_T(object) => cast(object, this, true);
+}
+
+class DynamicType extends DartType {
+ toString() => 'dynamic';
+
+ @JSExportName('is')
+ bool is_T(object) => true;
+
+ @JSExportName('as')
+ as_T(object) => object;
+
+ @JSExportName('_check')
+ check_T(object) => object;
+}
+
+@notNull
+bool _isJsObject(obj) => JS('!', '# === #', getReifiedType(obj), jsobject);
+
+/// Asserts that [f] is a native JS functions and returns it if so.
+/// This function should be used to ensure that a function is a native
+/// JS functions in contexts that expect that.
+F assertInterop<F extends Function>(F f) {
+ // TODO(vsm): Throw a more specific error if this fails.
+ assert(_isJsObject(f));
+ return f;
+}
+
+/// The Dart type that represents a JavaScript class(/constructor) type.
+///
+/// The JavaScript type may not exist, either because it's not loaded yet, or
+/// because it's not available (such as with mocks). To handle this gracefully,
+/// we disable type checks for in these cases, and allow any JS object to work
+/// as if it were an instance of this JS type.
+class LazyJSType extends DartType {
+ Function() _getRawJSTypeFn;
+ @notNull
+ final String _dartName;
+ Object _rawJSType;
+
+ LazyJSType(this._getRawJSTypeFn, this._dartName);
+
+ toString() {
+ var raw = _getRawJSType();
+ return raw != null ? typeName(raw) : "JSObject<$_dartName>";
+ }
+
+ Object _getRawJSType() {
+ var raw = _rawJSType;
+ if (raw != null) return raw;
+
+ // Try to evaluate the JS type. If this fails for any reason, we'll try
+ // again next time.
+ // TODO(jmesserly): is it worth trying again? It may create unnecessary
+ // overhead, especially if exceptions are being thrown. Also it means the
+ // behavior of a given type check can change later on.
+ try {
+ raw = _getRawJSTypeFn();
+ } catch (e) {}
+
+ if (raw == null) {
+ _warn('Cannot find native JavaScript type ($_dartName) for type check');
+ } else {
+ _rawJSType = raw;
+ _getRawJSTypeFn = null; // Free the function that computes the JS type.
+ }
+ return raw;
+ }
+
+ Object rawJSTypeForCheck() => _getRawJSType() ?? jsobject;
+
+ @notNull
+ bool isRawJSType(obj) {
+ var raw = _getRawJSType();
+ if (raw != null) return JS('!', '# instanceof #', obj, raw);
+ return _isJsObject(obj);
+ }
+
+ @notNull
+ @JSExportName('is')
+ bool is_T(obj) => isRawJSType(obj) || instanceOf(obj, this);
+
+ @JSExportName('as')
+ as_T(obj) => obj == null || is_T(obj) ? obj : castError(obj, this, false);
+
+ @JSExportName('_check')
+ check_T(obj) => obj == null || is_T(obj) ? obj : castError(obj, this, true);
+}
+
+/// An anonymous JS type
+///
+/// For the purposes of subtype checks, these match any JS type.
+class AnonymousJSType extends DartType {
+ final String _dartName;
+ AnonymousJSType(this._dartName);
+ toString() => _dartName;
+
+ @JSExportName('is')
+ bool is_T(obj) => _isJsObject(obj) || instanceOf(obj, this);
+
+ @JSExportName('as')
+ as_T(obj) => obj == null || _isJsObject(obj) ? obj : cast(obj, this, false);
+
+ @JSExportName('_check')
+ check_T(obj) => obj == null || _isJsObject(obj) ? obj : cast(obj, this, true);
+}
+
+void _warn(arg) {
+ JS('void', 'console.warn(#)', arg);
+}
+
+var _lazyJSTypes = JS('', 'new Map()');
+var _anonymousJSTypes = JS('', 'new Map()');
+
+lazyJSType(Function() getJSTypeCallback, String name) {
+ var ret = JS('', '#.get(#)', _lazyJSTypes, name);
+ if (ret == null) {
+ ret = LazyJSType(getJSTypeCallback, name);
+ JS('', '#.set(#, #)', _lazyJSTypes, name, ret);
+ }
+ return ret;
+}
+
+anonymousJSType(String name) {
+ var ret = JS('', '#.get(#)', _anonymousJSTypes, name);
+ if (ret == null) {
+ ret = AnonymousJSType(name);
+ JS('', '#.set(#, #)', _anonymousJSTypes, name, ret);
+ }
+ return ret;
+}
+
+@JSExportName('dynamic')
+final _dynamic = DynamicType();
+
+class VoidType extends DartType {
+ toString() => 'void';
+}
+
+@JSExportName('void')
+final void_ = VoidType();
+
+class BottomType extends DartType {
+ toString() => 'bottom';
+}
+
+// TODO(vsm): We reify bottom as Null. We will revisit this with
+// non-nullable types.
+final bottom = unwrapType(Null);
+
+class JSObjectType extends DartType {
+ toString() => 'NativeJavaScriptObject';
+}
+
+final jsobject = JSObjectType();
+
+/// Dev Compiler's implementation of Type, wrapping its internal [_type].
+class _Type extends Type {
+ /// The internal type representation, either a [DartType] or class constructor
+ /// function.
+ // TODO(jmesserly): introduce InterfaceType so we don't have to special case
+ // classes
+ @notNull
+ final Object _type;
+
+ _Type(this._type);
+
+ toString() => typeName(_type);
+
+ Type get runtimeType => Type;
+}
+
+/// Given an internal runtime type object, wraps it in a `_Type` object
+/// that implements the dart:core Type interface.
+Type wrapType(type) {
+ // If we've already wrapped this type once, use the previous wrapper. This
+ // way, multiple references to the same type return an identical Type.
+ if (JS('!', '#.hasOwnProperty(#)', type, _typeObject)) {
+ return JS('', '#[#]', type, _typeObject);
+ }
+ var result = _Type(type);
+ JS('', '#[#] = #', type, _typeObject, result);
+ return result;
+}
+
+/// The symbol used to store the cached `Type` object associated with a class.
+final _typeObject = JS('', 'Symbol("typeObject")');
+
+/// Given a WrappedType, return the internal runtime type object.
+Object unwrapType(Type obj) => JS<_Type>('', '#', obj)._type;
+
+// Marker class for generic functions, typedefs, and non-generic functions.
+abstract class AbstractFunctionType extends DartType {}
+
+/// Memo table for named argument groups. A named argument packet
+/// {name1 : type1, ..., namen : typen} corresponds to the path
+/// n, name1, type1, ...., namen, typen. The element of the map
+/// reached via this path (if any) is the canonical representative
+/// for this packet.
+final _fnTypeNamedArgMap = JS('', 'new Map()');
+
+/// Memo table for positional argument groups. A positional argument
+/// packet [type1, ..., typen] (required or optional) corresponds to
+/// the path n, type1, ...., typen. The element reached via
+/// this path (if any) is the canonical representative for this
+/// packet. Note that required and optional parameters packages
+/// may have the same canonical representation.
+final _fnTypeArrayArgMap = JS('', 'new Map()');
+
+/// Memo table for function types. The index path consists of the
+/// path length - 1, the returnType, the canonical positional argument
+/// packet, and if present, the canonical optional or named argument
+/// packet. A level of indirection could be avoided here if desired.
+final _fnTypeTypeMap = JS('', 'new Map()');
+
+/// Memo table for small function types with no optional or named
+/// arguments and less than a fixed n (currently 3) number of
+/// required arguments. Indexing into this table by the number
+/// of required arguments yields a map which is indexed by the
+/// argument types themselves. The element reached via this
+/// index path (if present) is the canonical function type.
+final List _fnTypeSmallMap = JS('', '[new Map(), new Map(), new Map()]');
+
+@NoReifyGeneric()
+T _memoizeArray<T>(map, arr, T create()) => JS('', '''(() => {
+ let len = $arr.length;
+ $map = $_lookupNonTerminal($map, len);
+ for (var i = 0; i < len-1; ++i) {
+ $map = $_lookupNonTerminal($map, $arr[i]);
+ }
+ let result = $map.get($arr[len-1]);
+ if (result !== void 0) return result;
+ $map.set($arr[len-1], result = $create());
+ return result;
+})()''');
+
+List _canonicalizeArray(List array, map) =>
+ _memoizeArray(map, array, () => array);
+
+// TODO(leafp): This only canonicalizes of the names are
+// emitted in a consistent order.
+_canonicalizeNamed(named, map) => JS('', '''(() => {
+ let key = [];
+ let names = $getOwnPropertyNames($named);
+ for (var i = 0; i < names.length; ++i) {
+ let name = names[i];
+ let type = $named[name];
+ key.push(name);
+ key.push(type);
+ }
+ return $_memoizeArray($map, key, () => $named);
+})()''');
+
+// TODO(leafp): This handles some low hanging fruit, but
+// really we should make all of this faster, and also
+// handle more cases here.
+FunctionType _createSmall(returnType, List required) => JS('', '''(() => {
+ let count = $required.length;
+ let map = $_fnTypeSmallMap[count];
+ for (var i = 0; i < count; ++i) {
+ map = $_lookupNonTerminal(map, $required[i]);
+ }
+ let result = map.get($returnType);
+ if (result !== void 0) return result;
+ result = ${new FunctionType(returnType, required, [], JS('', '{}'))};
+ map.set($returnType, result);
+ return result;
+})()''');
+
+class FunctionType extends AbstractFunctionType {
+ final Type returnType;
+ List args;
+ List optionals;
+ // Named arguments native JS Object of the form { namedArgName: namedArgType }
+ final named;
+ // TODO(vsm): This is just parameter metadata for now.
+ // Suspected but not confirmed: Only used by mirrors for pageloader2 support.
+ // The metadata is represented as a list of JS arrays, one for each argument
+ // that contains the annotations for that argument or an empty array if there
+ // are no annotations.
+ List metadata = [];
+ String _stringValue;
+
+ /// Construct a function type.
+ ///
+ /// We eagerly normalize the argument types to avoid having to deal with this
+ /// logic in multiple places.
+ ///
+ /// This code does best effort canonicalization. It does not guarantee that
+ /// all instances will share.
+ ///
+ /// Note: Generic function subtype checks assume types have been canonicalized
+ /// when testing if type bounds are equal.
+ static FunctionType create(returnType, List args, extra) {
+ // Note that if extra is ever passed as an empty array
+ // or an empty map, we can end up with semantically
+ // identical function types that don't canonicalize
+ // to the same object since we won't fall into this
+ // fast path.
+ if (extra == null && JS<bool>('!', '#.length < 3', args)) {
+ return _createSmall(returnType, args);
+ }
+ args = _canonicalizeArray(args, _fnTypeArrayArgMap);
+ var keys;
+ FunctionType Function() create;
+ if (extra == null) {
+ keys = [returnType, args];
+ create = () => FunctionType(returnType, args, [], JS('', '{}'));
+ } else if (JS('!', '# instanceof Array', extra)) {
+ var optionals =
+ _canonicalizeArray(JS('', '#', extra), _fnTypeArrayArgMap);
+ keys = [returnType, args, optionals];
+ create = () => FunctionType(returnType, args, optionals, JS('', '{}'));
+ } else {
+ var named = _canonicalizeNamed(extra, _fnTypeNamedArgMap);
+ keys = [returnType, args, named];
+ create = () => FunctionType(returnType, args, [], named);
+ }
+ return _memoizeArray(_fnTypeTypeMap, keys, create);
+ }
+
+ /// Returns the function arguments.
+ ///
+ /// If an argument is provided with annotations (encoded as a JS array where
+ /// the first element is the argument, and the rest are annotations) the
+ /// annotations are extracted and saved in [metadata].
+ List _process(List array) {
+ var result = [];
+ for (var i = 0; JS<bool>('!', '# < #.length', i, array); ++i) {
+ var arg = JS('', '#[#]', array, i);
+ if (JS('!', '# instanceof Array', arg)) {
+ JS('', '#.push(#.slice(1))', metadata, arg);
+ JS('', '#.push(#[0])', result, arg);
+ } else {
+ JS('', '#.push([])', metadata);
+ JS('', '#.push(#)', result, arg);
+ }
+ }
+ return result;
+ }
+
+ FunctionType(this.returnType, this.args, this.optionals, this.named) {
+ this.args = _process(this.args);
+ this.optionals = _process(this.optionals);
+ // TODO(vsm): Named arguments were never used by pageloader2 so they were
+ // never processed here.
+ }
+
+ toString() => name;
+
+ int get requiredParameterCount => args.length;
+ int get positionalParameterCount => args.length + optionals.length;
+
+ getPositionalParameter(int i) {
+ int n = args.length;
+ return i < n ? args[i] : optionals[i + n];
+ }
+
+ Map<String, Object> getNamedParameters() {
+ var result = <String, Object>{};
+ var names = getOwnPropertyNames(named);
+ JS('', '#.sort()', names);
+ for (var i = 0; JS<bool>('!', '# < #.length', i, names); ++i) {
+ String name = JS('!', '#[#]', names, i);
+ result[name] = JS('', '#[#]', named, name);
+ }
+ return result;
+ }
+
+ get name {
+ if (_stringValue != null) return _stringValue;
+
+ var buffer = '(';
+ for (var i = 0; JS<bool>('!', '# < #.length', i, args); ++i) {
+ if (i > 0) {
+ buffer += ', ';
+ }
+ buffer += typeName(JS('', '#[#]', args, i));
+ }
+ if (JS('!', '#.length > 0', optionals)) {
+ if (JS('!', '#.length > 0', args)) buffer += ', ';
+ buffer += '[';
+ for (var i = 0; JS<bool>('!', '# < #.length', i, optionals); ++i) {
+ if (i > 0) {
+ buffer += ', ';
+ }
+ buffer += typeName(JS('', '#[#]', optionals, i));
+ }
+ buffer += ']';
+ } else if (JS('!', 'Object.keys(#).length > 0', named)) {
+ if (JS('!', '#.length > 0', args)) buffer += ', ';
+ buffer += '{';
+ var names = getOwnPropertyNames(named);
+ JS('', '#.sort()', names);
+ for (var i = 0; JS<bool>('!', '# < #.length', i, names); ++i) {
+ if (i > 0) {
+ buffer += ', ';
+ }
+ var typeNameString = typeName(JS('', '#[#[#]]', named, names, i));
+ buffer += '$typeNameString ${JS('', '#[#]', names, i)}';
+ }
+ buffer += '}';
+ }
+
+ var returnTypeName = typeName(returnType);
+ buffer += ') => $returnTypeName';
+ _stringValue = buffer;
+ return buffer;
+ }
+
+ @JSExportName('is')
+ bool is_T(obj) {
+ if (JS('!', 'typeof # == "function"', obj)) {
+ var actual = JS('', '#[#]', obj, _runtimeType);
+ // If there's no actual type, it's a JS function.
+ // Allow them to subtype all Dart function types.
+ return actual == null || isSubtypeOf(actual, this);
+ }
+ return false;
+ }
+
+ @JSExportName('as')
+ as_T(obj, [@notNull bool isImplicit = false]) {
+ if (obj == null) return obj;
+ if (JS('!', 'typeof # == "function"', obj)) {
+ var actual = JS('', '#[#]', obj, _runtimeType);
+ // If there's no actual type, it's a JS function.
+ // Allow them to subtype all Dart function types.
+ if (actual == null || isSubtypeOf(actual, this)) {
+ return obj;
+ }
+ }
+ return castError(obj, this, isImplicit);
+ }
+
+ @JSExportName('_check')
+ check_T(obj) => as_T(obj, true);
+}
+
+/// A type variable, used by [GenericFunctionType] to represent a type formal.
+class TypeVariable extends DartType {
+ final String name;
+
+ TypeVariable(this.name);
+
+ toString() => name;
+}
+
+class GenericFunctionType extends AbstractFunctionType {
+ final _instantiateTypeParts;
+ final int formalCount;
+ final _instantiateTypeBounds;
+ List<TypeVariable> _typeFormals;
+
+ GenericFunctionType(instantiateTypeParts, this._instantiateTypeBounds)
+ : _instantiateTypeParts = instantiateTypeParts,
+ formalCount = JS('!', '#.length', instantiateTypeParts);
+
+ List<TypeVariable> get typeFormals {
+ if (_typeFormals != null) return _typeFormals;
+ return _typeFormals = _typeFormalsFromFunction(_instantiateTypeParts);
+ }
+
+ /// `true` if there are bounds on any of the generic type parameters.
+ get hasTypeBounds => _instantiateTypeBounds != null;
+
+ /// Checks that [typeArgs] satisfies the upper bounds of the [typeFormals],
+ /// and throws a [TypeError] if they do not.
+ void checkBounds(List typeArgs) {
+ // If we don't have explicit type parameter bounds, the bounds default to
+ // a top type, so there's nothing to check here.
+ if (!hasTypeBounds) return;
+
+ var bounds = instantiateTypeBounds(typeArgs);
+ var typeFormals = this.typeFormals;
+ for (var i = 0; i < typeArgs.length; i++) {
+ checkTypeBound(typeArgs[i], bounds[i], typeFormals[i].name);
+ }
+ }
+
+ FunctionType instantiate(typeArgs) {
+ var parts = JS('', '#.apply(null, #)', _instantiateTypeParts, typeArgs);
+ return FunctionType.create(
+ JS('', '#[0]', parts), JS('', '#[1]', parts), JS('', '#[2]', parts));
+ }
+
+ List instantiateTypeBounds(List typeArgs) {
+ if (!hasTypeBounds) {
+ // The Dart 1 spec says omitted type parameters have an upper bound of
+ // Object. However Dart 2 uses `dynamic` for the purpose of instantiate to
+ // bounds, so we use that here.
+ return List.filled(formalCount, _dynamic);
+ }
+ // Bounds can be recursive or depend on other type parameters, so we need to
+ // apply type arguments and return the resulting bounds.
+ return JS('List', '#.apply(null, #)', _instantiateTypeBounds, typeArgs);
+ }
+
+ toString() {
+ String s = "<";
+ var typeFormals = this.typeFormals;
+ var typeBounds = instantiateTypeBounds(typeFormals);
+ for (int i = 0, n = typeFormals.length; i < n; i++) {
+ if (i != 0) s += ", ";
+ s += JS<String>('!', '#[#].name', typeFormals, i);
+ var bound = typeBounds[i];
+ if (JS('!', '# !== # && # !== #', bound, dynamic, bound, Object)) {
+ s += " extends $bound";
+ }
+ }
+ s += ">" + instantiate(typeFormals).toString();
+ return s;
+ }
+
+ /// Given a [DartType] [type], if [type] is an uninstantiated
+ /// parameterized type then instantiate the parameters to their
+ /// bounds and return those type arguments.
+ ///
+ /// See the issue for the algorithm description:
+ /// <https://github.com/dart-lang/sdk/issues/27526#issuecomment-260021397>
+ List instantiateDefaultBounds() {
+ var typeFormals = this.typeFormals;
+
+ // All type formals
+ var all = HashMap<Object, int>.identity();
+ // ground types, by index.
+ //
+ // For each index, this will be a ground type for the corresponding type
+ // formal if known, or it will be the original TypeVariable if we are still
+ // solving for it. This array is passed to `instantiateToBounds` as we are
+ // progressively solving for type variables.
+ var defaults = List<Object>(typeFormals.length);
+ // not ground
+ var partials = Map<TypeVariable, Object>.identity();
+
+ var typeBounds = this.instantiateTypeBounds(typeFormals);
+ for (var i = 0; i < typeFormals.length; i++) {
+ var typeFormal = typeFormals[i];
+ var bound = typeBounds[i];
+ all[typeFormal] = i;
+ if (identical(bound, _dynamic)) {
+ defaults[i] = bound;
+ } else {
+ defaults[i] = typeFormal;
+ partials[typeFormal] = bound;
+ }
+ }
+
+ bool hasFreeFormal(Object t) {
+ if (partials.containsKey(t)) return true;
+
+ // Generic classes and typedefs.
+ var typeArgs = getGenericArgs(t);
+ if (typeArgs != null) return typeArgs.any(hasFreeFormal);
+
+ if (t is GenericFunctionType) {
+ return hasFreeFormal(t.instantiate(t.typeFormals));
+ }
+
+ if (t is FunctionType) {
+ return hasFreeFormal(t.returnType) || t.args.any(hasFreeFormal);
+ }
+
+ return false;
+ }
+
+ var hasProgress = true;
+ while (hasProgress) {
+ hasProgress = false;
+ for (var typeFormal in partials.keys) {
+ var partialBound = partials[typeFormal];
+ if (!hasFreeFormal(partialBound)) {
+ int index = all[typeFormal];
+ defaults[index] = instantiateTypeBounds(defaults)[index];
+ partials.remove(typeFormal);
+ hasProgress = true;
+ break;
+ }
+ }
+ }
+
+ // If we stopped making progress, and not all types are ground,
+ // then the whole type is malbounded and an error should be reported
+ // if errors are requested, and a partially completed type should
+ // be returned.
+ if (partials.isNotEmpty) {
+ throwTypeError('Instantiate to bounds failed for type with '
+ 'recursive generic bounds: ${typeName(this)}. '
+ 'Try passing explicit type arguments.');
+ }
+ return defaults;
+ }
+
+ @notNull
+ @JSExportName('is')
+ bool is_T(obj) {
+ if (JS('!', 'typeof # == "function"', obj)) {
+ var actual = JS('', '#[#]', obj, _runtimeType);
+ return actual != null && isSubtypeOf(actual, this);
+ }
+ return false;
+ }
+
+ @JSExportName('as')
+ as_T(obj) {
+ if (obj == null || is_T(obj)) return obj;
+ return castError(obj, this, false);
+ }
+
+ @JSExportName('_check')
+ check_T(obj) {
+ if (obj == null || is_T(obj)) return obj;
+ return castError(obj, this, true);
+ }
+}
+
+List<TypeVariable> _typeFormalsFromFunction(Object typeConstructor) {
+ // Extract parameter names from the function parameters.
+ //
+ // This is not robust in general for user-defined JS functions, but it
+ // should handle the functions generated by our compiler.
+ //
+ // TODO(jmesserly): names of TypeVariables are only used for display
+ // purposes, such as when an error happens or if someone calls
+ // `Type.toString()`. So we could recover them lazily rather than eagerly.
+ // Alternatively we could synthesize new names.
+ String str = JS('!', '#.toString()', typeConstructor);
+ var hasParens = str[0] == '(';
+ var end = str.indexOf(hasParens ? ')' : '=>');
+ if (hasParens) {
+ return str
+ .substring(1, end)
+ .split(',')
+ .map((n) => TypeVariable(n.trim()))
+ .toList();
+ } else {
+ return [TypeVariable(str.substring(0, end).trim())];
+ }
+}
+
+/// Create a function type.
+FunctionType fnType(returnType, List args, [@undefined extra]) =>
+ FunctionType.create(returnType, args, extra);
+
+/// Creates a generic function type from [instantiateFn] and [typeBounds].
+///
+/// A function type consists of two things:
+/// * An instantiate function that takes type arguments and returns the
+/// function signature in the form of a two element list. The first element
+/// is the return type. The second element is a list of the argument types.
+/// * A function that returns a list of upper bound constraints for each of
+/// the type formals.
+///
+/// Both functions accept the type parameters, allowing us to substitute values.
+/// The upper bound constraints can be omitted if all of the type parameters use
+/// the default upper bound.
+///
+/// For example given the type <T extends Iterable<T>>(T) -> T, we can declare
+/// this type with `gFnType(T => [T, [T]], T => [Iterable$(T)])`.
+gFnType(instantiateFn, typeBounds) =>
+ GenericFunctionType(instantiateFn, typeBounds);
+
+/// TODO(vsm): Remove when mirrors is deprecated.
+/// This is a temporary workaround to support dart:mirrors, which doesn't
+/// understand generic methods.
+getFunctionTypeMirror(AbstractFunctionType type) {
+ if (type is GenericFunctionType) {
+ var typeArgs = List.filled(type.formalCount, dynamic);
+ return type.instantiate(typeArgs);
+ }
+ return type;
+}
+
+/// Whether the given JS constructor [obj] is a Dart class type.
+@notNull
+bool isType(obj) => JS('', '#[#] === #', obj, _runtimeType, Type);
+
+void checkTypeBound(
+ @notNull Object type, @notNull Object bound, @notNull String name) {
+ if (!isSubtypeOf(type, bound)) {
+ throwTypeError('type `$type` does not extend `$bound` of `$name`.');
+ }
+}
+
+@notNull
+String typeName(type) => JS('', '''(() => {
+ if ($type === void 0) return "undefined type";
+ if ($type === null) return "null type";
+ // Non-instance types
+ if ($type instanceof $DartType) {
+ return $type.toString();
+ }
+
+ // Instance types
+ let tag = $type[$_runtimeType];
+ if (tag === $Type) {
+ let name = $type.name;
+ let args = ${getGenericArgs(type)};
+ if (args == null) return name;
+
+ if (${getGenericClass(type)} == ${getGenericClass(JSArray)}) name = 'List';
+
+ let result = name;
+ result += '<';
+ for (let i = 0; i < args.length; ++i) {
+ if (i > 0) result += ', ';
+ result += $typeName(args[i]);
+ }
+ result += '>';
+ return result;
+ }
+ if (tag) return "Not a type: " + tag.name;
+ return "JSObject<" + $type.name + ">";
+})()''');
+
+/// Returns true if [ft1] <: [ft2].
+_isFunctionSubtype(ft1, ft2) => JS('', '''(() => {
+ let ret1 = $ft1.returnType;
+ let ret2 = $ft2.returnType;
+
+ let args1 = $ft1.args;
+ let args2 = $ft2.args;
+
+ if (args1.length > args2.length) {
+ return false;
+ }
+
+ for (let i = 0; i < args1.length; ++i) {
+ if (!$_isSubtype(args2[i], args1[i])) {
+ return false;
+ }
+ }
+
+ let optionals1 = $ft1.optionals;
+ let optionals2 = $ft2.optionals;
+
+ if (args1.length + optionals1.length < args2.length + optionals2.length) {
+ return false;
+ }
+
+ let j = 0;
+ for (let i = args1.length; i < args2.length; ++i, ++j) {
+ if (!$_isSubtype(args2[i], optionals1[j])) {
+ return false;
+ }
+ }
+
+ for (let i = 0; i < optionals2.length; ++i, ++j) {
+ if (!$_isSubtype(optionals2[i], optionals1[j])) {
+ return false;
+ }
+ }
+
+ let named1 = $ft1.named;
+ let named2 = $ft2.named;
+
+ let names = $getOwnPropertyNames(named2);
+ for (let i = 0; i < names.length; ++i) {
+ let name = names[i];
+ let n1 = named1[name];
+ let n2 = named2[name];
+ if (n1 === void 0) {
+ return false;
+ }
+ if (!$_isSubtype(n2, n1)) {
+ return false;
+ }
+ }
+
+ return $_isSubtype(ret1, ret2);
+})()''');
+
+/// Returns true if [t1] <: [t2].
+@notNull
+bool isSubtypeOf(Object t1, Object t2) {
+ // TODO(jmesserly): we've optimized `is`/`as`/implicit type checks, so they're
+ // dispatched on the type. Can we optimize the subtype relation too?
+ Object map;
+ if (JS('!', '!#.hasOwnProperty(#)', t1, _subtypeCache)) {
+ JS('', '#[#] = # = new Map()', t1, _subtypeCache, map);
+ _cacheMaps.add(map);
+ } else {
+ map = JS('', '#[#]', t1, _subtypeCache);
+ bool result = JS('', '#.get(#)', map, t2);
+ if (JS('!', '# !== void 0', result)) return result;
+ }
+ var result = _isSubtype(t1, t2);
+ JS('', '#.set(#, #)', map, t2, result);
+ return result;
+}
+
+final _subtypeCache = JS('', 'Symbol("_subtypeCache")');
+
+@notNull
+bool _isBottom(type) => JS('!', '# == # || # == #', type, bottom, type, Null);
+
+@notNull
+bool _isTop(type) {
+ if (_isFutureOr(type)) {
+ return _isTop(JS('', '#[0]', getGenericArgs(type)));
+ }
+ return JS('!', '# == # || # == # || # == #', type, Object, type, dynamic,
+ type, void_);
+}
+
+@notNull
+bool _isFutureOr(type) =>
+ identical(getGenericClass(type), getGenericClass(FutureOr));
+
+bool _isSubtype(t1, t2) => JS('', '''(() => {
+ if ($t1 === $t2) {
+ return true;
+ }
+
+ // Trivially true.
+ if (${_isTop(t2)} || ${_isBottom(t1)}) {
+ return true;
+ }
+
+ // Trivially false.
+ if (${_isTop(t1)} || ${_isBottom(t2)}) {
+ return false;
+ }
+
+ // Handle FutureOr<T> union type.
+ if (${_isFutureOr(t1)}) {
+ let t1TypeArg = ${getGenericArgs(t1)}[0];
+ if (${_isFutureOr(t2)}) {
+ let t2TypeArg = ${getGenericArgs(t2)}[0];
+ // FutureOr<A> <: FutureOr<B> iff A <: B
+ return $_isSubtype(t1TypeArg, t2TypeArg);
+ }
+
+ // given t1 is Future<A> | A, then:
+ // (Future<A> | A) <: t2 iff Future<A> <: t2 and A <: t2.
+ let t1Future = ${getGenericClass(Future)}(t1TypeArg);
+ // Known to handle the case FutureOr<Null> <: Future<Null>.
+ return $_isSubtype(t1Future, $t2) && $_isSubtype(t1TypeArg, $t2);
+ }
+
+ if ($_isFutureOr($t2)) {
+ // given t2 is Future<A> | A, then:
+ // t1 <: (Future<A> | A) iff t1 <: Future<A> or t1 <: A
+ let t2TypeArg = ${getGenericArgs(t2)}[0];
+ let t2Future = ${getGenericClass(Future)}(t2TypeArg);
+ return $_isSubtype($t1, t2Future) || $_isSubtype($t1, t2TypeArg);
+ }
+
+ // "Traditional" name-based subtype check. Avoid passing
+ // function types to the class subtype checks, since we don't
+ // currently distinguish between generic typedefs and classes.
+ if (!($t2 instanceof $AbstractFunctionType)) {
+ // t2 is an interface type.
+
+ if ($t1 instanceof $AbstractFunctionType) {
+ // Function types are only subtypes of interface types `Function` (and top
+ // types, handled already above).
+ return $t2 === $Function;
+ }
+
+ // All JS types are subtypes of anonymous JS types.
+ if ($t1 === $jsobject && $t2 instanceof $AnonymousJSType) {
+ return true;
+ }
+
+ // Compare two interface types.
+ return ${_isInterfaceSubtype(t1, t2)};
+ }
+
+ // Function subtyping.
+ if (!($t1 instanceof $AbstractFunctionType)) {
+ return false;
+ }
+
+ // Handle generic functions.
+ if ($t1 instanceof $GenericFunctionType) {
+ if (!($t2 instanceof $GenericFunctionType)) {
+ return false;
+ }
+
+ // Given generic functions g1 and g2, g1 <: g2 iff:
+ //
+ // g1<TFresh> <: g2<TFresh>
+ //
+ // where TFresh is a list of fresh type variables that both g1 and g2 will
+ // be instantiated with.
+ let formalCount = $t1.formalCount;
+ if (formalCount !== $t2.formalCount) {
+ return false;
+ }
+
+ // Using either function's type formals will work as long as they're both
+ // instantiated with the same ones. The instantiate operation is guaranteed
+ // to avoid capture because it does not depend on its TypeVariable objects,
+ // rather it uses JS function parameters to ensure correct binding.
+ let fresh = $t2.typeFormals;
+
+ // Without type bounds all will instantiate to dynamic. Only need to check
+ // further if at least one of the functions has type bounds.
+ if ($t1.hasTypeBounds || $t2.hasTypeBounds) {
+ // Check the bounds of the type parameters of g1 and g2.
+ // given a type parameter `T1 extends U1` from g1, and a type parameter
+ // `T2 extends U2` from g2, we must ensure that:
+ //
+ // U2 == U1
+ //
+ // (Note there is no variance in the type bounds of type parameters of
+ // generic functions).
+ let t1Bounds = $t1.instantiateTypeBounds(fresh);
+ let t2Bounds = $t2.instantiateTypeBounds(fresh);
+ for (let i = 0; i < formalCount; i++) {
+ if (t2Bounds[i] != t1Bounds[i]) {
+ return false;
+ }
+ }
+ }
+
+ $t1 = $t1.instantiate(fresh);
+ $t2 = $t2.instantiate(fresh);
+ } else if ($t2 instanceof $GenericFunctionType) {
+ return false;
+ }
+
+ // Handle non-generic functions.
+ return ${_isFunctionSubtype(t1, t2)};
+})()''');
+
+bool _isInterfaceSubtype(t1, t2) => JS('', '''(() => {
+ // If we have lazy JS types, unwrap them. This will effectively
+ // reduce to a prototype check below.
+ if ($t1 instanceof $LazyJSType) $t1 = $t1.rawJSTypeForCheck();
+ if ($t2 instanceof $LazyJSType) $t2 = $t2.rawJSTypeForCheck();
+
+ if ($t1 === $t2) {
+ return true;
+ }
+ if ($t1 === $Object) {
+ return false;
+ }
+
+ // Classes cannot subtype `Function` or vice versa.
+ if ($t1 === $Function || $t2 === $Function) {
+ return false;
+ }
+
+ // If t1 is a JS Object, we may not hit core.Object.
+ if ($t1 == null) {
+ return $t2 == $Object || $t2 == $dynamic;
+ }
+
+ // Check if t1 and t2 have the same raw type. If so, check covariance on
+ // type parameters.
+ let raw1 = $getGenericClass($t1);
+ let raw2 = $getGenericClass($t2);
+ if (raw1 != null && raw1 == raw2) {
+ let typeArguments1 = $getGenericArgs($t1);
+ let typeArguments2 = $getGenericArgs($t2);
+ if (typeArguments1.length != typeArguments2.length) {
+ $assertFailed();
+ }
+ for (let i = 0; i < typeArguments1.length; ++i) {
+ if (!$_isSubtype(typeArguments1[i], typeArguments2[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if ($_isInterfaceSubtype(t1.__proto__, $t2)) {
+ return true;
+ }
+
+ // Check mixin.
+ let m1 = $getMixin($t1);
+ if (m1 != null && $_isInterfaceSubtype(m1, $t2)) {
+ return true;
+ }
+
+ // Check interfaces.
+ let getInterfaces = $getImplements($t1);
+ if (getInterfaces) {
+ for (let i1 of getInterfaces()) {
+ if ($_isInterfaceSubtype(i1, $t2)) {
+ return true;
+ }
+ }
+ }
+ return false;
+})()''');
+
+Object extractTypeArguments<T>(T instance, Function f) {
+ if (instance == null) {
+ throw ArgumentError('Cannot extract type of null instance.');
+ }
+ var type = unwrapType(T);
+ if (type is AbstractFunctionType || _isFutureOr(type)) {
+ throw ArgumentError('Cannot extract from non-class type ($type).');
+ }
+ var typeArguments = getGenericArgs(type);
+ if (typeArguments.isEmpty) {
+ throw ArgumentError('Cannot extract from non-generic type ($type).');
+ }
+ var supertype = _getMatchingSupertype(getReifiedType(instance), type);
+ // The signature of this method guarantees that instance is a T, so we
+ // should have a valid non-empty list at this point.
+ assert(supertype != null);
+ var typeArgs = getGenericArgs(supertype);
+ assert(typeArgs != null && typeArgs.isNotEmpty);
+ return dgcall(f, typeArgs, []);
+}
+
+/// Infers type variables based on a series of [trySubtypeMatch] calls, followed
+/// by [getInferredTypes] to return the type.
+class _TypeInferrer {
+ final Map<TypeVariable, TypeConstraint> _typeVariables;
+
+ /// Creates a [TypeConstraintGatherer] which is prepared to gather type
+ /// constraints for the given type parameters.
+ _TypeInferrer(Iterable<TypeVariable> typeVariables)
+ : _typeVariables = Map.fromIterables(
+ typeVariables, typeVariables.map((_) => TypeConstraint()));
+
+ /// Returns the inferred types based on the current constraints.
+ List<Object> getInferredTypes() {
+ var result = List<Object>();
+ for (var constraint in _typeVariables.values) {
+ // Prefer the known bound, if any.
+ if (constraint.lower != null) {
+ result.add(constraint.lower);
+ } else if (constraint.upper != null) {
+ result.add(constraint.upper);
+ } else {
+ return null;
+ }
+ }
+ return result;
+ }
+
+ /// Tries to match [subtype] against [supertype].
+ ///
+ /// If the match succeeds, the resulting type constraints are recorded for
+ /// later use by [computeConstraints]. If the match fails, the set of type
+ /// constraints is unchanged.
+ bool trySubtypeMatch(Object subtype, Object supertype) =>
+ _isSubtypeMatch(subtype, supertype);
+
+ void _constrainLower(TypeVariable parameter, Object lower) {
+ _typeVariables[parameter]._constrainLower(lower);
+ }
+
+ void _constrainUpper(TypeVariable parameter, Object upper) {
+ _typeVariables[parameter]._constrainUpper(upper);
+ }
+
+ bool _isFunctionSubtypeMatch(FunctionType subtype, FunctionType supertype) {
+ // A function type `(M0,..., Mn, [M{n+1}, ..., Mm]) -> R0` is a subtype
+ // match for a function type `(N0,..., Nk, [N{k+1}, ..., Nr]) -> R1` with
+ // respect to `L` under constraints `C0 + ... + Cr + C`
+ // - If `R0` is a subtype match for a type `R1` with respect to `L` under
+ // constraints `C`:
+ // - If `n <= k` and `r <= m`.
+ // - And for `i` in `0...r`, `Ni` is a subtype match for `Mi` with respect
+ // to `L` under constraints `Ci`.
+ // Function types with named parameters are treated analogously to the
+ // positional parameter case above.
+ // A generic function type `<T0 extends B0, ..., Tn extends Bn>F0` is a
+ // subtype match for a generic function type `<S0 extends B0, ..., Sn
+ // extends Bn>F1` with respect to `L` under constraints `Cl`:
+ // - If `F0[Z0/T0, ..., Zn/Tn]` is a subtype match for `F0[Z0/S0, ...,
+ // Zn/Sn]` with respect to `L` under constraints `C`, where each `Zi` is a
+ // fresh type variable with bound `Bi`.
+ // - And `Cl` is `C` with each constraint replaced with its closure with
+ // respect to `[Z0, ..., Zn]`.
+ if (subtype.requiredParameterCount > supertype.requiredParameterCount) {
+ return false;
+ }
+ if (subtype.positionalParameterCount < supertype.positionalParameterCount) {
+ return false;
+ }
+ // Test the return types.
+ if (supertype.returnType is! VoidType &&
+ !_isSubtypeMatch(subtype.returnType, supertype.returnType)) {
+ return false;
+ }
+
+ // Test the parameter types.
+ for (int i = 0, n = supertype.positionalParameterCount; i < n; ++i) {
+ if (!_isSubtypeMatch(supertype.getPositionalParameter(i),
+ subtype.getPositionalParameter(i))) {
+ return false;
+ }
+ }
+ var supertypeNamed = supertype.getNamedParameters();
+ var subtypeNamed = supertype.getNamedParameters();
+ for (var name in supertypeNamed.keys) {
+ var subtypeParamType = subtypeNamed[name];
+ if (subtypeParamType == null) return false;
+ if (!_isSubtypeMatch(supertypeNamed[name], subtypeParamType)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool _isInterfaceSubtypeMatch(Object subtype, Object supertype) {
+ // A type `P<M0, ..., Mk>` is a subtype match for `P<N0, ..., Nk>` with
+ // respect to `L` under constraints `C0 + ... + Ck`:
+ // - If `Mi` is a subtype match for `Ni` with respect to `L` under
+ // constraints `Ci`.
+ // A type `P<M0, ..., Mk>` is a subtype match for `Q<N0, ..., Nj>` with
+ // respect to `L` under constraints `C`:
+ // - If `R<B0, ..., Bj>` is the superclass of `P<M0, ..., Mk>` and `R<B0,
+ // ..., Bj>` is a subtype match for `Q<N0, ..., Nj>` with respect to `L`
+ // under constraints `C`.
+ // - Or `R<B0, ..., Bj>` is one of the interfaces implemented by `P<M0, ...,
+ // Mk>` (considered in lexical order) and `R<B0, ..., Bj>` is a subtype
+ // match for `Q<N0, ..., Nj>` with respect to `L` under constraints `C`.
+ // - Or `R<B0, ..., Bj>` is a mixin into `P<M0, ..., Mk>` (considered in
+ // lexical order) and `R<B0, ..., Bj>` is a subtype match for `Q<N0, ...,
+ // Nj>` with respect to `L` under constraints `C`.
+
+ // Note that since kernel requires that no class may only appear in the set
+ // of supertypes of a given type more than once, the order of the checks
+ // above is irrelevant; we just need to find the matched superclass,
+ // substitute, and then iterate through type variables.
+ var matchingSupertype = _getMatchingSupertype(subtype, supertype);
+ if (matchingSupertype == null) return false;
+
+ var matchingTypeArgs = getGenericArgs(matchingSupertype);
+ var supertypeTypeArgs = getGenericArgs(supertype);
+ for (int i = 0; i < supertypeTypeArgs.length; i++) {
+ if (!_isSubtypeMatch(matchingTypeArgs[i], supertypeTypeArgs[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool _isNull(Object type) => identical(type, unwrapType(Null));
+
+ /// Attempts to match [subtype] as a subtype of [supertype], gathering any
+ /// constraints discovered in the process.
+ ///
+ /// If a set of constraints was found, `true` is returned and the caller
+ /// may proceed to call [computeConstraints]. Otherwise, `false` is returned.
+ ///
+ /// In the case where `false` is returned, some bogus constraints may have
+ /// been added to [_protoConstraints]. It is the caller's responsibility to
+ /// discard them if necessary.
+ bool _isSubtypeMatch(Object subtype, Object supertype) {
+ // A type variable `T` in `L` is a subtype match for any type schema `Q`:
+ // - Under constraint `T <: Q`.
+ if (subtype is TypeVariable && _typeVariables.containsKey(subtype)) {
+ _constrainUpper(subtype, supertype);
+ return true;
+ }
+ // A type schema `Q` is a subtype match for a type variable `T` in `L`:
+ // - Under constraint `Q <: T`.
+ if (supertype is TypeVariable && _typeVariables.containsKey(supertype)) {
+ _constrainLower(supertype, subtype);
+ return true;
+ }
+ // Any two equal types `P` and `Q` are subtype matches under no constraints.
+ // Note: to avoid making the algorithm quadratic, we just check for
+ // identical(). If P and Q are equal but not identical, recursing through
+ // the types will give the proper result.
+ if (identical(subtype, supertype)) return true;
+ // Any type `P` is a subtype match for `dynamic`, `Object`, or `void` under
+ // no constraints.
+ if (_isTop(supertype)) return true;
+ // `Null` is a subtype match for any type `Q` under no constraints.
+ // Note that nullable types will change this.
+ if (_isNull(subtype)) return true;
+
+ // Handle FutureOr<T> union type.
+ if (_isFutureOr(subtype)) {
+ var subtypeArg = getGenericArgs(subtype)[0];
+ if (_isFutureOr(supertype)) {
+ // `FutureOr<P>` is a subtype match for `FutureOr<Q>` with respect to `L`
+ // under constraints `C`:
+ // - If `P` is a subtype match for `Q` with respect to `L` under constraints
+ // `C`.
+ var supertypeArg = getGenericArgs(supertype)[0];
+ return _isSubtypeMatch(subtypeArg, supertypeArg);
+ }
+
+ // `FutureOr<P>` is a subtype match for `Q` with respect to `L` under
+ // constraints `C0 + C1`:
+ // - If `Future<P>` is a subtype match for `Q` with respect to `L` under
+ // constraints `C0`.
+ // - And `P` is a subtype match for `Q` with respect to `L` under
+ // constraints `C1`.
+ var subtypeFuture = JS('!', '#(#)', getGenericClass(Future), subtypeArg);
+ return _isSubtypeMatch(subtypeFuture, supertype) &&
+ _isSubtypeMatch(subtypeArg, supertype);
+ }
+
+ if (_isFutureOr(supertype)) {
+ // `P` is a subtype match for `FutureOr<Q>` with respect to `L` under
+ // constraints `C`:
+ // - If `P` is a subtype match for `Future<Q>` with respect to `L` under
+ // constraints `C`.
+ // - Or `P` is not a subtype match for `Future<Q>` with respect to `L` under
+ // constraints `C`
+ // - And `P` is a subtype match for `Q` with respect to `L` under
+ // constraints `C`
+ var supertypeArg = getGenericArgs(supertype)[0];
+ var supertypeFuture =
+ JS('!', '#(#)', getGenericClass(Future), supertypeArg);
+ return _isSubtypeMatch(subtype, supertypeFuture) ||
+ _isSubtypeMatch(subtype, supertypeArg);
+ }
+
+ // A type variable `T` not in `L` with bound `P` is a subtype match for the
+ // same type variable `T` with bound `Q` with respect to `L` under
+ // constraints `C`:
+ // - If `P` is a subtype match for `Q` with respect to `L` under constraints
+ // `C`.
+ if (subtype is TypeVariable) {
+ return supertype is TypeVariable && identical(subtype, supertype);
+ }
+ if (subtype is GenericFunctionType) {
+ if (supertype is GenericFunctionType) {
+ // Given generic functions g1 and g2, g1 <: g2 iff:
+ //
+ // g1<TFresh> <: g2<TFresh>
+ //
+ // where TFresh is a list of fresh type variables that both g1 and g2 will
+ // be instantiated with.
+ var formalCount = subtype.formalCount;
+ if (formalCount != supertype.formalCount) return false;
+
+ // Using either function's type formals will work as long as they're
+ // both instantiated with the same ones. The instantiate operation is
+ // guaranteed to avoid capture because it does not depend on its
+ // TypeVariable objects, rather it uses JS function parameters to ensure
+ // correct binding.
+ var fresh = supertype.typeFormals;
+
+ // Check the bounds of the type parameters of g1 and g2.
+ // given a type parameter `T1 extends U1` from g1, and a type parameter
+ // `T2 extends U2` from g2, we must ensure that:
+ //
+ // U2 <: U1
+ //
+ // (Note the reversal of direction -- type formal bounds are
+ // contravariant, similar to the function's formal parameter types).
+ //
+ var t1Bounds = subtype.instantiateTypeBounds(fresh);
+ var t2Bounds = supertype.instantiateTypeBounds(fresh);
+ // TODO(jmesserly): we could optimize for the common case of no bounds.
+ for (var i = 0; i < formalCount; i++) {
+ if (!_isSubtypeMatch(t2Bounds[i], t1Bounds[i])) {
+ return false;
+ }
+ }
+ return _isFunctionSubtypeMatch(
+ subtype.instantiate(fresh), supertype.instantiate(fresh));
+ } else {
+ return false;
+ }
+ } else if (supertype is GenericFunctionType) {
+ return false;
+ }
+
+ // A type `P` is a subtype match for `Function` with respect to `L` under no
+ // constraints:
+ // - If `P` implements a call method.
+ // - Or if `P` is a function type.
+ // TODO(paulberry): implement this case.
+ // A type `P` is a subtype match for a type `Q` with respect to `L` under
+ // constraints `C`:
+ // - If `P` is an interface type which implements a call method of type `F`,
+ // and `F` is a subtype match for a type `Q` with respect to `L` under
+ // constraints `C`.
+ // TODO(paulberry): implement this case.
+ if (subtype is FunctionType) {
+ if (supertype is! FunctionType) {
+ if (identical(supertype, unwrapType(Function)) ||
+ identical(supertype, unwrapType(Object))) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ if (supertype is FunctionType) {
+ return _isFunctionSubtypeMatch(subtype, supertype);
+ }
+ }
+ return _isInterfaceSubtypeMatch(subtype, supertype);
+ }
+
+ bool _isTop(Object type) =>
+ identical(type, _dynamic) ||
+ identical(type, void_) ||
+ identical(type, unwrapType(Object));
+}
+
+/// A constraint on a type parameter that we're inferring.
+class TypeConstraint {
+ /// The lower bound of the type being constrained. This bound must be a
+ /// subtype of the type being constrained.
+ Object lower;
+
+ /// The upper bound of the type being constrained. The type being constrained
+ /// must be a subtype of this bound.
+ Object upper;
+
+ void _constrainLower(Object type) {
+ if (lower != null) {
+ if (isSubtypeOf(lower, type)) {
+ // nothing to do, existing lower bound is lower than the new one.
+ return;
+ }
+ if (!isSubtypeOf(type, lower)) {
+ // Neither bound is lower and we don't have GLB, so use bottom type.
+ type = unwrapType(Null);
+ }
+ }
+ lower = type;
+ }
+
+ void _constrainUpper(Object type) {
+ if (upper != null) {
+ if (isSubtypeOf(type, upper)) {
+ // nothing to do, existing upper bound is higher than the new one.
+ return;
+ }
+ if (!isSubtypeOf(upper, type)) {
+ // Neither bound is higher and we don't have LUB, so use top type.
+ type = unwrapType(Object);
+ }
+ }
+ upper = type;
+ }
+
+ String toString() => '${typeName(lower)} <: <type> <: ${typeName(upper)}';
+}
+
+/// Finds a supertype of [subtype] that matches the class [supertype], but may
+/// contain different generic type arguments.
+Object _getMatchingSupertype(Object subtype, Object supertype) {
+ if (identical(subtype, supertype)) return supertype;
+ if (subtype == null || subtype == unwrapType(Object)) return null;
+
+ var subclass = getGenericClass(subtype);
+ var superclass = getGenericClass(supertype);
+ if (subclass != null && identical(subclass, superclass)) {
+ return subtype; // matching supertype found!
+ }
+
+ var result = _getMatchingSupertype(JS('', '#.__proto__', subtype), supertype);
+ if (result != null) return result;
+
+ // Check mixin.
+ var mixin = getMixin(subtype);
+ if (mixin != null) {
+ result = _getMatchingSupertype(mixin, supertype);
+ if (result != null) return result;
+ }
+
+ // Check interfaces.
+ var getInterfaces = getImplements(subtype);
+ if (getInterfaces != null) {
+ for (var iface in getInterfaces()) {
+ result = _getMatchingSupertype(iface, supertype);
+ if (result != null) return result;
+ }
+ }
+
+ return null;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/utils.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/utils.dart
new file mode 100644
index 0000000..2c06179
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/utils.dart
@@ -0,0 +1,136 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._runtime;
+
+/// This library defines a set of general javascript utilities for us
+/// by the Dart runtime.
+// TODO(ochafik): Rewrite some of these in Dart when possible.
+
+final Function(Object, Object, Object) defineProperty =
+ JS('', 'Object.defineProperty');
+
+defineValue(obj, name, value) {
+ defineAccessor(obj, name, value: value, configurable: true, writable: true);
+ return value;
+}
+
+final Function(Object, Object,
+ {Object get,
+ Object set,
+ Object value,
+ bool configurable,
+ bool writable}) defineAccessor = JS('', 'Object.defineProperty');
+
+final Function(Object, Object) getOwnPropertyDescriptor =
+ JS('', 'Object.getOwnPropertyDescriptor');
+
+final Iterable Function(Object) getOwnPropertyNames =
+ JS('', 'Object.getOwnPropertyNames');
+
+final Function(Object) getOwnPropertySymbols =
+ JS('', 'Object.getOwnPropertySymbols');
+
+final Function(Object) getPrototypeOf = JS('', 'Object.getPrototypeOf');
+
+/// This error indicates a strong mode specific failure, other than a type
+/// assertion failure (TypeError) or CastError.
+void throwTypeError(String message) {
+ throw TypeErrorImpl(message);
+}
+
+/// This error indicates a bug in the runtime or the compiler.
+void throwInternalError(String message) {
+ JS('', 'throw Error(#)', message);
+}
+
+Iterable getOwnNamesAndSymbols(obj) {
+ var names = getOwnPropertyNames(obj);
+ var symbols = getOwnPropertySymbols(obj);
+ return JS('', '#.concat(#)', names, symbols);
+}
+
+safeGetOwnProperty(obj, name) {
+ var desc = getOwnPropertyDescriptor(obj, name);
+ if (desc != null) return JS('', '#.value', desc);
+}
+
+/// Defines a lazy static field.
+/// After initial get or set, it will replace itself with a value property.
+// TODO(jmesserly): reusing descriptor objects has been shown to improve
+// performance in other projects (e.g. webcomponents.js ShadowDOM polyfill).
+defineLazyField(to, name, desc) => JS('', '''(() => {
+ const initializer = $desc.get;
+ let init = initializer;
+ let value = null;
+ $desc.get = function() {
+ if (init == null) return value;
+ let f = init;
+ init = $throwCyclicInitializationError;
+ if (f === init) f($name); // throw cycle error
+
+ // On the first (non-cyclic) execution, record the field so we can reset it
+ // later if needed (hot restart).
+ $_resetFields.push(() => {
+ init = initializer;
+ value = null;
+ });
+
+ // Try to evaluate the field, using try+catch to ensure we implement the
+ // correct Dart error semantics.
+ try {
+ value = f();
+ init = null;
+ return value;
+ } catch (e) {
+ init = null;
+ value = null;
+ throw e;
+ }
+ };
+ $desc.configurable = true;
+ if ($desc.set != null) {
+ $desc.set = function(x) {
+ init = null;
+ value = x;
+ };
+ }
+ return ${defineProperty(to, name, desc)};
+})()''');
+
+copyTheseProperties(to, from, names) {
+ for (int i = 0, n = JS('!', '#.length', names); i < n; ++i) {
+ var name = JS('', '#[#]', names, i);
+ if (name == 'constructor') continue;
+ copyProperty(to, from, name);
+ }
+ return to;
+}
+
+copyProperty(to, from, name) {
+ var desc = getOwnPropertyDescriptor(from, name);
+ if (JS('!', '# == Symbol.iterator', name)) {
+ // On native types, Symbol.iterator may already be present.
+ // TODO(jmesserly): investigate if we still need this.
+ // If so, we need to find a better solution.
+ // See https://github.com/dart-lang/sdk/issues/28324
+ var existing = getOwnPropertyDescriptor(to, name);
+ if (existing != null) {
+ if (JS('!', '#.writable', existing)) {
+ JS('', '#[#] = #.value', to, name, desc);
+ }
+ return;
+ }
+ }
+ defineProperty(to, name, desc);
+}
+
+@JSExportName('export')
+exportProperty(to, from, name) => copyProperty(to, from, name);
+
+/// Copy properties from source to destination object.
+/// This operation is commonly called `mixin` in JS.
+copyProperties(to, from) {
+ return copyTheseProperties(to, from, getOwnNamesAndSymbols(from));
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/debugger.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/debugger.dart
new file mode 100644
index 0000000..4618317
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/debugger.dart
@@ -0,0 +1,1016 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._debugger;
+
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show JSArray;
+import 'dart:_js_helper' show InternalMap;
+import 'dart:_runtime' as dart;
+import 'dart:core';
+import 'dart:collection';
+import 'dart:html' as html;
+import 'dart:math';
+
+part 'profile.dart';
+
+/// JsonMLConfig object to pass to devtools to specify how an Object should
+/// be displayed. skipDart signals that an object should not be formatted
+/// by the Dart formatter. This is used to specify that an Object
+/// should just be displayed using the regular JavaScript view instead of a
+/// custom Dart view. For example, this is used to display the JavaScript view
+/// of a Dart Function as a child of the regular Function object. keyToString
+/// signals that a map key object should have its toString() displayed by
+/// the Dart formatter.
+///
+/// We'd like this to be an enum, but we can't because it's a dev_compiler bug.
+class JsonMLConfig {
+ const JsonMLConfig(this.name);
+
+ final String name;
+ static const none = JsonMLConfig("none");
+ static const skipDart = JsonMLConfig("skipDart");
+ static const keyToString = JsonMLConfig("keyToString");
+ static const asClass = JsonMLConfig("asClass");
+ static const asObject = JsonMLConfig("asObject");
+ static const asMap = JsonMLConfig("asMap");
+ toString() => "JsonMLConfig($name)";
+}
+
+int _maxSpanLength = 100;
+var _devtoolsFormatter = JsonMLFormatter(DartFormatter());
+
+/// We truncate a toString() longer than [maxStringLength].
+int maxFormatterStringLength = 100;
+
+String _typeof(object) => JS<String>('!', 'typeof #', object);
+
+List<String> getOwnPropertyNames(object) =>
+ JSArray<String>.of(dart.getOwnPropertyNames(object));
+
+List getOwnPropertySymbols(object) =>
+ JS('List', 'Object.getOwnPropertySymbols(#)', object);
+
+// TODO(jacobr): move this to dart:js and fully implement.
+class JSNative {
+ // Name may be a String or a Symbol.
+ static getProperty(object, name) => JS('', '#[#]', object, name);
+ // Name may be a String or a Symbol.
+ static setProperty(object, name, value) =>
+ JS('', '#[#]=#', object, name, value);
+}
+
+void addMetadataChildren(object, Set<NameValuePair> ret) {
+ ret.add(NameValuePair(
+ name: "[[class]]",
+ value: dart.getReifiedType(object),
+ config: JsonMLConfig.asClass));
+}
+
+/// Add properties from a signature definition [sig] for [object].
+/// Walk the prototype chain if [walkProtypeChain] is set.
+/// Tag types on function typed properties of [object] if [tagTypes] is set.
+///
+void addPropertiesFromSignature(
+ sig, Set<NameValuePair> properties, object, bool walkPrototypeChain,
+ {tagTypes = false}) {
+ // Including these property names doesn't add any value and just clutters
+ // the debugger output.
+ // TODO(jacobr): consider adding runtimeType to this list.
+ var skippedNames = Set()..add('hashCode');
+ var objectPrototype = JS('', 'Object.prototype');
+ while (sig != null && !identical(sig, objectPrototype)) {
+ for (var symbol in getOwnPropertySymbols(sig)) {
+ var dartName = symbolName(symbol);
+ String dartXPrefix = 'dartx.';
+ if (dartName.startsWith(dartXPrefix)) {
+ dartName = dartName.substring(dartXPrefix.length);
+ }
+ if (skippedNames.contains(dartName)) continue;
+ var value = safeGetProperty(object, symbol);
+ // Tag the function with its runtime type.
+ if (tagTypes && _typeof(value) == 'function') {
+ dart.fn(value, JS('', '#[#]', sig, symbol));
+ }
+ properties.add(NameValuePair(name: dartName, value: value));
+ }
+
+ for (var name in getOwnPropertyNames(sig)) {
+ var value = safeGetProperty(object, name);
+ if (skippedNames.contains(name)) continue;
+ // Tag the function with its runtime type.
+ if (tagTypes && _typeof(value) == 'function') {
+ dart.fn(value, JS('', '#[#]', sig, name));
+ }
+ properties.add(NameValuePair(name: name, value: value));
+ }
+
+ if (!walkPrototypeChain) break;
+
+ sig = dart.getPrototypeOf(sig);
+ }
+}
+
+/// Sort properties sorting public names before private names.
+List<NameValuePair> sortProperties(Iterable<NameValuePair> properties) {
+ var sortedProperties = properties.toList();
+
+ sortedProperties.sort((a, b) {
+ var aPrivate = a.name.startsWith('_');
+ var bPrivate = b.name.startsWith('_');
+ if (aPrivate != bPrivate) return aPrivate ? 1 : -1;
+ return a.name.compareTo(b.name);
+ });
+ return sortedProperties;
+}
+
+String getObjectTypeName(object) {
+ var reifiedType = dart.getReifiedType(object);
+ if (reifiedType == null) {
+ if (_typeof(object) == 'function') {
+ return '[[Raw JavaScript Function]]';
+ }
+ return '<Error getting type name>';
+ }
+ return getTypeName(reifiedType);
+}
+
+String getTypeName(type) {
+ // TODO(jacobr): it would be nice if there was a way we could distinguish
+ // between a List<dynamic> created from Dart and an Array passed in from
+ // JavaScript.
+ return dart.typeName(type);
+}
+
+String safePreview(object, config) {
+ try {
+ var preview = _devtoolsFormatter._simpleFormatter.preview(object, config);
+ if (preview != null) return preview;
+ return object.toString();
+ } catch (e) {
+ return '<Exception thrown> $e';
+ }
+}
+
+String symbolName(symbol) {
+ var name = symbol.toString();
+ assert(name.startsWith('Symbol('));
+ return name.substring('Symbol('.length, name.length - 1);
+}
+
+bool hasMethod(object, String name) {
+ try {
+ return dart.hasMethod(object, name);
+ } catch (e) {
+ return false;
+ }
+}
+
+/// [JsonMLFormatter] consumes [NameValuePair] objects and
+class NameValuePair {
+ NameValuePair(
+ {this.name,
+ this.value,
+ this.config = JsonMLConfig.none,
+ this.hideName = false});
+
+ // Define equality and hashCode so that NameValuePair can be used
+ // in a Set to dedupe entries with duplicate names.
+ bool operator ==(other) {
+ if (other is! NameValuePair) return false;
+ if (this.hideName || other.hideName) return identical(this, other);
+ return other.name == name;
+ }
+
+ int get hashCode => name.hashCode;
+
+ final String name;
+ final Object value;
+ final JsonMLConfig config;
+ final bool hideName;
+
+ String get displayName => hideName ? '' : name;
+}
+
+class MapEntry {
+ MapEntry({this.key, this.value});
+
+ final Object key;
+ final Object value;
+}
+
+class IterableSpan {
+ IterableSpan(this.start, this.end, this.iterable);
+
+ final int start;
+ final int end;
+ final Iterable iterable;
+ int get length => end - start;
+
+ /// Using length - .5, a list of length 10000 results in a
+ /// maxPowerOfSubsetSize of 1, so the list will be broken up into 100,
+ /// 100-length subsets. A list of length 10001 results in a
+ /// maxPowerOfSubsetSize of 2, so the list will be broken up into 1
+ /// 10000-length subset and 1 1-length subset.
+ int get maxPowerOfSubsetSize =>
+ (log(length - .5) / log(_maxSpanLength)).truncate();
+ int get subsetSize => pow(_maxSpanLength, maxPowerOfSubsetSize);
+
+ Map<int, dynamic> asMap() =>
+ iterable.skip(start).take(length).toList().asMap();
+
+ List<NameValuePair> children() {
+ var children = <NameValuePair>[];
+ if (length <= _maxSpanLength) {
+ asMap().forEach((i, element) {
+ children
+ .add(NameValuePair(name: (i + start).toString(), value: element));
+ });
+ } else {
+ for (var i = start; i < end; i += subsetSize) {
+ var subSpan = IterableSpan(i, min(end, subsetSize + i), iterable);
+ if (subSpan.length == 1) {
+ children.add(
+ NameValuePair(name: i.toString(), value: iterable.elementAt(i)));
+ } else {
+ children.add(NameValuePair(
+ name: '[${i}...${subSpan.end - 1}]',
+ value: subSpan,
+ hideName: true));
+ }
+ }
+ }
+ return children;
+ }
+}
+
+class Library {
+ Library(this.name, this.object);
+
+ final String name;
+ final Object object;
+}
+
+class NamedConstructor {
+ NamedConstructor(this.object);
+
+ final Object object;
+}
+
+class HeritageClause {
+ HeritageClause(this.name, this.types);
+
+ final String name;
+ final List types;
+}
+
+Object safeGetProperty(Object protoChain, Object name) {
+ try {
+ return JSNative.getProperty(protoChain, name);
+ } catch (e) {
+ return '<Exception thrown> $e';
+ }
+}
+
+safeProperties(object) => Map.fromIterable(
+ getOwnPropertyNames(object)
+ .where((each) => safeGetProperty(object, each) != null),
+ key: (name) => name,
+ value: (name) => safeGetProperty(object, name));
+
+/// Class to simplify building the JsonML objects expected by the
+/// Devtools Formatter API.
+class JsonMLElement {
+ dynamic _attributes;
+ List _jsonML;
+
+ JsonMLElement(tagName) {
+ _attributes = JS('', '{}');
+ _jsonML = [tagName, _attributes];
+ }
+
+ appendChild(element) {
+ _jsonML.add(element.toJsonML());
+ }
+
+ JsonMLElement createChild(String tagName) {
+ var c = JsonMLElement(tagName);
+ _jsonML.add(c.toJsonML());
+ return c;
+ }
+
+ JsonMLElement createObjectTag(object) =>
+ createChild('object')..addAttribute('object', object);
+
+ void setStyle(String style) {
+ _attributes.style = style;
+ }
+
+ addStyle(String style) {
+ if (_attributes.style == null) {
+ _attributes.style = style;
+ } else {
+ _attributes.style += style;
+ }
+ }
+
+ addAttribute(key, value) {
+ JSNative.setProperty(_attributes, key, value);
+ }
+
+ createTextChild(String text) {
+ _jsonML.add(text);
+ }
+
+ toJsonML() => _jsonML;
+}
+
+/// Whether an object is a native JavaScript type where we should display the
+/// JavaScript view of the object instead of the custom Dart specific render
+/// of properties.
+bool isNativeJavaScriptObject(object) {
+ var type = _typeof(object);
+ if (type != 'object' && type != 'function') return true;
+
+ // Consider all regular JS objects that do not represent Dart modules native
+ // JavaScript objects.
+ if (dart.isJsInterop(object) && dart.getModuleName(object) == null) {
+ return true;
+ }
+
+ // Treat Node objects as a native JavaScript type as the regular DOM render
+ // in devtools is superior to the dart specific view.
+ return object is html.Node;
+}
+
+/// Class implementing the Devtools Formatter API described by:
+/// https://docs.google.com/document/d/1FTascZXT9cxfetuPRT2eXPQKXui4nWFivUnS_335T3U
+/// Specifically, a formatter implements a header, hasBody, and body method.
+/// This class renders the simple structured format objects [_simpleFormatter]
+/// provides as JsonML.
+class JsonMLFormatter {
+ // TODO(jacobr): define a SimpleFormatter base class that DartFormatter
+ // implements if we decide to use this class elsewhere. We specify that the
+ // type is DartFormatter here purely to get type checking benefits not because
+ // this class is really intended to only support instances of type
+ // DartFormatter.
+ DartFormatter _simpleFormatter;
+
+ bool customFormattersOn = false;
+
+ JsonMLFormatter(this._simpleFormatter);
+
+ void setMaxSpanLengthForTestingOnly(int spanLength) {
+ _maxSpanLength = spanLength;
+ }
+
+ header(object, config) {
+ customFormattersOn = true;
+ if (config == JsonMLConfig.skipDart || isNativeJavaScriptObject(object)) {
+ return null;
+ }
+ var c = _simpleFormatter.preview(object, config);
+ if (c == null) return null;
+
+ if (config == JsonMLConfig.keyToString) {
+ c = object.toString();
+ }
+
+ // Indicate this is a Dart Object by using a Dart background color.
+ // This is stylistically a bit ugly but it eases distinguishing Dart and
+ // JS objects.
+ var element = JsonMLElement('span')
+ ..setStyle('background-color: #d9edf7;color: black')
+ ..createTextChild(c);
+ return element.toJsonML();
+ }
+
+ bool hasBody(object, config) => _simpleFormatter.hasChildren(object, config);
+
+ body(object, config) {
+ var body = JsonMLElement('ol')
+ ..setStyle('list-style-type: none;'
+ 'padding-left: 0px;'
+ 'margin-top: 0px;'
+ 'margin-bottom: 0px;'
+ 'margin-left: 12px;');
+ if (object is StackTrace) {
+ body.addStyle('background-color: thistle;color: rgb(196, 26, 22);');
+ }
+ var children = _simpleFormatter.children(object, config);
+ if (children == null) return body.toJsonML();
+ for (NameValuePair child in children) {
+ var li = body.createChild('li');
+ li.setStyle("padding-left: 13px;");
+
+ // The value is indented when it is on a different line from the name
+ // by setting right padding of the name to -13px and the padding of the
+ // value to 13px.
+ JsonMLElement nameSpan;
+ var valueStyle = '';
+ if (!child.hideName) {
+ nameSpan = JsonMLElement('span')
+ ..createTextChild(
+ child.displayName.isNotEmpty ? '${child.displayName}: ' : '')
+ ..setStyle(
+ 'background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px');
+ valueStyle = 'margin-left: 13px';
+ }
+
+ if (_typeof(child.value) == 'object' ||
+ _typeof(child.value) == 'function') {
+ var valueSpan = JsonMLElement('span')..setStyle(valueStyle);
+ valueSpan.createObjectTag(child.value)
+ ..addAttribute('config', child.config);
+ if (nameSpan != null) {
+ li.appendChild(nameSpan);
+ }
+ li.appendChild(valueSpan);
+ } else {
+ var line = li.createChild('span');
+ if (nameSpan != null) {
+ line.appendChild(nameSpan);
+ }
+ line.appendChild(JsonMLElement('span')
+ ..createTextChild(safePreview(child.value, child.config))
+ ..setStyle(valueStyle));
+ }
+ }
+ return body.toJsonML();
+ }
+}
+
+abstract class Formatter {
+ bool accept(object, config);
+ String preview(object);
+ bool hasChildren(object);
+ List<NameValuePair> children(object);
+}
+
+class DartFormatter {
+ List<Formatter> _formatters;
+
+ DartFormatter() {
+ // The order of formatters matters as formatters earlier in the list take
+ // precedence.
+ _formatters = [
+ ObjectInternalsFormatter(),
+ ClassFormatter(),
+ TypeFormatter(),
+ NamedConstructorFormatter(),
+ MapFormatter(),
+ MapOverviewFormatter(),
+ IterableFormatter(),
+ IterableSpanFormatter(),
+ MapEntryFormatter(),
+ StackTraceFormatter(),
+ ErrorAndExceptionFormatter(),
+ FunctionFormatter(),
+ HeritageClauseFormatter(),
+ LibraryModuleFormatter(),
+ LibraryFormatter(),
+ ObjectFormatter(),
+ ];
+ }
+
+ String preview(object, config) {
+ try {
+ if (object == null ||
+ object is num ||
+ object is String ||
+ isNativeJavaScriptObject(object)) {
+ return object.toString();
+ }
+ for (var formatter in _formatters) {
+ if (formatter.accept(object, config)) return formatter.preview(object);
+ }
+ } catch (e, trace) {
+ // Log formatter internal errors as unfortunately the devtools cannot
+ // be used to debug formatter errors.
+ html.window.console.error("Caught exception $e\n trace:\n$trace");
+ }
+
+ return null;
+ }
+
+ bool hasChildren(object, config) {
+ if (object == null) return false;
+ try {
+ for (var formatter in _formatters) {
+ if (formatter.accept(object, config))
+ return formatter.hasChildren(object);
+ }
+ } catch (e, trace) {
+ // See comment for preview.
+ html.window.console
+ .error("[hasChildren] Caught exception $e\n trace:\n$trace");
+ }
+ return false;
+ }
+
+ List<NameValuePair> children(object, config) {
+ try {
+ if (object != null) {
+ for (var formatter in _formatters) {
+ if (formatter.accept(object, config))
+ return formatter.children(object);
+ }
+ }
+ } catch (e, trace) {
+ // See comment for preview.
+ html.window.console.error("Caught exception $e\n trace:\n$trace");
+ }
+ return <NameValuePair>[];
+ }
+}
+
+/// Default formatter for Dart Objects.
+class ObjectFormatter extends Formatter {
+ bool accept(object, config) => !isNativeJavaScriptObject(object);
+
+ String preview(object) {
+ var typeName = getObjectTypeName(object);
+ try {
+ // An explicit toString() call might not actually be a string. This way
+ // we're sure.
+ var toString = "$object";
+ if (toString.length > maxFormatterStringLength) {
+ toString = toString.substring(0, maxFormatterStringLength - 3) + "...";
+ }
+ // The default toString() will be "Instance of 'Foo'", in which case we
+ // don't need any further indication of the class.
+ if (toString.contains(typeName)) {
+ return toString;
+ } else {
+ // If there's no class indication, e.g. an Int64 that just prints as a
+ // number, then add the class name.
+ return "$toString ($typeName)";
+ }
+ } catch (e) {}
+ // We will only get here if there was an error getting the toString, in
+ // which case we just use the type name.
+ return typeName;
+ }
+
+ bool hasChildren(object) => true;
+
+ List<NameValuePair> children(object) {
+ var type = dart.getType(object);
+ var ret = LinkedHashSet<NameValuePair>();
+ // We use a Set rather than a List to avoid duplicates.
+ var fields = Set<NameValuePair>();
+ addPropertiesFromSignature(dart.getFields(type), fields, object, true);
+ var getters = Set<NameValuePair>();
+ addPropertiesFromSignature(dart.getGetters(type), getters, object, true);
+ ret.addAll(sortProperties(fields));
+ ret.addAll(sortProperties(getters));
+ addMetadataChildren(object, ret);
+ return ret.toList();
+ }
+}
+
+/// Show the object instance members and a reduced preview.
+///
+/// Used as a sub-entry to show the internals of objects that have a different
+/// primary format. For example, a Map shows the key-value pairs, but this makes
+/// the internals of the map visible for debugging.
+class ObjectInternalsFormatter extends ObjectFormatter {
+ bool accept(object, config) =>
+ super.accept(object, config) && config == JsonMLConfig.asObject;
+
+ // A minimal preview because we expect a full preview is already shown in a
+ // parent formatter.
+ String preview(object) {
+ return getObjectTypeName(object);
+ }
+}
+
+/// Formatter for module Dart Library objects.
+class LibraryModuleFormatter implements Formatter {
+ accept(object, config) => dart.getModuleName(object) != null;
+
+ bool hasChildren(object) => true;
+
+ String preview(object) {
+ var libraryNames = dart.getModuleName(object).split('/');
+ // Library names are received with a repeat directory name, so strip the
+ // last directory entry here to make the path cleaner. For example, the
+ // library "third_party/dart/utf/utf" shoud display as
+ // "third_party/dart/utf/".
+ if (libraryNames.length > 1 &&
+ libraryNames.last == libraryNames[libraryNames.length - 2]) {
+ libraryNames[libraryNames.length - 1] = '';
+ }
+ return 'Library Module: ${libraryNames.join('/')}';
+ }
+
+ List<NameValuePair> children(object) {
+ var children = LinkedHashSet<NameValuePair>();
+ for (var name in getOwnPropertyNames(object)) {
+ var value = safeGetProperty(object, name);
+ children.add(NameValuePair(
+ name: name, value: Library(name, value), hideName: true));
+ }
+ return children.toList();
+ }
+}
+
+class LibraryFormatter implements Formatter {
+ var genericParameters = HashMap<String, String>();
+
+ accept(object, config) => object is Library;
+
+ bool hasChildren(object) => true;
+
+ String preview(object) => object.name;
+
+ List<NameValuePair> children(object) {
+ // Maintain library member order rather than sorting members as is the
+ // case for class members.
+ var children = LinkedHashSet<NameValuePair>();
+ var objectProperties = safeProperties(object.object);
+ objectProperties.forEach((name, value) {
+ // Skip the generic constructors for each class as users are only
+ // interested in seeing the actual classes.
+ if (dart.getGenericTypeCtor(value) != null) return;
+
+ children.add(dart.isType(value)
+ ? classChild(name, value)
+ : NameValuePair(name: name, value: value));
+ });
+ return children.toList();
+ }
+
+ classChild(String name, Object child) {
+ var typeName = getTypeName(child);
+ return NameValuePair(
+ name: typeName, value: child, config: JsonMLConfig.asClass);
+ }
+}
+
+/// Formatter for Dart Function objects.
+/// Dart functions happen to be regular JavaScript Function objects but
+/// we can distinguish them based on whether they have been tagged with
+/// runtime type information.
+class FunctionFormatter implements Formatter {
+ accept(object, config) {
+ if (_typeof(object) != 'function') return false;
+ return dart.getReifiedType(object) != null;
+ }
+
+ bool hasChildren(object) => true;
+
+ String preview(object) {
+ // The debugger can createa a preview of a FunctionType while it's being
+ // constructed (before argument types exist), so we need to catch errors.
+ try {
+ return dart.typeName(dart.getReifiedType(object));
+ } catch (e) {
+ return safePreview(object, JsonMLConfig.none);
+ }
+ }
+
+ List<NameValuePair> children(object) => <NameValuePair>[
+ NameValuePair(name: 'signature', value: preview(object)),
+ NameValuePair(
+ name: 'JavaScript Function',
+ value: object,
+ config: JsonMLConfig.skipDart)
+ ];
+}
+
+/// Formatter for Objects that implement Map but are not system Maps.
+///
+/// This shows two sub-views, one for instance fields and one for
+/// Map key/value pairs.
+class MapOverviewFormatter implements Formatter {
+ // Because this comes after MapFormatter in the list, internal
+ // maps will be picked up by that formatter.
+ accept(object, config) => object is Map;
+
+ bool hasChildren(object) => true;
+
+ String preview(object) {
+ Map map = object;
+ try {
+ return '${getObjectTypeName(map)}';
+ } catch (e) {
+ return safePreview(object, JsonMLConfig.none);
+ }
+ }
+
+ List<NameValuePair> children(object) => [
+ NameValuePair(
+ name: "[[instance view]]",
+ value: object,
+ config: JsonMLConfig.asObject),
+ NameValuePair(
+ name: "[[entries]]", value: object, config: JsonMLConfig.asMap)
+ ];
+}
+
+/// Formatter for Dart Map objects.
+///
+/// This is only used for internal maps, or when shown as [[entries]]
+/// from MapOverViewFormatter.
+class MapFormatter implements Formatter {
+ accept(object, config) =>
+ object is InternalMap || config == JsonMLConfig.asMap;
+
+ bool hasChildren(object) => true;
+
+ String preview(object) {
+ Map map = object;
+ try {
+ return '${getObjectTypeName(map)} length ${map.length}';
+ } catch (e) {
+ return safePreview(object, JsonMLConfig.none);
+ }
+ }
+
+ List<NameValuePair> children(object) {
+ // TODO(jacobr): be lazier about enumerating contents of Maps that are not
+ // the build in LinkedHashMap class.
+ // TODO(jacobr): handle large Maps better.
+ Map map = object;
+ var entries = LinkedHashSet<NameValuePair>();
+ map.forEach((key, value) {
+ var entryWrapper = MapEntry(key: key, value: value);
+ entries.add(
+ NameValuePair(name: entries.length.toString(), value: entryWrapper));
+ });
+ addMetadataChildren(object, entries);
+ return entries.toList();
+ }
+}
+
+/// Formatter for Dart Iterable objects including List and Set.
+class IterableFormatter implements Formatter {
+ bool accept(object, config) => object is Iterable;
+
+ String preview(object) {
+ Iterable iterable = object;
+ try {
+ var length = iterable.length;
+ return '${getObjectTypeName(iterable)} length $length';
+ } catch (_) {
+ return '${getObjectTypeName(iterable)}';
+ }
+ }
+
+ bool hasChildren(object) => true;
+
+ List<NameValuePair> children(object) {
+ // TODO(jacobr): be lazier about enumerating contents of Iterables that
+ // are not the built in Set or List types.
+ // TODO(jacobr): handle large Iterables better.
+ // TODO(jacobr): consider only using numeric indices
+ var children = LinkedHashSet<NameValuePair>();
+ children.addAll(IterableSpan(0, object.length, object).children());
+ // TODO(jacobr): provide a link to show regular class properties here.
+ // required for subclasses of iterable, etc.
+ addMetadataChildren(object, children);
+ return children.toList();
+ }
+}
+
+class NamedConstructorFormatter implements Formatter {
+ accept(object, config) => object is NamedConstructor;
+
+ // TODO(bmilligan): Display the signature of the named constructor as the
+ // preview.
+ String preview(object) => 'Named Constructor';
+
+ bool hasChildren(object) => true;
+
+ List<NameValuePair> children(object) => <NameValuePair>[
+ NameValuePair(
+ name: 'JavaScript Function',
+ value: object,
+ config: JsonMLConfig.skipDart)
+ ];
+}
+
+/// Formatter for synthetic MapEntry objects used to display contents of a Map
+/// cleanly.
+class MapEntryFormatter implements Formatter {
+ accept(object, config) => object is MapEntry;
+
+ String preview(object) {
+ MapEntry entry = object;
+ return '${safePreview(entry.key, JsonMLConfig.none)} => ${safePreview(entry.value, JsonMLConfig.none)}';
+ }
+
+ bool hasChildren(object) => true;
+
+ List<NameValuePair> children(object) => <NameValuePair>[
+ NameValuePair(
+ name: 'key', value: object.key, config: JsonMLConfig.keyToString),
+ NameValuePair(name: 'value', value: object.value)
+ ];
+}
+
+/// Formatter for Dart Iterable objects including List and Set.
+class HeritageClauseFormatter implements Formatter {
+ bool accept(object, config) => object is HeritageClause;
+
+ String preview(object) {
+ HeritageClause clause = object;
+ var typeNames = clause.types.map(getTypeName);
+ return '${clause.name} ${typeNames.join(", ")}';
+ }
+
+ bool hasChildren(object) => true;
+
+ List<NameValuePair> children(object) {
+ HeritageClause clause = object;
+ var children = <NameValuePair>[];
+ for (var type in clause.types) {
+ children.add(NameValuePair(value: type, config: JsonMLConfig.asClass));
+ }
+ return children;
+ }
+}
+
+/// Formatter for synthetic IterableSpan objects used to display contents of
+/// an Iterable cleanly.
+class IterableSpanFormatter implements Formatter {
+ accept(object, config) => object is IterableSpan;
+
+ String preview(object) {
+ return '[${object.start}...${object.end - 1}]';
+ }
+
+ bool hasChildren(object) => true;
+
+ List<NameValuePair> children(object) => object.children();
+}
+
+/// Formatter for Dart Errors and Exceptions.
+class ErrorAndExceptionFormatter extends ObjectFormatter {
+ static final RegExp _pattern = RegExp(r'\d+\:\d+');
+
+ accept(object, config) => object is Error || object is Exception;
+
+ bool hasChildren(object) => true;
+
+ String preview(object) {
+ var trace = dart.stackTrace(object);
+ // TODO(vsm): Pull our stack mapping logic here. We should aim to
+ // provide the first meaningful stack frame.
+ var line = '$trace'.split('\n').firstWhere(
+ (l) =>
+ l.contains(_pattern) &&
+ !l.contains('dart:sdk') &&
+ !l.contains('dart_sdk'),
+ orElse: () => null);
+ return line != null ? '${object} at ${line}' : '${object}';
+ }
+
+ List<NameValuePair> children(object) {
+ var trace = dart.stackTrace(object);
+ var entries = LinkedHashSet<NameValuePair>();
+ entries.add(NameValuePair(name: 'stackTrace', value: trace));
+ addInstanceMembers(object, entries);
+ addMetadataChildren(object, entries);
+ return entries.toList();
+ }
+
+ // Add an ObjectFormatter view underneath.
+ void addInstanceMembers(object, Set<NameValuePair> ret) {
+ ret.add(NameValuePair(
+ name: "[[instance members]]",
+ value: object,
+ config: JsonMLConfig.asObject));
+ }
+}
+
+class StackTraceFormatter implements Formatter {
+ accept(object, config) => object is StackTrace;
+
+ String preview(object) => 'StackTrace';
+
+ bool hasChildren(object) => true;
+
+ // Using the stack_trace formatting would be ideal, but adding the
+ // dependency or re-writing the code is too messy, so each line of the
+ // StackTrace will be added as its own child.
+ List<NameValuePair> children(object) => object
+ .toString()
+ .split('\n')
+ .map((line) => NameValuePair(
+ value: line.replaceFirst(RegExp(r'^\s+at\s'), ''), hideName: true))
+ .toList();
+}
+
+class ClassFormatter implements Formatter {
+ accept(object, config) => config == JsonMLConfig.asClass;
+
+ String preview(type) {
+ var implements = dart.getImplements(type);
+ var typeName = getTypeName(type);
+ if (implements != null) {
+ var typeNames = implements().map(getTypeName);
+ return '${typeName} implements ${typeNames.join(", ")}';
+ } else {
+ return typeName;
+ }
+ }
+
+ bool hasChildren(object) => true;
+
+ List<NameValuePair> children(type) {
+ // TODO(jacobr): add other entries describing the class such as
+ // implemented interfaces, and methods.
+ var ret = LinkedHashSet<NameValuePair>();
+
+ var staticProperties = Set<NameValuePair>();
+ var staticMethods = Set<NameValuePair>();
+ // Static fields and properties.
+ addPropertiesFromSignature(
+ dart.getStaticFields(type), staticProperties, type, false);
+ addPropertiesFromSignature(
+ dart.getStaticGetters(type), staticProperties, type, false);
+ // static methods.
+ addPropertiesFromSignature(
+ dart.getStaticMethods(type), staticMethods, type, false);
+
+ if (staticProperties.isNotEmpty || staticMethods.isNotEmpty) {
+ ret
+ ..add(NameValuePair(value: '[[Static members]]', hideName: true))
+ ..addAll(sortProperties(staticProperties))
+ ..addAll(sortProperties(staticMethods));
+ }
+
+ // instance methods.
+ var instanceMethods = Set<NameValuePair>();
+ // Instance methods are defined on the prototype not the constructor object.
+ addPropertiesFromSignature(dart.getMethods(type), instanceMethods,
+ JS('', '#.prototype', type), false,
+ tagTypes: true);
+ if (instanceMethods.isNotEmpty) {
+ ret
+ ..add(NameValuePair(value: '[[Instance Methods]]', hideName: true))
+ ..addAll(sortProperties(instanceMethods));
+ }
+
+ var mixin = dart.getMixin(type);
+ if (mixin != null) {
+ // TODO(jmesserly): this can only be one value.
+ ret.add(NameValuePair(
+ name: '[[Mixins]]', value: HeritageClause('mixins', [mixin])));
+ }
+
+ var baseProto = JS('', '#.__proto__', type);
+ if (baseProto != null && !dart.isJsInterop(baseProto)) {
+ ret.add(NameValuePair(
+ name: "[[base class]]",
+ value: baseProto,
+ config: JsonMLConfig.asClass));
+ }
+
+ // TODO(jacobr): add back fields for named constructors.
+ return ret.toList();
+ }
+}
+
+class TypeFormatter implements Formatter {
+ accept(object, config) => object is Type;
+
+ String preview(object) => object.toString();
+
+ bool hasChildren(object) => false;
+
+ List<NameValuePair> children(object) => [];
+}
+
+typedef String StackTraceMapper(String stackTrace);
+
+/// Hook for other parts of the SDK To use to map JS stack traces to Dart
+/// stack traces.
+///
+/// Raw JS stack traces are used if $dartStackTraceUtility has not been
+/// specified.
+StackTraceMapper get stackTraceMapper {
+ var _util = JS('', r'#.$dartStackTraceUtility', dart.global_);
+ return _util != null ? JS('!', '#.mapper', _util) : null;
+}
+
+/// This entry point is automatically invoked by the code generated by
+/// Dart Dev Compiler
+registerDevtoolsFormatter() {
+ JS('', '#.devtoolsFormatters = [#]', dart.global_, _devtoolsFormatter);
+}
+
+// These methods are exposed here for debugger tests.
+//
+// TODO(jmesserly): these are not exports because there is existing code that
+// calls into them from JS. Currently `dartdevc` always resolves exports at
+// compile time, so there is no need to make exports available at runtime by
+// copying properties. For that reason we cannot use re-export.
+//
+// If these methods are only for tests, we should move them here, or change the
+// tests to call the methods directly on dart:_runtime.
+List<String> getModuleNames() => dart.getModuleNames();
+getModuleLibraries(String name) => dart.getModuleLibraries(name);
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart
new file mode 100644
index 0000000..588d789
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart
@@ -0,0 +1,285 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._foreign_helper;
+
+/**
+ * Emits a JavaScript code fragment parameterized by arguments.
+ *
+ * Hash characters `#` in the [codeTemplate] are replaced in left-to-right order
+ * with expressions that contain the values of, or evaluate to, the arguments.
+ * The number of hash marks must match the number or arguments. Although
+ * declared with arguments [arg0] through [arg2], the form actually has no limit
+ * on the number of arguments.
+ *
+ * The [typeDescription] argument is interpreted as a description of the
+ * behavior of the JavaScript code. Currently it describes the types that may
+ * be returned by the expression, with the additional behavior that the returned
+ * values may be fresh instances of the types. The type information must be
+ * correct as it is trusted by the compiler in optimizations, and it must be
+ * precise as possible since it is used for native live type analysis to
+ * tree-shake large parts of the DOM libraries. If poorly written, the
+ * [typeDescription] will cause unnecessarily bloated programs. (You can check
+ * for this by compiling with `--verbose`; there is an info message describing
+ * the number of native (DOM) types that can be removed, which usually should be
+ * greater than zero.)
+ *
+ * The [typeDescription] is a [String] which contains a union of types separated
+ * by vertical bar `|` symbols, e.g. `"num|String"` describes the union of
+ * numbers and Strings. There is no type in Dart that is this precise. The
+ * Dart alternative would be `Object` or `dynamic`, but these types imply that
+ * the JS-code might also be creating instances of all the DOM types. If `null`
+ * is possible, it must be specified explicitly, e.g. `"String|Null"`.
+ * [typeDescription] has several extensions to help describe the behavior more
+ * accurately. In addition to the union type already described:
+ *
+ * + `=Object` is a plain JavaScript object. Some DOM methods return instances
+ * that have no corresponding Dart type (e.g. cross-frame documents),
+ * `=Object` can be used to describe these untyped' values.
+ *
+ * + `var` (or empty string). If the entire [typeDescription] is `var` (or
+ * empty string) then the type is `dynamic` but the code is known to not
+ * create any instances.
+ *
+ * Examples:
+ *
+ * // Parent window might be an opaque cross-frame window.
+ * var thing = JS('=Object|Window', '#.parent', myWindow);
+ *
+ * Guidelines:
+ *
+ * + Do not use any parameter, local, method or field names in the
+ * [codeTemplate]. These names are all subject to arbitrary renaming by the
+ * compiler. Pass the values in via `#` substition, and test with the
+ * `--minify` dart2js command-line option.
+ *
+ * + The substituted expressions are values, not locations.
+ *
+ * JS('void', '# += "x"', this.field);
+ *
+ * `this.field` might not be a substituted as a reference to the field. The
+ * generated code might accidentally work as intended, but it also might be
+ *
+ * var t1 = this.field;
+ * t1 += "x";
+ *
+ * or
+ *
+ * this.get$field() += "x";
+ *
+ * The remedy in this case is to expand the `+=` operator, leaving all
+ * references to the Dart field as Dart code:
+ *
+ * this.field = JS<String>('!', '# + "x"', this.field);
+ *
+ * + Never use `#` in function bodies.
+ *
+ * This is a variation on the previous guideline. Since `#` is replaced with
+ * an *expression* and the expression is only valid in the immediate context,
+ * `#` should never appear in a function body. Doing so might defer the
+ * evaluation of the expression, and its side effects, until the function is
+ * called.
+ *
+ * For example,
+ *
+ * var value = foo();
+ * var f = JS('', 'function(){return #}', value)
+ *
+ * might result in no immediate call to `foo` and a call to `foo` on every
+ * call to the JavaScript function bound to `f`. This is better:
+ *
+ * var f = JS('',
+ * '(function(val) { return function(){return val}; })(#)', value);
+ *
+ * Since `#` occurs in the immediately evaluated expression, the expression
+ * is immediately evaluated and bound to `val` in the immediate call.
+ *
+ *
+ * Additional notes.
+ *
+ * In the future we may extend [typeDescription] to include other aspects of the
+ * behavior, for example, separating the returned types from the instantiated
+ * types, or including effects to allow the compiler to perform more
+ * optimizations around the code. This might be an extension of [JS] or a new
+ * function similar to [JS] with additional arguments for the new information.
+ */
+// Add additional optional arguments if needed. The method is treated internally
+// as a variable argument method.
+T JS<T extends Object>(String typeDescription, String codeTemplate,
+ [arg0,
+ arg1,
+ arg2,
+ arg3,
+ arg4,
+ arg5,
+ arg6,
+ arg7,
+ arg8,
+ arg9,
+ arg10,
+ arg11,
+ arg12,
+ arg13,
+ arg14,
+ arg15,
+ arg16,
+ arg17,
+ arg18,
+ arg19]) {}
+
+/// Annotates the compiled Js name for fields and methods.
+/// Similar behaviour to `JS` from `package:js/js.dart` (but usable from runtime
+/// files), and not to be confused with `JSName` from `js_helper` (which deals
+/// with names of externs).
+// TODO(jmesserly): remove this in favor of js_helper's `@JSName`
+// (Currently they have slightly different semantics, but they can be unified.)
+class JSExportName {
+ final String name;
+ const JSExportName(this.name);
+}
+
+/**
+ * Returns the JavaScript constructor function for Dart's Object class.
+ * This can be used for type tests, as in
+ *
+ * if (JS<bool>('!', '# instanceof #', obj, JS_DART_OBJECT_CONSTRUCTOR()))
+ * ...
+ */
+JS_DART_OBJECT_CONSTRUCTOR() {}
+
+/**
+ * Returns the interceptor for class [type]. The interceptor is the type's
+ * constructor's `prototype` property. [type] will typically be the class, not
+ * an interface, e.g. `JS_INTERCEPTOR_CONSTANT(JSInt)`, not
+ * `JS_INTERCEPTOR_CONSTANT(int)`.
+ */
+JS_INTERCEPTOR_CONSTANT(Type type) {}
+
+/**
+ * Returns the prefix used for generated is checks on classes.
+ */
+String JS_OPERATOR_IS_PREFIX() {}
+
+/**
+ * Returns the prefix used for generated type argument substitutions on classes.
+ */
+String JS_OPERATOR_AS_PREFIX() {}
+
+/// Returns the name of the class `Object` in the generated code.
+String JS_OBJECT_CLASS_NAME() {}
+
+/// Returns the name of the class `Null` in the generated code.
+String JS_NULL_CLASS_NAME() {}
+
+/// Returns the name of the class `Function` in the generated code.
+String JS_FUNCTION_CLASS_NAME() {}
+
+/**
+ * Returns the field name used for determining if an object or its
+ * interceptor has JavaScript indexing behavior.
+ */
+String JS_IS_INDEXABLE_FIELD_NAME() {}
+
+/// Returns the name used for generated function types on classes and methods.
+String JS_SIGNATURE_NAME() {}
+
+/// Returns the name used to tag typedefs.
+String JS_TYPEDEF_TAG() {}
+
+/// Returns the name used to tag function type representations in JavaScript.
+String JS_FUNCTION_TYPE_TAG() {}
+
+/**
+ * Returns the name used to tag void return in function type representations
+ * in JavaScript.
+ */
+String JS_FUNCTION_TYPE_VOID_RETURN_TAG() {}
+
+/**
+ * Returns the name used to tag return types in function type representations
+ * in JavaScript.
+ */
+String JS_FUNCTION_TYPE_RETURN_TYPE_TAG() {}
+
+/**
+ * Returns the name used to tag required parameters in function type
+ * representations in JavaScript.
+ */
+String JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG() {}
+
+/**
+ * Returns the name used to tag optional parameters in function type
+ * representations in JavaScript.
+ */
+String JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG() {}
+
+/**
+ * Returns the name used to tag named parameters in function type
+ * representations in JavaScript.
+ */
+String JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG() {}
+
+/// Returns the JS name for [name] from the Namer.
+String JS_GET_NAME(String name) {}
+
+/// Returns the state of a flag that is determined by the state of the compiler
+/// when the program has been analyzed.
+bool JS_GET_FLAG(String name) {}
+
+/**
+ * Pretend [code] is executed. Generates no executable code. This is used to
+ * model effects at some other point in external code. For example, the
+ * following models an assignment to foo with an unknown value.
+ *
+ * var foo;
+ *
+ * main() {
+ * JS_EFFECT((_){ foo = _; })
+ * }
+ *
+ * TODO(sra): Replace this hack with something to mark the volatile or
+ * externally initialized elements.
+ */
+void JS_EFFECT(Function code) {
+ code(null);
+}
+
+/**
+ * Use this class for creating constants that hold JavaScript code.
+ * For example:
+ *
+ * const constant = JS_CONST('typeof window != "undefined");
+ *
+ * This code will generate:
+ * $.JS_CONST_1 = typeof window != "undefined";
+ */
+class JS_CONST {
+ final String code;
+ const JS_CONST(this.code);
+}
+
+/**
+ * JavaScript string concatenation. Inputs must be Strings. Corresponds to the
+ * HStringConcat SSA instruction and may be constant-folded.
+ */
+String JS_STRING_CONCAT(String a, String b) {
+ // This body is unused, only here for type analysis.
+ return JS<String>('!', '# + #', a, b);
+}
+
+/// Same `@rest` annotation and `spread` function as in
+/// `package:js/src/varargs.dart`.
+///
+/// Runtime files cannot import packages, which is why we have an ad-hoc copy.
+
+class _Rest {
+ const _Rest();
+}
+
+const _Rest rest = _Rest();
+
+dynamic spread(args) {
+ throw StateError('The spread function cannot be called, '
+ 'it should be compiled away.');
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/identity_hash_map.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/identity_hash_map.dart
new file mode 100644
index 0000000..04107cc
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/identity_hash_map.dart
@@ -0,0 +1,137 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._js_helper;
+
+class IdentityMap<K, V> extends InternalMap<K, V> {
+ final _map = JS('', 'new Map()');
+
+ // We track the number of modifications done to the key set of the
+ // hash map to be able to throw when the map is modified while being
+ // iterated over.
+ //
+ // Value cycles after 2^30 modifications so that modification counts are
+ // always unboxed (Smi) values. Modification detection will be missed if you
+ // make exactly some multiple of 2^30 modifications between advances of an
+ // iterator.
+ @notNull
+ int _modifications = 0;
+
+ IdentityMap();
+ IdentityMap.from(JSArray entries) {
+ var map = _map;
+ for (int i = 0, n = JS<int>('!', '#.length', entries); i < n; i += 2) {
+ JS('', '#.set(#[#], #[#])', map, entries, i, entries, i + 1);
+ }
+ }
+
+ int get length => JS<int>('!', '#.size', _map);
+ bool get isEmpty => JS<bool>('!', '#.size == 0', _map);
+ bool get isNotEmpty => JS<bool>('!', '#.size != 0', _map);
+
+ Iterable<K> get keys => _JSMapIterable<K>(this, true);
+ Iterable<V> get values => _JSMapIterable<V>(this, false);
+
+ bool containsKey(Object key) {
+ return JS<bool>('!', '#.has(#)', _map, key);
+ }
+
+ bool containsValue(Object value) {
+ for (var v in JS('', '#.values()', _map)) {
+ if (v == value) return true;
+ }
+ return false;
+ }
+
+ void addAll(Map<K, V> other) {
+ if (other.isNotEmpty) {
+ var map = _map;
+ other.forEach((key, value) {
+ JS('', '#.set(#, #)', map, key, value);
+ });
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ }
+
+ V operator [](Object key) {
+ V value = JS('', '#.get(#)', _map, key);
+ return value == null ? null : value; // coerce undefined to null.
+ }
+
+ void operator []=(K key, V value) {
+ var map = _map;
+ int length = JS('!', '#.size', map);
+ JS('', '#.set(#, #)', map, key, value);
+ if (length != JS<int>('!', '#.size', map)) {
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ }
+
+ V putIfAbsent(K key, V ifAbsent()) {
+ if (JS<bool>('!', '#.has(#)', _map, key)) {
+ return JS('', '#.get(#)', _map, key);
+ }
+ V value = ifAbsent();
+ if (value == null) value = null; // coerce undefined to null.
+ JS('', '#.set(#, #)', _map, key, value);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ return value;
+ }
+
+ V remove(Object key) {
+ V value = JS('', '#.get(#)', _map, key);
+ if (JS<bool>('!', '#.delete(#)', _map, key)) {
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ return value == null ? null : value; // coerce undefined to null.
+ }
+
+ void clear() {
+ if (JS<int>('!', '#.size', _map) > 0) {
+ JS('', '#.clear()', _map);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ }
+}
+
+class _JSMapIterable<E> extends EfficientLengthIterable<E> {
+ final InternalMap _map;
+ @notNull
+ final bool _isKeys;
+ _JSMapIterable(this._map, this._isKeys);
+
+ int get length => _map.length;
+ bool get isEmpty => _map.isEmpty;
+
+ @JSExportName('Symbol.iterator')
+ _jsIterator() {
+ var map = _map;
+ var iterator =
+ JS('', '# ? #.keys() : #.values()', _isKeys, map._map, map._map);
+ int modifications = map._modifications;
+ return JS(
+ '',
+ '''{
+ next() {
+ if (# != #) {
+ throw #;
+ }
+ return #.next();
+ }
+ }''',
+ modifications,
+ map._modifications,
+ ConcurrentModificationError(map),
+ iterator);
+ }
+
+ Iterator<E> get iterator => DartIterator<E>(_jsIterator());
+
+ bool contains(Object element) =>
+ _isKeys ? _map.containsKey(element) : _map.containsValue(element);
+
+ void forEach(void f(E element)) {
+ for (var entry in this) f(entry);
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/interceptors.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/interceptors.dart
new file mode 100644
index 0000000..6ddd96b
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/interceptors.dart
@@ -0,0 +1,233 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._interceptors;
+
+import 'dart:collection';
+import 'dart:_internal' hide Symbol;
+import 'dart:_js_helper';
+import 'dart:_foreign_helper' show JS, JSExportName;
+import 'dart:math' show Random, ln2;
+import 'dart:_runtime' as dart;
+
+part 'js_array.dart';
+part 'js_number.dart';
+part 'js_string.dart';
+
+// TODO(jmesserly): remove, this doesn't do anything for us.
+abstract class Interceptor {
+ const Interceptor();
+
+ // Use native JS toString method instead of standard Dart Object.toString.
+ String toString() => JS<String>('!', '#.toString()', this);
+}
+
+// TODO(jmesserly): remove
+getInterceptor(obj) => obj;
+
+/**
+ * The interceptor class for [bool].
+ */
+@JsPeerInterface(name: 'Boolean')
+class JSBool extends Interceptor implements bool {
+ const JSBool();
+
+ // Note: if you change this, also change the function [S].
+ @notNull
+ String toString() => JS<String>('!', r'String(#)', this);
+
+ // The values here are SMIs, co-prime and differ about half of the bit
+ // positions, including the low bit, so they are different mod 2^k.
+ @notNull
+ int get hashCode => this ? (2 * 3 * 23 * 3761) : (269 * 811);
+
+ @notNull
+ bool operator &(@nullCheck bool other) =>
+ JS<bool>('!', "# && #", other, this);
+
+ @notNull
+ bool operator |(@nullCheck bool other) =>
+ JS<bool>('!', "# || #", other, this);
+
+ @notNull
+ bool operator ^(@nullCheck bool other) => !identical(this, other);
+
+ Type get runtimeType => bool;
+}
+
+/**
+ * The supertype for JSString and JSArray. Used by the backend as to
+ * have a type mask that contains the objects that we can use the
+ * native JS [] operator and length on.
+ */
+abstract class JSIndexable<E> {
+ int get length;
+ E operator [](int index);
+}
+
+/**
+ * The interface implemented by JavaScript objects. These are methods in
+ * addition to the regular Dart Object methods like [Object.hashCode].
+ *
+ * This is the type that should be exported by a JavaScript interop library.
+ */
+abstract class JSObject {}
+
+/**
+ * Interceptor base class for JavaScript objects not recognized as some more
+ * specific native type.
+ */
+abstract class JavaScriptObject extends Interceptor implements JSObject {
+ const JavaScriptObject();
+
+ // It would be impolite to stash a property on the object.
+ int get hashCode => 0;
+
+ Type get runtimeType => JSObject;
+}
+
+/**
+ * Interceptor for plain JavaScript objects created as JavaScript object
+ * literals or `new Object()`.
+ */
+class PlainJavaScriptObject extends JavaScriptObject {
+ const PlainJavaScriptObject();
+}
+
+/**
+ * Interceptor for unclassified JavaScript objects, typically objects with a
+ * non-trivial prototype chain.
+ *
+ * This class also serves as a fallback for unknown JavaScript exceptions.
+ */
+class UnknownJavaScriptObject extends JavaScriptObject {
+ const UnknownJavaScriptObject();
+
+ String toString() => JS<String>('!', 'String(#)', this);
+}
+
+class NativeError extends Interceptor {
+ String dartStack() => JS<String>('!', '#.stack', this);
+}
+
+// Note that this needs to be in interceptors.dart in order for
+// it to be picked up as an extension type.
+@JsPeerInterface(name: 'TypeError')
+class JSNoSuchMethodError extends NativeError implements NoSuchMethodError {
+ static final _nullError = RegExp(r"^Cannot read property '(.+)' of null$");
+ static final _notAFunction = RegExp(r"^(.+) is not a function$");
+ static final _extensionName = RegExp(r"^Symbol\(dartx\.(.+)\)$");
+ static final _privateName = RegExp(r"^Symbol\((_.+)\)$");
+
+ String _fieldName(String message) {
+ var match = _nullError.firstMatch(message);
+ if (match == null) return null;
+ var name = match[1];
+ match = _extensionName.firstMatch(name) ?? _privateName.firstMatch(name);
+ return match != null ? match[1] : name;
+ }
+
+ String _functionCallTarget(String message) {
+ var match = _notAFunction.firstMatch(message);
+ return match != null ? match[1] : null;
+ }
+
+ String dartStack() {
+ var stack = super.dartStack();
+ // Strip TypeError from first line.
+ stack = toString() + '\n' + stack.split('\n').sublist(1).join('\n');
+ return stack;
+ }
+
+ StackTrace get stackTrace => dart.stackTrace(this);
+
+ String toString() {
+ String message = JS('!', '#.message', this);
+ var callTarget = _functionCallTarget(message);
+ if (callTarget != null) {
+ return "NoSuchMethodError: tried to call a non-function, such as null: "
+ "'$callTarget'";
+ }
+ // TODO(vsm): Distinguish between null reference errors and other
+ // TypeErrors. We should not get non-null TypeErrors from DDC code,
+ // but we may from native JavaScript.
+ var name = _fieldName(message);
+ if (name == null) {
+ // Not a Null NSM error: fallback to JS.
+ return JS<String>('!', '#.toString()', this);
+ }
+ return "NoSuchMethodError: invalid member on null: '$name'";
+ }
+}
+
+@JsPeerInterface(name: 'Function')
+class JSFunction extends Interceptor {
+ toString() {
+ // If the function is a Type object, we should just display the type name.
+ //
+ // Regular Dart code should typically get wrapped type objects instead of
+ // raw type (aka JS constructor) objects, however raw type objects can be
+ // exposed to Dart code via JS interop or debugging tools.
+ if (dart.isType(this)) return dart.typeName(this);
+
+ return JS<String>('!', r'"Closure: " + # + " from: " + #',
+ dart.typeName(dart.getReifiedType(this)), this);
+ }
+
+ // TODO(jmesserly): remove these once we canonicalize tearoffs.
+ operator ==(other) {
+ if (other == null) return false;
+ var boundObj = JS<Object>('', '#._boundObject', this);
+ if (boundObj == null) return JS<bool>('!', '# === #', this, other);
+ return JS(
+ 'bool',
+ '# === #._boundObject && #._boundMethod === #._boundMethod',
+ boundObj,
+ other,
+ this,
+ other);
+ }
+
+ get hashCode {
+ var boundObj = JS<Object>('', '#._boundObject', this);
+ if (boundObj == null) return identityHashCode(this);
+
+ var boundMethod = JS<Object>('!', '#._boundMethod', this);
+ int hash = (17 * 31 + boundObj.hashCode) & 0x1fffffff;
+ return (hash * 31 + identityHashCode(boundMethod)) & 0x1fffffff;
+ }
+
+ get runtimeType => dart.wrapType(dart.getReifiedType(this));
+}
+
+/// A class used for implementing `null` tear-offs.
+class JSNull {
+ toString() => 'null';
+ noSuchMethod(Invocation i) => dart.defaultNoSuchMethod(null, i);
+}
+
+final Object jsNull = JSNull();
+
+// Note that this needs to be in interceptors.dart in order for
+// it to be picked up as an extension type.
+@JsPeerInterface(name: 'RangeError')
+class JSRangeError extends Interceptor implements ArgumentError {
+ StackTrace get stackTrace => dart.stackTrace(this);
+
+ get invalidValue => null;
+ get name => null;
+ get message => JS<String>('!', '#.message', this);
+
+ String toString() => "Invalid argument: $message";
+}
+
+// Obsolete in dart dev compiler. Added only so that the same version of
+// dart:html can be used in dart2js an dev compiler.
+// Warning: calls to these methods need to be removed before custom elements
+// and cross-frame dom objects behave correctly in ddc.
+// See https://github.com/dart-lang/sdk/issues/28326
+findInterceptorConstructorForType(Type type) {}
+findConstructorForNativeSubclassType(Type type, String name) {}
+getNativeInterceptor(object) {}
+setDispatchProperty(object, value) {}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/isolate_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/isolate_helper.dart
new file mode 100644
index 0000000..490c4b9
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/isolate_helper.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._isolate_helper;
+
+import 'dart:_runtime' as dart;
+import 'dart:async';
+import 'dart:_foreign_helper' show JS;
+
+/// Deprecated way of initializing `main()` in DDC, typically called from JS.
+@deprecated
+void startRootIsolate(main, args) {
+ if (args == null) args = <String>[];
+ if (args is List) {
+ if (args is! List<String>) args = List<String>.from(args);
+ // DDC attaches signatures only when torn off, and the typical way of
+ // getting `main` via the JS ABI won't do this. So use JS to invoke main.
+ if (JS<bool>('!', 'typeof # == "function"', main)) {
+ // JS will ignore extra arguments.
+ JS('', '#(#, #)', main, args, null);
+ } else {
+ // Not a function. Use a dynamic call to throw an error.
+ (main as dynamic)(args);
+ }
+ } else {
+ throw ArgumentError("Arguments to main must be a List: $args");
+ }
+}
+
+// TODO(vsm): Other libraries import global from here. Consider replacing
+// those uses to just refer to the one in dart:runtime.
+final global = dart.global_;
+
+class TimerImpl implements Timer {
+ final bool _once;
+ int _handle;
+ int _tick = 0;
+
+ TimerImpl(int milliseconds, void callback()) : _once = true {
+ if (hasTimer()) {
+ void internalCallback() {
+ _handle = null;
+ dart.removeAsyncCallback();
+ _tick = 1;
+ callback();
+ }
+
+ dart.addAsyncCallback();
+
+ _handle = JS(
+ 'int', '#.setTimeout(#, #)', global, internalCallback, milliseconds);
+ } else {
+ throw UnsupportedError("`setTimeout()` not found.");
+ }
+ }
+
+ TimerImpl.periodic(int milliseconds, void callback(Timer timer))
+ : _once = false {
+ if (hasTimer()) {
+ dart.addAsyncCallback();
+ int start = JS<int>('!', 'Date.now()');
+ _handle = JS<int>('!', '#.setInterval(#, #)', global, () {
+ int tick = this._tick + 1;
+ if (milliseconds > 0) {
+ int duration = JS<int>('!', 'Date.now()') - start;
+ if (duration > (tick + 1) * milliseconds) {
+ tick = duration ~/ milliseconds;
+ }
+ }
+ this._tick = tick;
+ callback(this);
+ }, milliseconds);
+ } else {
+ throw UnsupportedError("Periodic timer.");
+ }
+ }
+
+ int get tick => _tick;
+
+ void cancel() {
+ if (hasTimer()) {
+ if (_handle == null) return;
+ dart.removeAsyncCallback();
+ if (_once) {
+ JS('void', '#.clearTimeout(#)', global, _handle);
+ } else {
+ JS('void', '#.clearInterval(#)', global, _handle);
+ }
+ _handle = null;
+ } else {
+ throw UnsupportedError("Canceling a timer.");
+ }
+ }
+
+ bool get isActive => _handle != null;
+}
+
+bool hasTimer() {
+ return JS('', '#.setTimeout', global) != null;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_array.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_array.dart
new file mode 100644
index 0000000..f064b24
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_array.dart
@@ -0,0 +1,694 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._interceptors;
+
+/**
+ * The interceptor class for [List]. The compiler recognizes this
+ * class as an interceptor, and changes references to [:this:] to
+ * actually use the receiver of the method, which is generated as an extra
+ * argument added to each member.
+ */
+@JsPeerInterface(name: 'Array')
+class JSArray<E> implements List<E>, JSIndexable<E> {
+ const JSArray();
+
+ /**
+ * Constructor for adding type parameters to an existing JavaScript
+ * Array. Used for creating literal lists.
+ */
+ factory JSArray.of(list) {
+ // TODO(sra): Move this to core.List for better readability.
+ //
+ // TODO(jmesserly): this uses special compiler magic to close over the
+ // parameterized ES6 'JSArray' class.
+ JS('', '#.__proto__ = JSArray.prototype', list);
+ return JS('-dynamic', '#', list);
+ }
+
+ // TODO(jmesserly): consider a fixed array subclass instead.
+ factory JSArray.fixed(list) {
+ JS('', '#.__proto__ = JSArray.prototype', list);
+ JS('', r'#.fixed$length = Array', list);
+ return JS('-dynamic', '#', list);
+ }
+
+ factory JSArray.unmodifiable(list) {
+ JS('', '#.__proto__ = JSArray.prototype', list);
+ JS('', r'#.fixed$length = Array', list);
+ JS('', r'#.immutable$list = Array', list);
+ return JS('-dynamic', '#', list);
+ }
+
+ static void markFixedList(list) {
+ // Functions are stored in the hidden class and not as properties in
+ // the object. We never actually look at the value, but only want
+ // to know if the property exists.
+ JS('', r'#.fixed$length = Array', list);
+ }
+
+ static void markUnmodifiableList(list) {
+ // Functions are stored in the hidden class and not as properties in
+ // the object. We never actually look at the value, but only want
+ // to know if the property exists.
+ JS('', r'#.fixed$length = Array', list);
+ JS('', r'#.immutable$list = Array', list);
+ }
+
+ checkMutable(reason) {
+ if (JS<bool>('!', r'#.immutable$list', this)) {
+ throw UnsupportedError(reason);
+ }
+ }
+
+ checkGrowable(reason) {
+ if (JS<bool>('!', r'#.fixed$length', this)) {
+ throw UnsupportedError(reason);
+ }
+ }
+
+ List<R> cast<R>() => List.castFrom<E, R>(this);
+ void add(E value) {
+ checkGrowable('add');
+ JS('void', r'#.push(#)', this, value);
+ }
+
+ E removeAt(@nullCheck int index) {
+ checkGrowable('removeAt');
+ if (index < 0 || index >= length) {
+ throw RangeError.value(index);
+ }
+ return JS('-dynamic', r'#.splice(#, 1)[0]', this, index);
+ }
+
+ void insert(@nullCheck int index, E value) {
+ checkGrowable('insert');
+ if (index < 0 || index > length) {
+ throw RangeError.value(index);
+ }
+ JS('void', r'#.splice(#, 0, #)', this, index, value);
+ }
+
+ void insertAll(@nullCheck int index, Iterable<E> iterable) {
+ checkGrowable('insertAll');
+ RangeError.checkValueInInterval(index, 0, this.length, "index");
+ if (iterable is! EfficientLengthIterable) {
+ iterable = iterable.toList();
+ }
+ @nullCheck
+ int insertionLength = iterable.length;
+ this.length += insertionLength;
+ int end = index + insertionLength;
+ this.setRange(end, this.length, this, index);
+ this.setRange(index, end, iterable);
+ }
+
+ void setAll(@nullCheck int index, Iterable<E> iterable) {
+ checkMutable('setAll');
+ RangeError.checkValueInInterval(index, 0, this.length, "index");
+ for (var element in iterable) {
+ this[index++] = element;
+ }
+ }
+
+ E removeLast() {
+ checkGrowable('removeLast');
+ if (length == 0) throw diagnoseIndexError(this, -1);
+ return JS('var', r'#.pop()', this);
+ }
+
+ bool remove(Object element) {
+ checkGrowable('remove');
+ var length = this.length;
+ for (int i = 0; i < length; i++) {
+ if (this[i] == element) {
+ JS('var', r'#.splice(#, 1)', this, i);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Removes elements matching [test] from [this] List.
+ */
+ void removeWhere(bool test(E element)) {
+ checkGrowable('removeWhere');
+ _removeWhere(test, true);
+ }
+
+ void retainWhere(bool test(E element)) {
+ checkGrowable('retainWhere');
+ _removeWhere(test, false);
+ }
+
+ void _removeWhere(bool test(E element), bool removeMatching) {
+ // Performed in two steps, to avoid exposing an inconsistent state
+ // to the [test] function. First the elements to retain are found, and then
+ // the original list is updated to contain those elements.
+
+ // TODO(sra): Replace this algorithm with one that retains a list of ranges
+ // to be removed. Most real uses remove 0, 1 or a few clustered elements.
+
+ List retained = [];
+ int end = this.length;
+ for (int i = 0; i < end; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ E element = JS('-dynamic', '#[#]', this, i);
+ // !test() ensures bool conversion in checked mode.
+ if (!test(element) == removeMatching) {
+ retained.add(element);
+ }
+ if (this.length != end) throw ConcurrentModificationError(this);
+ }
+ if (retained.length == end) return;
+ this.length = retained.length;
+ @nullCheck
+ var length = retained.length;
+ for (int i = 0; i < length; i++) {
+ JS('', '#[#] = #[#]', this, i, retained, i);
+ }
+ }
+
+ Iterable<E> where(bool f(E element)) {
+ return WhereIterable<E>(this, f);
+ }
+
+ Iterable<T> expand<T>(Iterable<T> f(E element)) {
+ return ExpandIterable<E, T>(this, f);
+ }
+
+ void addAll(Iterable<E> collection) {
+ int i = this.length;
+ checkGrowable('addAll');
+ for (E e in collection) {
+ assert(i == this.length || (throw ConcurrentModificationError(this)));
+ i++;
+ JS('void', r'#.push(#)', this, e);
+ }
+ }
+
+ void clear() {
+ length = 0;
+ }
+
+ void forEach(void f(E element)) {
+ int end = this.length;
+ for (int i = 0; i < end; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var/*=E*/ element = JS('', '#[#]', this, i);
+ f(element);
+ if (this.length != end) throw ConcurrentModificationError(this);
+ }
+ }
+
+ Iterable<T> map<T>(T f(E element)) {
+ return MappedListIterable<E, T>(this, f);
+ }
+
+ String join([String separator = ""]) {
+ var length = this.length;
+ var list = List(length);
+ for (int i = 0; i < length; i++) {
+ list[i] = "${this[i]}";
+ }
+ return JS<String>('!', "#.join(#)", list, separator);
+ }
+
+ Iterable<E> take(int n) {
+ return SubListIterable<E>(this, 0, n);
+ }
+
+ Iterable<E> takeWhile(bool test(E value)) {
+ return TakeWhileIterable<E>(this, test);
+ }
+
+ Iterable<E> skip(int n) {
+ return SubListIterable<E>(this, n, null);
+ }
+
+ Iterable<E> skipWhile(bool test(E value)) {
+ return SkipWhileIterable<E>(this, test);
+ }
+
+ E reduce(E combine(E previousValue, E element)) {
+ int length = this.length;
+ if (length == 0) throw IterableElementError.noElement();
+ E value = this[0];
+ for (int i = 1; i < length; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var/*=E*/ element = JS('', '#[#]', this, i);
+ value = combine(value, element);
+ if (length != this.length) throw ConcurrentModificationError(this);
+ }
+ return value;
+ }
+
+ T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+ var value = initialValue;
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var/*=E*/ element = JS('', '#[#]', this, i);
+ value = combine(value, element);
+ if (this.length != length) throw ConcurrentModificationError(this);
+ }
+ return value;
+ }
+
+ E firstWhere(bool test(E value), {E orElse()}) {
+ int end = this.length;
+ for (int i = 0; i < end; ++i) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var/*=E*/ element = JS('', '#[#]', this, i);
+ if (test(element)) return element;
+ if (this.length != end) throw ConcurrentModificationError(this);
+ }
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E lastWhere(bool test(E element), {E orElse()}) {
+ int length = this.length;
+ for (int i = length - 1; i >= 0; i--) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var/*=E*/ element = JS('', '#[#]', this, i);
+ if (test(element)) return element;
+ if (length != this.length) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E singleWhere(bool test(E element), {E orElse()}) {
+ int length = this.length;
+ E match = null;
+ bool matchFound = false;
+ for (int i = 0; i < length; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ E element = JS('-dynamic', '#[#]', this, i);
+ if (test(element)) {
+ if (matchFound) {
+ throw IterableElementError.tooMany();
+ }
+ matchFound = true;
+ match = element;
+ }
+ if (length != this.length) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ if (matchFound) return match;
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E elementAt(int index) {
+ return this[index];
+ }
+
+ List<E> sublist(@nullCheck int start, [int end]) {
+ if (start < 0 || start > length) {
+ throw RangeError.range(start, 0, length, "start");
+ }
+ if (end == null) {
+ end = length;
+ } else {
+ @notNull
+ var _end = end;
+ if (_end < start || _end > length) {
+ throw RangeError.range(end, start, length, "end");
+ }
+ }
+ if (start == end) return <E>[];
+ return JSArray<E>.of(JS('', r'#.slice(#, #)', this, start, end));
+ }
+
+ Iterable<E> getRange(int start, int end) {
+ RangeError.checkValidRange(start, end, this.length);
+ return SubListIterable<E>(this, start, end);
+ }
+
+ E get first {
+ if (length > 0) return this[0];
+ throw IterableElementError.noElement();
+ }
+
+ E get last {
+ if (length > 0) return this[length - 1];
+ throw IterableElementError.noElement();
+ }
+
+ E get single {
+ if (length == 1) return this[0];
+ if (length == 0) throw IterableElementError.noElement();
+ throw IterableElementError.tooMany();
+ }
+
+ void removeRange(@nullCheck int start, @nullCheck int end) {
+ checkGrowable('removeRange');
+ RangeError.checkValidRange(start, end, this.length);
+ int deleteCount = end - start;
+ JS('', '#.splice(#, #)', this, start, deleteCount);
+ }
+
+ void setRange(@nullCheck int start, @nullCheck int end, Iterable<E> iterable,
+ [@nullCheck int skipCount = 0]) {
+ checkMutable('set range');
+
+ RangeError.checkValidRange(start, end, this.length);
+ int length = end - start;
+ if (length == 0) return;
+ RangeError.checkNotNegative(skipCount, "skipCount");
+
+ List<E> otherList;
+ int otherStart = 0;
+ // TODO(floitsch): Make this accept more.
+ if (iterable is List<E>) {
+ otherList = iterable;
+ otherStart = skipCount;
+ } else {
+ otherList = iterable.skip(skipCount).toList(growable: false);
+ otherStart = 0;
+ }
+ if (otherStart + length > otherList.length) {
+ throw IterableElementError.tooFew();
+ }
+ if (otherStart < start) {
+ // Copy backwards to ensure correct copy if [from] is this.
+ // TODO(sra): If [from] is the same Array as [this], we can copy without
+ // type annotation checks on the stores.
+ for (int i = length - 1; i >= 0; i--) {
+ // Use JS to avoid bounds check (the bounds check elimination
+ // optimzation is too weak). The 'E' type annotation is a store type
+ // check - we can't rely on iterable, it could be List<dynamic>.
+ E element = otherList[otherStart + i];
+ JS('', '#[#] = #', this, start + i, element);
+ }
+ } else {
+ for (int i = 0; i < length; i++) {
+ E element = otherList[otherStart + i];
+ JS('', '#[#] = #', this, start + i, element);
+ }
+ }
+ }
+
+ void fillRange(@nullCheck int start, @nullCheck int end, [E fillValue]) {
+ checkMutable('fill range');
+ RangeError.checkValidRange(start, end, this.length);
+ for (int i = start; i < end; i++) {
+ // Store is safe since [fillValue] type has been checked as parameter.
+ JS('', '#[#] = #', this, i, fillValue);
+ }
+ }
+
+ void replaceRange(
+ @nullCheck int start, @nullCheck int end, Iterable<E> replacement) {
+ checkGrowable('replace range');
+ RangeError.checkValidRange(start, end, this.length);
+ if (replacement is! EfficientLengthIterable) {
+ replacement = replacement.toList();
+ }
+ int removeLength = end - start;
+ @nullCheck
+ int insertLength = replacement.length;
+ if (removeLength >= insertLength) {
+ int delta = removeLength - insertLength;
+ int insertEnd = start + insertLength;
+ int newLength = this.length - delta;
+ this.setRange(start, insertEnd, replacement);
+ if (delta != 0) {
+ this.setRange(insertEnd, newLength, this, end);
+ this.length = newLength;
+ }
+ } else {
+ int delta = insertLength - removeLength;
+ int newLength = this.length + delta;
+ int insertEnd = start + insertLength; // aka. end + delta.
+ this.length = newLength;
+ this.setRange(insertEnd, newLength, this, end);
+ this.setRange(start, insertEnd, replacement);
+ }
+ }
+
+ bool any(bool test(E element)) {
+ int end = this.length;
+ for (int i = 0; i < end; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var/*=E*/ element = JS('', '#[#]', this, i);
+ if (test(element)) return true;
+ if (this.length != end) throw ConcurrentModificationError(this);
+ }
+ return false;
+ }
+
+ bool every(bool test(E element)) {
+ int end = this.length;
+ for (int i = 0; i < end; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ E element = JS('-dynamic', '#[#]', this, i);
+ if (!test(element)) return false;
+ if (this.length != end) throw ConcurrentModificationError(this);
+ }
+ return true;
+ }
+
+ Iterable<E> get reversed => ReversedListIterable<E>(this);
+
+ void sort([int compare(E a, E b)]) {
+ checkMutable('sort');
+ if (compare == null) {
+ Sort.sort(this, (a, b) => Comparable.compare(a, b));
+ } else {
+ Sort.sort(this, compare);
+ }
+ }
+
+ void shuffle([Random random]) {
+ checkMutable('shuffle');
+ if (random == null) random = Random();
+ int length = this.length;
+ while (length > 1) {
+ int pos = random.nextInt(length);
+ length -= 1;
+ var tmp = this[length];
+ this[length] = this[pos];
+ this[pos] = tmp;
+ }
+ }
+
+ int indexOf(Object element, [@nullCheck int start = 0]) {
+ int length = this.length;
+ if (start >= length) {
+ return -1;
+ }
+ if (start < 0) {
+ start = 0;
+ }
+ for (int i = start; i < length; i++) {
+ if (this[i] == element) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ int lastIndexOf(Object element, [int _startIndex]) {
+ @notNull
+ int startIndex = _startIndex ?? this.length - 1;
+ if (startIndex >= this.length) {
+ startIndex = this.length - 1;
+ } else if (startIndex < 0) {
+ return -1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (this[i] == element) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ bool contains(Object other) {
+ var length = this.length;
+ for (int i = 0; i < length; i++) {
+ E element = JS('Null', '#[#]', this, i);
+ if (element == other) return true;
+ }
+ return false;
+ }
+
+ @notNull
+ bool get isEmpty => length == 0;
+
+ @notNull
+ bool get isNotEmpty => !isEmpty;
+
+ String toString() => ListBase.listToString(this);
+
+ List<E> toList({@nullCheck bool growable = true}) {
+ var list = JS('', '#.slice()', this);
+ if (!growable) markFixedList(list);
+ return JSArray<E>.of(list);
+ }
+
+ Set<E> toSet() => Set<E>.from(this);
+
+ Iterator<E> get iterator => ArrayIterator<E>(this);
+
+ int get hashCode => identityHashCode(this);
+
+ @notNull
+ bool operator ==(other) => identical(this, other);
+
+ @notNull
+ int get length => JS<int>('!', r'#.length', this);
+
+ void set length(@nullCheck int newLength) {
+ checkGrowable('set length');
+ // TODO(sra): Remove this test and let JavaScript throw an error.
+ if (newLength < 0) {
+ throw RangeError.range(newLength, 0, null, 'newLength');
+ }
+ // JavaScript with throw a RangeError for numbers that are too big. The
+ // message does not contain the value.
+ JS('void', r'#.length = #', this, newLength);
+ }
+
+ E operator [](int index) {
+ // Suppress redundant null checks via JS.
+ if (index == null ||
+ JS<int>('!', '#', index) >= JS<int>('!', '#.length', this) ||
+ JS<int>('!', '#', index) < 0) {
+ throw diagnoseIndexError(this, index);
+ }
+ return JS('var', '#[#]', this, index);
+ }
+
+ void operator []=(int index, E value) {
+ checkMutable('indexed set');
+ if (index == null ||
+ JS<int>('!', '#', index) >= JS<int>('!', '#.length', this) ||
+ JS<int>('!', '#', index) < 0) {
+ throw diagnoseIndexError(this, index);
+ }
+ JS('void', r'#[#] = #', this, index, value);
+ }
+
+ Map<int, E> asMap() {
+ return ListMapView<E>(this);
+ }
+
+ Type get runtimeType =>
+ dart.wrapType(JS('', '#(#)', dart.getGenericClass(List), E));
+
+ Iterable<E> followedBy(Iterable<E> other) =>
+ FollowedByIterable<E>.firstEfficient(this, other);
+
+ Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
+
+ List<E> operator +(List<E> other) {
+ int totalLength = this.length + other.length;
+ return <E>[]
+ ..length = totalLength
+ ..setRange(0, this.length, this)
+ ..setRange(this.length, totalLength, other);
+ }
+
+ int indexWhere(bool test(E element), [int start = 0]) {
+ if (start >= this.length) return -1;
+ if (start < 0) start = 0;
+ for (int i = start; i < this.length; i++) {
+ if (test(this[i])) return i;
+ }
+ return -1;
+ }
+
+ int lastIndexWhere(bool test(E element), [int start]) {
+ if (start == null) start = this.length - 1;
+ if (start < 0) return -1;
+ for (int i = start; i >= 0; i--) {
+ if (test(this[i])) return i;
+ }
+ return -1;
+ }
+
+ void set first(E element) {
+ if (this.isEmpty) throw RangeError.index(0, this);
+ this[0] = element;
+ }
+
+ void set last(E element) {
+ if (this.isEmpty) throw RangeError.index(0, this);
+ this[this.length - 1] = element;
+ }
+}
+
+/**
+ * Dummy subclasses that allow the backend to track more precise
+ * information about arrays through their type. The CPA type inference
+ * relies on the fact that these classes do not override [] nor []=.
+ *
+ * These classes are really a fiction, and can have no methods, since
+ * getInterceptor always returns JSArray. We should consider pushing the
+ * 'isGrowable' and 'isMutable' checks into the getInterceptor implementation so
+ * these classes can have specialized implementations. Doing so will challenge
+ * many assumptions in the JS backend.
+ */
+class JSMutableArray<E> extends JSArray<E> {}
+
+class JSFixedArray<E> extends JSMutableArray<E> {}
+
+class JSExtendableArray<E> extends JSMutableArray<E> {}
+
+class JSUnmodifiableArray<E> extends JSArray<E> {} // Already is JSIndexable.
+
+/// An [Iterator] that iterates a JSArray.
+///
+class ArrayIterator<E> implements Iterator<E> {
+ final JSArray<E> _iterable;
+ @notNull
+ final int _length;
+ @notNull
+ int _index;
+ E _current;
+
+ ArrayIterator(JSArray<E> iterable)
+ : _iterable = iterable,
+ _length = iterable.length,
+ _index = 0;
+
+ E get current => _current;
+
+ bool moveNext() {
+ @notNull
+ int length = _iterable.length;
+
+ // We have to do the length check even on fixed length Arrays. If we can
+ // inline moveNext() we might be able to GVN the length and eliminate this
+ // check on known fixed length JSArray.
+ if (_length != length) {
+ throw throwConcurrentModificationError(_iterable);
+ }
+
+ if (_index >= length) {
+ _current = null;
+ return false;
+ }
+ _current = _iterable[_index];
+ _index++;
+ return true;
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
new file mode 100644
index 0000000..5d6b037
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
@@ -0,0 +1,826 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._js_helper;
+
+import 'dart:collection';
+
+import 'dart:_foreign_helper' show JS, JS_STRING_CONCAT, JSExportName;
+
+import 'dart:_interceptors';
+import 'dart:_internal'
+ show
+ EfficientLengthIterable,
+ MappedIterable,
+ IterableElementError,
+ SubListIterable;
+
+import 'dart:_native_typed_data';
+import 'dart:_runtime' as dart;
+
+part 'annotations.dart';
+part 'linked_hash_map.dart';
+part 'identity_hash_map.dart';
+part 'custom_hash_map.dart';
+part 'native_helper.dart';
+part 'regexp_helper.dart';
+part 'string_helper.dart';
+part 'js_rti.dart';
+
+class _Patch {
+ const _Patch();
+}
+
+const _Patch patch = _Patch();
+
+/// Adapts a JS `[Symbol.iterator]` to a Dart `get iterator`.
+///
+/// This is the inverse of `JsIterator`, for classes where we can more
+/// efficiently obtain a JS iterator instead of a Dart one.
+///
+// TODO(jmesserly): this adapter is to work around
+// https://github.com/dart-lang/sdk/issues/28320
+class DartIterator<E> implements Iterator<E> {
+ final _jsIterator;
+ E _current;
+
+ DartIterator(this._jsIterator);
+
+ E get current => _current;
+
+ bool moveNext() {
+ final ret = JS('', '#.next()', _jsIterator);
+ _current = JS('', '#.value', ret);
+ return JS<bool>('!', '!#.done', ret);
+ }
+}
+
+/// Used to compile `sync*`.
+class SyncIterable<E> extends IterableBase<E> {
+ final Function() _initGenerator;
+ SyncIterable(this._initGenerator);
+
+ @JSExportName('Symbol.iterator')
+ _jsIterator() => _initGenerator();
+
+ get iterator => DartIterator(_initGenerator());
+}
+
+class Primitives {
+ @NoInline()
+ static int _parseIntError(String source, int handleError(String source)) {
+ if (handleError == null) throw FormatException(source);
+ return handleError(source);
+ }
+
+ static int parseInt(
+ @nullCheck String source, int _radix, int handleError(String source)) {
+ var re = JS('', r'/^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i');
+ // TODO(jmesserly): this isn't reified List<String>, but it's safe to use as
+ // long as we use it locally and don't expose it to user code.
+ List<String> match = JS('', '#.exec(#)', re, source);
+ int digitsIndex = 1;
+ int hexIndex = 2;
+ int decimalIndex = 3;
+ if (match == null) {
+ // TODO(sra): It might be that the match failed due to unrecognized U+0085
+ // spaces. We could replace them with U+0020 spaces and try matching
+ // again.
+ return _parseIntError(source, handleError);
+ }
+ String decimalMatch = match[decimalIndex];
+ if (_radix == null) {
+ if (decimalMatch != null) {
+ // Cannot fail because we know that the digits are all decimal.
+ return JS<int>('!', r'parseInt(#, 10)', source);
+ }
+ if (match[hexIndex] != null) {
+ // Cannot fail because we know that the digits are all hex.
+ return JS<int>('!', r'parseInt(#, 16)', source);
+ }
+ return _parseIntError(source, handleError);
+ }
+ @notNull
+ var radix = _radix;
+ if (radix < 2 || radix > 36) {
+ throw RangeError.range(radix, 2, 36, 'radix');
+ }
+ if (radix == 10 && decimalMatch != null) {
+ // Cannot fail because we know that the digits are all decimal.
+ return JS<int>('!', r'parseInt(#, 10)', source);
+ }
+ // If radix >= 10 and we have only decimal digits the string is safe.
+ // Otherwise we need to check the digits.
+ if (radix < 10 || decimalMatch == null) {
+ // We know that the characters must be ASCII as otherwise the
+ // regexp wouldn't have matched. Lowercasing by doing `| 0x20` is thus
+ // guaranteed to be a safe operation, since it preserves digits
+ // and lower-cases ASCII letters.
+ int maxCharCode;
+ if (radix <= 10) {
+ // Allow all digits less than the radix. For example 0, 1, 2 for
+ // radix 3.
+ // "0".codeUnitAt(0) + radix - 1;
+ maxCharCode = (0x30 - 1) + radix;
+ } else {
+ // Letters are located after the digits in ASCII. Therefore we
+ // only check for the character code. The regexp above made already
+ // sure that the string does not contain anything but digits or
+ // letters.
+ // "a".codeUnitAt(0) + (radix - 10) - 1;
+ maxCharCode = (0x61 - 10 - 1) + radix;
+ }
+ assert(match[digitsIndex] is String);
+ String digitsPart = JS<String>('!', '#[#]', match, digitsIndex);
+ for (int i = 0; i < digitsPart.length; i++) {
+ int characterCode = digitsPart.codeUnitAt(i) | 0x20;
+ if (characterCode > maxCharCode) {
+ return _parseIntError(source, handleError);
+ }
+ }
+ }
+ // The above matching and checks ensures the source has at least one digits
+ // and all digits are suitable for the radix, so parseInt cannot return NaN.
+ return JS<int>('!', r'parseInt(#, #)', source, radix);
+ }
+
+ @NoInline()
+ static double _parseDoubleError(
+ String source, double handleError(String source)) {
+ if (handleError == null) {
+ throw FormatException('Invalid double', source);
+ }
+ return handleError(source);
+ }
+
+ static double parseDouble(
+ @nullCheck String source, double handleError(String source)) {
+ // Notice that JS parseFloat accepts garbage at the end of the string.
+ // Accept only:
+ // - [+/-]NaN
+ // - [+/-]Infinity
+ // - a Dart double literal
+ // We do allow leading or trailing whitespace.
+ if (!JS(
+ 'bool',
+ r'/^\s*[+-]?(?:Infinity|NaN|'
+ r'(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$/.test(#)',
+ source)) {
+ return _parseDoubleError(source, handleError);
+ }
+ num result = JS('!', r'parseFloat(#)', source);
+ if (result.isNaN) {
+ var trimmed = source.trim();
+ if (trimmed == 'NaN' || trimmed == '+NaN' || trimmed == '-NaN') {
+ return result;
+ }
+ return _parseDoubleError(source, handleError);
+ }
+ return result;
+ }
+
+ /** `r"$".codeUnitAt(0)` */
+ static const int DOLLAR_CHAR_VALUE = 36;
+
+ static int dateNow() => JS<int>('!', r'Date.now()');
+
+ static void initTicker() {
+ if (timerFrequency != null) return;
+ // Start with low-resolution. We overwrite the fields if we find better.
+ timerFrequency = 1000;
+ timerTicks = dateNow;
+ if (JS<bool>('!', 'typeof window == "undefined"')) return;
+ var jsWindow = JS('var', 'window');
+ if (jsWindow == null) return;
+ var performance = JS('var', '#.performance', jsWindow);
+ if (performance == null) return;
+ if (JS<bool>('!', 'typeof #.now != "function"', performance)) return;
+ timerFrequency = 1000000;
+ timerTicks = () => (1000 * JS<num>('!', '#.now()', performance)).floor();
+ }
+
+ static int timerFrequency;
+ static num Function() timerTicks;
+
+ static bool get isD8 {
+ return JS(
+ 'bool',
+ 'typeof version == "function"'
+ ' && typeof os == "object" && "system" in os');
+ }
+
+ static bool get isJsshell {
+ return JS(
+ 'bool', 'typeof version == "function" && typeof system == "function"');
+ }
+
+ static String currentUri() {
+ // In a browser return self.location.href.
+ if (JS<bool>('!', '!!#.location', dart.global_)) {
+ return JS<String>('!', '#.location.href', dart.global_);
+ }
+
+ // TODO(vsm): Consider supporting properly in non-browser settings.
+ return '';
+ }
+
+ // This is to avoid stack overflows due to very large argument arrays in
+ // apply(). It fixes http://dartbug.com/6919
+ @notNull
+ static String _fromCharCodeApply(List<int> array) {
+ const kMaxApply = 500;
+ @nullCheck
+ int end = array.length;
+ if (end <= kMaxApply) {
+ return JS<String>('!', r'String.fromCharCode.apply(null, #)', array);
+ }
+ String result = '';
+ for (int i = 0; i < end; i += kMaxApply) {
+ int chunkEnd = (i + kMaxApply < end) ? i + kMaxApply : end;
+ result = JS(
+ 'String',
+ r'# + String.fromCharCode.apply(null, #.slice(#, #))',
+ result,
+ array,
+ i,
+ chunkEnd);
+ }
+ return result;
+ }
+
+ @notNull
+ static String stringFromCodePoints(JSArray<int> codePoints) {
+ List<int> a = <int>[];
+ for (@nullCheck var i in codePoints) {
+ if (i <= 0xffff) {
+ a.add(i);
+ } else if (i <= 0x10ffff) {
+ a.add(0xd800 + ((((i - 0x10000) >> 10) & 0x3ff)));
+ a.add(0xdc00 + (i & 0x3ff));
+ } else {
+ throw argumentErrorValue(i);
+ }
+ }
+ return _fromCharCodeApply(a);
+ }
+
+ @notNull
+ static String stringFromCharCodes(JSArray<int> charCodes) {
+ for (@nullCheck var i in charCodes) {
+ if (i < 0) throw argumentErrorValue(i);
+ if (i > 0xffff) return stringFromCodePoints(charCodes);
+ }
+ return _fromCharCodeApply(charCodes);
+ }
+
+ // [start] and [end] are validated.
+ @notNull
+ static String stringFromNativeUint8List(
+ NativeUint8List charCodes, @nullCheck int start, @nullCheck int end) {
+ const kMaxApply = 500;
+ if (end <= kMaxApply && start == 0 && end == charCodes.length) {
+ return JS<String>('!', r'String.fromCharCode.apply(null, #)', charCodes);
+ }
+ String result = '';
+ for (int i = start; i < end; i += kMaxApply) {
+ int chunkEnd = (i + kMaxApply < end) ? i + kMaxApply : end;
+ result = JS(
+ 'String',
+ r'# + String.fromCharCode.apply(null, #.subarray(#, #))',
+ result,
+ charCodes,
+ i,
+ chunkEnd);
+ }
+ return result;
+ }
+
+ @notNull
+ static String stringFromCharCode(@nullCheck int charCode) {
+ if (0 <= charCode) {
+ if (charCode <= 0xffff) {
+ return JS<String>('!', 'String.fromCharCode(#)', charCode);
+ }
+ if (charCode <= 0x10ffff) {
+ var bits = charCode - 0x10000;
+ var low = 0xDC00 | (bits & 0x3ff);
+ var high = 0xD800 | (bits >> 10);
+ return JS<String>('!', 'String.fromCharCode(#, #)', high, low);
+ }
+ }
+ throw RangeError.range(charCode, 0, 0x10ffff);
+ }
+
+ static String stringConcatUnchecked(String string1, String string2) {
+ return JS_STRING_CONCAT(string1, string2);
+ }
+
+ static String flattenString(String str) {
+ return JS<String>('!', "#.charCodeAt(0) == 0 ? # : #", str, str, str);
+ }
+
+ static String getTimeZoneName(DateTime receiver) {
+ // Firefox and Chrome emit the timezone in parenthesis.
+ // Example: "Wed May 16 2012 21:13:00 GMT+0200 (CEST)".
+ // We extract this name using a regexp.
+ var d = lazyAsJsDate(receiver);
+ List match = JS('JSArray|Null', r'/\((.*)\)/.exec(#.toString())', d);
+ if (match != null) return match[1];
+
+ // Internet Explorer 10+ emits the zone name without parenthesis:
+ // Example: Thu Oct 31 14:07:44 PDT 2013
+ match = JS(
+ 'JSArray|Null',
+ // Thu followed by a space.
+ r'/^[A-Z,a-z]{3}\s'
+ // Oct 31 followed by space.
+ r'[A-Z,a-z]{3}\s\d+\s'
+ // Time followed by a space.
+ r'\d{2}:\d{2}:\d{2}\s'
+ // The time zone name followed by a space.
+ r'([A-Z]{3,5})\s'
+ // The year.
+ r'\d{4}$/'
+ '.exec(#.toString())',
+ d);
+ if (match != null) return match[1];
+
+ // IE 9 and Opera don't provide the zone name. We fall back to emitting the
+ // UTC/GMT offset.
+ // Example (IE9): Wed Nov 20 09:51:00 UTC+0100 2013
+ // (Opera): Wed Nov 20 2013 11:03:38 GMT+0100
+ match = JS('JSArray|Null', r'/(?:GMT|UTC)[+-]\d{4}/.exec(#.toString())', d);
+ if (match != null) return match[0];
+ return "";
+ }
+
+ static int getTimeZoneOffsetInMinutes(DateTime receiver) {
+ // Note that JS and Dart disagree on the sign of the offset.
+ return -JS<int>('!', r'#.getTimezoneOffset()', lazyAsJsDate(receiver));
+ }
+
+ static num valueFromDecomposedDate(
+ @nullCheck int years,
+ @nullCheck int month,
+ @nullCheck int day,
+ @nullCheck int hours,
+ @nullCheck int minutes,
+ @nullCheck int seconds,
+ @nullCheck int milliseconds,
+ @nullCheck bool isUtc) {
+ final int MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000;
+ var jsMonth = month - 1;
+ num value;
+ if (isUtc) {
+ value = JS('!', r'Date.UTC(#, #, #, #, #, #, #)', years, jsMonth, day,
+ hours, minutes, seconds, milliseconds);
+ } else {
+ value = JS('!', r'new Date(#, #, #, #, #, #, #).valueOf()', years,
+ jsMonth, day, hours, minutes, seconds, milliseconds);
+ }
+ if (value.isNaN ||
+ value < -MAX_MILLISECONDS_SINCE_EPOCH ||
+ value > MAX_MILLISECONDS_SINCE_EPOCH) {
+ return null;
+ }
+ if (years <= 0 || years < 100) return patchUpY2K(value, years, isUtc);
+ return value;
+ }
+
+ static num patchUpY2K(value, years, isUtc) {
+ var date = JS('', r'new Date(#)', value);
+ if (isUtc) {
+ JS('', r'#.setUTCFullYear(#)', date, years);
+ } else {
+ JS('', r'#.setFullYear(#)', date, years);
+ }
+ return JS('!', r'#.valueOf()', date);
+ }
+
+ // Lazily keep a JS Date stored in the JS object.
+ static lazyAsJsDate(DateTime receiver) {
+ if (JS<bool>('!', r'#.date === (void 0)', receiver)) {
+ JS('void', r'#.date = new Date(#)', receiver,
+ receiver.millisecondsSinceEpoch);
+ }
+ return JS('var', r'#.date', receiver);
+ }
+
+ // The getters for date and time parts below add a positive integer to ensure
+ // that the result is really an integer, because the JavaScript implementation
+ // may return -0.0 instead of 0.
+
+ static int getYear(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS<int>('!', r'(#.getUTCFullYear() + 0)', lazyAsJsDate(receiver))
+ : JS<int>('!', r'(#.getFullYear() + 0)', lazyAsJsDate(receiver));
+ }
+
+ static int getMonth(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS<int>('!', r'#.getUTCMonth() + 1', lazyAsJsDate(receiver))
+ : JS<int>('!', r'#.getMonth() + 1', lazyAsJsDate(receiver));
+ }
+
+ static int getDay(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS<int>('!', r'(#.getUTCDate() + 0)', lazyAsJsDate(receiver))
+ : JS<int>('!', r'(#.getDate() + 0)', lazyAsJsDate(receiver));
+ }
+
+ static int getHours(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS<int>('!', r'(#.getUTCHours() + 0)', lazyAsJsDate(receiver))
+ : JS<int>('!', r'(#.getHours() + 0)', lazyAsJsDate(receiver));
+ }
+
+ static int getMinutes(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS<int>('!', r'(#.getUTCMinutes() + 0)', lazyAsJsDate(receiver))
+ : JS<int>('!', r'(#.getMinutes() + 0)', lazyAsJsDate(receiver));
+ }
+
+ static int getSeconds(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS<int>('!', r'(#.getUTCSeconds() + 0)', lazyAsJsDate(receiver))
+ : JS<int>('!', r'(#.getSeconds() + 0)', lazyAsJsDate(receiver));
+ }
+
+ static int getMilliseconds(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS<int>('!', r'(#.getUTCMilliseconds() + 0)', lazyAsJsDate(receiver))
+ : JS<int>('!', r'(#.getMilliseconds() + 0)', lazyAsJsDate(receiver));
+ }
+
+ static int getWeekday(DateTime receiver) {
+ int weekday = (receiver.isUtc)
+ ? JS<int>('!', r'#.getUTCDay() + 0', lazyAsJsDate(receiver))
+ : JS<int>('!', r'#.getDay() + 0', lazyAsJsDate(receiver));
+ // Adjust by one because JS weeks start on Sunday.
+ return (weekday + 6) % 7 + 1;
+ }
+
+ static num valueFromDateString(str) {
+ if (str is! String) throw argumentErrorValue(str);
+ num value = JS('!', r'Date.parse(#)', str);
+ if (value.isNaN) throw argumentErrorValue(str);
+ return value;
+ }
+
+ static getProperty(object, key) {
+ if (object == null || object is bool || object is num || object is String) {
+ throw argumentErrorValue(object);
+ }
+ return JS('var', '#[#]', object, key);
+ }
+
+ static void setProperty(object, key, value) {
+ if (object == null || object is bool || object is num || object is String) {
+ throw argumentErrorValue(object);
+ }
+ JS('void', '#[#] = #', object, key, value);
+ }
+}
+
+/**
+ * Diagnoses an indexing error. Returns the ArgumentError or RangeError that
+ * describes the problem.
+ */
+@NoInline()
+Error diagnoseIndexError(indexable, int index) {
+ int length = indexable.length;
+ // The following returns the same error that would be thrown by calling
+ // [RangeError.checkValidIndex] with no optional parameters provided.
+ if (index < 0 || index >= length) {
+ return RangeError.index(index, indexable, 'index', null, length);
+ }
+ // The above should always match, but if it does not, use the following.
+ return RangeError.value(index, 'index');
+}
+
+/**
+ * Diagnoses a range error. Returns the ArgumentError or RangeError that
+ * describes the problem.
+ */
+@NoInline()
+Error diagnoseRangeError(int start, int end, int length) {
+ if (start == null) {
+ return ArgumentError.value(start, 'start');
+ }
+ if (start < 0 || start > length) {
+ return RangeError.range(start, 0, length, 'start');
+ }
+ if (end != null) {
+ if (end < start || end > length) {
+ return RangeError.range(end, start, length, 'end');
+ }
+ }
+ // The above should always match, but if it does not, use the following.
+ return ArgumentError.value(end, "end");
+}
+
+@notNull
+int stringLastIndexOfUnchecked(receiver, element, start) =>
+ JS<int>('!', r'#.lastIndexOf(#, #)', receiver, element, start);
+
+/// 'factory' for constructing ArgumentError.value to keep the call sites small.
+@NoInline()
+ArgumentError argumentErrorValue(object) {
+ return ArgumentError.value(object);
+}
+
+void throwArgumentErrorValue(value) {
+ throw argumentErrorValue(value);
+}
+
+checkInt(value) {
+ if (value is! int) throw argumentErrorValue(value);
+ return value;
+}
+
+throwRuntimeError(message) {
+ throw RuntimeError(message);
+}
+
+throwAbstractClassInstantiationError(className) {
+ throw AbstractClassInstantiationError(className);
+}
+
+@NoInline()
+throwConcurrentModificationError(collection) {
+ throw ConcurrentModificationError(collection);
+}
+
+class JsNoSuchMethodError extends Error implements NoSuchMethodError {
+ final String _message;
+ final String _method;
+ final String _receiver;
+
+ JsNoSuchMethodError(this._message, match)
+ : _method = match == null ? null : JS('String|Null', '#.method', match),
+ _receiver =
+ match == null ? null : JS('String|Null', '#.receiver', match);
+
+ String toString() {
+ if (_method == null) return 'NoSuchMethodError: $_message';
+ if (_receiver == null) {
+ return "NoSuchMethodError: method not found: '$_method' ($_message)";
+ }
+ return "NoSuchMethodError: "
+ "method not found: '$_method' on '$_receiver' ($_message)";
+ }
+}
+
+class UnknownJsTypeError extends Error {
+ final String _message;
+
+ UnknownJsTypeError(this._message);
+
+ String toString() => _message.isEmpty ? 'Error' : 'Error: $_message';
+}
+
+/**
+ * Called by generated code to build a map literal. [keyValuePairs] is
+ * a list of key, value, key, value, ..., etc.
+ */
+fillLiteralMap(keyValuePairs, Map result) {
+ // TODO(johnniwinther): Use JSArray to optimize this code instead of calling
+ // [getLength] and [getIndex].
+ int index = 0;
+ int length = getLength(keyValuePairs);
+ while (index < length) {
+ var key = getIndex(keyValuePairs, index++);
+ var value = getIndex(keyValuePairs, index++);
+ result[key] = value;
+ }
+ return result;
+}
+
+bool jsHasOwnProperty(var jsObject, String property) {
+ return JS<bool>('!', r'#.hasOwnProperty(#)', jsObject, property);
+}
+
+jsPropertyAccess(var jsObject, String property) {
+ return JS('var', r'#[#]', jsObject, property);
+}
+
+/**
+ * Called at the end of unaborted switch cases to get the singleton
+ * FallThroughError exception that will be thrown.
+ */
+getFallThroughError() => FallThroughErrorImplementation();
+
+/**
+ * A metadata annotation describing the types instantiated by a native element.
+ *
+ * The annotation is valid on a native method and a field of a native class.
+ *
+ * By default, a field of a native class is seen as an instantiation point for
+ * all native classes that are a subtype of the field's type, and a native
+ * method is seen as an instantiation point fo all native classes that are a
+ * subtype of the method's return type, or the argument types of the declared
+ * type of the method's callback parameter.
+ *
+ * An @[Creates] annotation overrides the default set of instantiated types. If
+ * one or more @[Creates] annotations are present, the type of the native
+ * element is ignored, and the union of @[Creates] annotations is used instead.
+ * The names in the strings are resolved and the program will fail to compile
+ * with dart2js if they do not name types.
+ *
+ * The argument to [Creates] is a string. The string is parsed as the names of
+ * one or more types, separated by vertical bars `|`. There are some special
+ * names:
+ *
+ * * `=Object`. This means 'exactly Object', which is a plain JavaScript object
+ * with properties and none of the subtypes of Object.
+ *
+ * Example: we may know that a method always returns a specific implementation:
+ *
+ * @Creates('_NodeList')
+ * List<Node> getElementsByTagName(String tag) native;
+ *
+ * Useful trick: A method can be marked as not instantiating any native classes
+ * with the annotation `@Creates('Null')`. This is useful for fields on native
+ * classes that are used only in Dart code.
+ *
+ * @Creates('Null')
+ * var _cachedFoo;
+ */
+class Creates {
+ final String types;
+ const Creates(this.types);
+}
+
+/**
+ * A metadata annotation describing the types returned or yielded by a native
+ * element.
+ *
+ * The annotation is valid on a native method and a field of a native class.
+ *
+ * By default, a native method or field is seen as returning or yielding all
+ * subtypes if the method return type or field type. This annotation allows a
+ * more precise set of types to be specified.
+ *
+ * See [Creates] for the syntax of the argument.
+ *
+ * Example: IndexedDB keys are numbers, strings and JavaScript Arrays of keys.
+ *
+ * @Returns('String|num|JSExtendableArray')
+ * dynamic key;
+ *
+ * // Equivalent:
+ * @Returns('String') @Returns('num') @Returns('JSExtendableArray')
+ * dynamic key;
+ */
+class Returns {
+ final String types;
+ const Returns(this.types);
+}
+
+/**
+ * A metadata annotation placed on native methods and fields of native classes
+ * to specify the JavaScript name.
+ *
+ * This example declares a Dart field + getter + setter called `$dom_title` that
+ * corresponds to the JavaScript property `title`.
+ *
+ * class Document native "*Foo" {
+ * @JSName('title')
+ * String $dom_title;
+ * }
+ */
+class JSName {
+ final String name;
+ const JSName(this.name);
+}
+
+/**
+ * Special interface recognized by the compiler and implemented by DOM
+ * objects that support integer indexing. This interface is not
+ * visible to anyone, and is only injected into special libraries.
+ */
+abstract class JavaScriptIndexingBehavior<E> {}
+
+// TODO(lrn): These exceptions should be implemented in core.
+// When they are, remove the 'Implementation' here.
+
+/// Thrown by type assertions that fail.
+class TypeErrorImpl extends Error implements TypeError {
+ final String message;
+
+ TypeErrorImpl(this.message);
+
+ String toString() => message;
+}
+
+/// Thrown by the 'as' operator if the cast isn't valid.
+class CastErrorImpl extends Error implements CastError {
+ final String message;
+
+ CastErrorImpl(this.message);
+
+ String toString() => message;
+}
+
+class FallThroughErrorImplementation extends FallThroughError {
+ String toString() => "Switch case fall-through.";
+}
+
+/**
+ * Error thrown when a runtime error occurs.
+ */
+class RuntimeError extends Error {
+ final message;
+ RuntimeError(this.message);
+ String toString() => "RuntimeError: $message";
+}
+
+/// Error thrown by DDC when an `assert()` fails (with or without a message).
+class AssertionErrorImpl extends AssertionError {
+ final String _fileUri;
+ final int _line;
+ final int _column;
+ final String _conditionSource;
+
+ AssertionErrorImpl(Object message,
+ [this._fileUri, this._line, this._column, this._conditionSource])
+ : super(message);
+
+ String toString() {
+ var failureMessage = "";
+ if (_fileUri != null &&
+ _line != null &&
+ _column != null &&
+ _conditionSource != null) {
+ failureMessage += "$_fileUri:${_line}:${_column}\n$_conditionSource\n";
+ }
+ failureMessage +=
+ message != null ? Error.safeToString(message) : "is not true";
+
+ return "Assertion failed: $failureMessage";
+ }
+}
+
+/**
+ * Creates a random number with 64 bits of randomness.
+ *
+ * This will be truncated to the 53 bits available in a double.
+ */
+int random64() {
+ // TODO(lrn): Use a secure random source.
+ int int32a = JS("int", "(Math.random() * 0x100000000) >>> 0");
+ int int32b = JS("int", "(Math.random() * 0x100000000) >>> 0");
+ return int32a + int32b * 0x100000000;
+}
+
+class BooleanConversionAssertionError extends AssertionError {
+ toString() => 'Failed assertion: boolean expression must not be null';
+}
+
+// Hook to register new global object. This is invoked from dart:html
+// whenever a new window is accessed for the first time.
+void registerGlobalObject(object) {
+ try {
+ if (dart.polyfill(object)) {
+ dart.applyAllExtensions(object);
+ }
+ } catch (e) {
+ // This may fail due to cross-origin errors. In that case, we shouldn't
+ // need to polyfill as we can't get objects from that frame.
+
+ // TODO(vsm): Detect this more robustly - ideally before we try to polyfill.
+ }
+}
+
+/// Expose browser JS classes.
+void applyExtension(name, nativeObject) {
+ dart.applyExtension(name, nativeObject);
+}
+
+/// Used internally by DDC to map ES6 symbols to Dart.
+class PrivateSymbol implements Symbol {
+ // TODO(jmesserly): could also get this off the native symbol instead of
+ // storing it. Mirrors already does this conversion.
+ final String _name;
+ final Object _nativeSymbol;
+
+ const PrivateSymbol(this._name, this._nativeSymbol);
+
+ static String getName(Symbol symbol) => (symbol as PrivateSymbol)._name;
+
+ static Object getNativeSymbol(Symbol symbol) {
+ if (symbol is PrivateSymbol) return symbol._nativeSymbol;
+ return null;
+ }
+
+ bool operator ==(other) =>
+ other is PrivateSymbol &&
+ _name == other._name &&
+ identical(_nativeSymbol, other._nativeSymbol);
+
+ get hashCode => _name.hashCode;
+
+ // TODO(jmesserly): is this equivalent to _nativeSymbol toString?
+ toString() => 'Symbol("$_name")';
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_mirrors.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_mirrors.dart
new file mode 100644
index 0000000..a93f5fb
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_mirrors.dart
@@ -0,0 +1,598 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._js_mirrors;
+
+import 'dart:mirrors';
+import 'dart:_runtime' as dart;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_internal' as _internal show Symbol;
+import 'dart:_js_helper' show PrivateSymbol;
+
+String getName(Symbol symbol) {
+ if (symbol is PrivateSymbol) {
+ return PrivateSymbol.getName(symbol);
+ } else {
+ return _internal.Symbol.getName(symbol as _internal.Symbol);
+ }
+}
+
+Symbol getSymbol(name, library) =>
+ throw UnimplementedError("MirrorSystem.getSymbol unimplemented");
+
+final currentJsMirrorSystem = JsMirrorSystem();
+
+final _typeMirror = JS('', 'Symbol("_typeMirror")');
+
+InstanceMirror reflect(reflectee) {
+ // TODO(vsm): Consider caching the mirror here. Unlike the type below,
+ // reflectee may be a primitive - i.e., we can't just add an expando.
+ if (reflectee is Function) {
+ return JsClosureMirror._(reflectee);
+ } else {
+ return JsInstanceMirror._(reflectee);
+ }
+}
+
+TypeMirror reflectType(Type key) {
+ var unwrapped = dart.unwrapType(key);
+ var property =
+ JS('', 'Object.getOwnPropertyDescriptor(#, #)', unwrapped, _typeMirror);
+ if (property != null) {
+ return JS('', '#.value', property);
+ }
+ // TODO(vsm): Might not be a class.
+ var mirror = JsClassMirror._(key);
+ JS('', '#[#] = #', unwrapped, _typeMirror, mirror);
+ return mirror;
+}
+
+typedef T _Lazy<T>();
+
+dynamic _getESSymbol(Symbol symbol) => PrivateSymbol.getNativeSymbol(symbol);
+
+dynamic _getMember(Symbol symbol) {
+ var privateSymbol = _getESSymbol(symbol);
+ if (privateSymbol != null) {
+ return privateSymbol;
+ }
+ var name = getName(symbol);
+ // TODO(jacobr): this code is duplicated in code_generator.dart
+ switch (name) {
+ case '[]':
+ name = '_get';
+ break;
+ case '[]=':
+ name = '_set';
+ break;
+ case 'unary-':
+ name = '_negate';
+ break;
+ case 'constructor':
+ case 'prototype':
+ name = '_$name';
+ break;
+ }
+ return name;
+}
+
+String _getNameForESSymbol(member) {
+ // Convert private JS symbol "Symbol(_foo)" to string "_foo".
+ assert(JS<bool>('!', 'typeof # == "symbol"', member));
+ var str = member.toString();
+ assert(str.startsWith('Symbol(') && str.endsWith(')'));
+ return str.substring(7, str.length - 1);
+}
+
+Symbol _getSymbolForESSymbol(member) {
+ var name = _getNameForESSymbol(member);
+ return PrivateSymbol(name, member);
+}
+
+// The [member] must be either a string (public) or an ES6 symbol (private).
+Symbol _getSymbolForMember(member) {
+ if (member is String) {
+ return Symbol(member);
+ } else {
+ var name = _getNameForESSymbol(member);
+ return PrivateSymbol(name, member);
+ }
+}
+
+Map<Symbol, dynamic> _toDartMap(data) {
+ if (data == null) return {};
+ var map = Map<Symbol, dynamic>();
+ // Note: we recorded a map from fields/methods to their type and metadata.
+ // The key is a string name for public members but an ES6 symbol for private
+ // ones. That's works nicely for dynamic operations, but dart:mirrors expects
+ // Dart symbols, so we convert here.
+ var publicMembers = JS('', 'Object.getOwnPropertyNames(#)', data);
+ for (var member in publicMembers) {
+ var symbol = Symbol(member);
+ map[symbol] = JS('', '#[#]', data, member);
+ }
+
+ var privateMembers = JS('', 'Object.getOwnPropertySymbols(#)', data);
+ for (var member in privateMembers) {
+ var symbol = _getSymbolForESSymbol(member);
+ map[symbol] = JS('', '#[#]', data, member);
+ }
+ return map;
+}
+
+dynamic _runtimeType(obj) => dart.wrapType(dart.getReifiedType(obj));
+
+_unimplemented(Type t, Invocation i) {
+ throw UnimplementedError('$t.${getName(i.memberName)} unimplemented');
+}
+
+dynamic _toJsMap(Map<Symbol, dynamic> map) {
+ if (map == null) return null;
+ var obj = JS('', '{}');
+ map.forEach((Symbol key, value) {
+ JS('', '#[#] = #', obj, getName(key), value);
+ });
+ return obj;
+}
+
+class JsMirrorSystem implements MirrorSystem {
+ get libraries => const {};
+
+ noSuchMethod(Invocation i) {
+ _unimplemented(this.runtimeType, i);
+ }
+}
+
+class JsMirror implements Mirror {
+ noSuchMethod(Invocation i) {
+ _unimplemented(this.runtimeType, i);
+ }
+}
+
+class JsCombinatorMirror extends JsMirror implements CombinatorMirror {}
+
+class JsDeclarationMirror extends JsMirror implements DeclarationMirror {}
+
+class JsIsolateMirror extends JsMirror implements IsolateMirror {}
+
+class JsLibraryDependencyMirror extends JsMirror
+ implements LibraryDependencyMirror {}
+
+class JsObjectMirror extends JsMirror implements ObjectMirror {}
+
+class JsInstanceMirror extends JsObjectMirror implements InstanceMirror {
+ // Reflected object
+ final reflectee;
+ bool get hasReflectee => true;
+
+ ClassMirror get type {
+ // The spec guarantees that `null` is the singleton instance of the `Null`
+ // class.
+ if (reflectee == null) return reflectClass(Null);
+ return reflectType(_runtimeType(reflectee));
+ }
+
+ JsInstanceMirror._(this.reflectee);
+
+ bool operator ==(Object other) {
+ return (other is JsInstanceMirror) && identical(reflectee, other.reflectee);
+ }
+
+ int get hashCode {
+ // Avoid hash collisions with the reflectee. This constant is in Smi range
+ // and happens to be the inner padding from RFC 2104.
+ return identityHashCode(reflectee) ^ 0x36363636;
+ }
+
+ InstanceMirror getField(Symbol symbol) {
+ var name = _getMember(symbol);
+ var field = dart.dloadMirror(reflectee, name);
+ return reflect(field);
+ }
+
+ InstanceMirror setField(Symbol symbol, Object value) {
+ var name = _getMember(symbol);
+ dart.dputMirror(reflectee, name, value);
+ return reflect(value);
+ }
+
+ InstanceMirror invoke(Symbol symbol, List<dynamic> args,
+ [Map<Symbol, dynamic> namedArgs]) {
+ var name = _getMember(symbol);
+ var result =
+ dart.callMethod(reflectee, name, null, args, _toJsMap(namedArgs), name);
+ return reflect(result);
+ }
+
+ String toString() => "InstanceMirror on '$reflectee'";
+}
+
+class JsClosureMirror extends JsInstanceMirror implements ClosureMirror {
+ JsClosureMirror._(reflectee) : super._(reflectee);
+
+ InstanceMirror apply(List<dynamic> args, [Map<Symbol, dynamic> namedArgs]) {
+ var result = dart.dcall(reflectee, args, _toJsMap(namedArgs));
+ return reflect(result);
+ }
+}
+
+// For generic classes, mirrors uses the same representation, [ClassMirror],
+// for the instantiated and uninstantiated type. Somewhat awkwardly, most APIs
+// (e.g., [newInstance]) treat the uninstantiated type as if instantiated
+// with all dynamic. The representation below is correspondingly a bit wonky.
+// For an uninstantiated generic class, [_cls] is the instantiated type (with
+// dynamic) and [_raw] is null. For an instantiated generic class, [_cls] is
+// the instantiated type (with the corresponding type parameters), and [_raw]
+// is the generic factory.
+class JsClassMirror extends JsMirror implements ClassMirror {
+ final Type _cls;
+ final Symbol simpleName;
+ // Generic class factory for instantiated types.
+ final dynamic _raw;
+
+ ClassMirror _originalDeclaration;
+
+ // TODO(vsm): Do this properly
+ ClassMirror _mixin = null;
+ List<TypeMirror> _typeArguments;
+
+ List<InstanceMirror> _metadata;
+ Map<Symbol, DeclarationMirror> _declarations;
+
+ List<InstanceMirror> get metadata {
+ if (_metadata == null) {
+ // Load metadata.
+ var unwrapped = dart.unwrapType(_cls);
+ // Only get metadata directly embedded on this class, not its
+ // superclasses.
+ Function fn = JS(
+ '',
+ 'Object.hasOwnProperty.call(#, dart.metadata) ? #[dart.metadata] : null',
+ unwrapped,
+ unwrapped);
+ _metadata = (fn == null)
+ ? const <InstanceMirror>[]
+ : List<InstanceMirror>.unmodifiable(fn().map((i) => reflect(i)));
+ }
+ return _metadata;
+ }
+
+ Map<Symbol, DeclarationMirror> get declarations {
+ if (_declarations == null) {
+ // Load declarations.
+ // TODO(vsm): This is only populating the default constructor right now.
+ _declarations = Map<Symbol, DeclarationMirror>();
+ var unwrapped = dart.unwrapType(_cls);
+ var constructors = _toDartMap(dart.getConstructors(unwrapped));
+ constructors.forEach((symbol, ft) {
+ var name = getName(symbol);
+ _declarations[symbol] = JsMethodMirror._constructor(this, symbol, ft);
+ });
+ if (constructors.isEmpty) {
+ // Add a default
+ var name = 'new';
+ var ft = dart.fnType(dart.unwrapType(_cls), []);
+ var symbol = Symbol(name);
+ _declarations[symbol] = JsMethodMirror._constructor(this, symbol, ft);
+ }
+ var fields = _toDartMap(dart.getFields(unwrapped));
+ fields.forEach((symbol, t) {
+ _declarations[symbol] = JsVariableMirror._fromField(symbol, t);
+ });
+ var methods = _toDartMap(dart.getMethods(unwrapped));
+ methods.forEach((symbol, ft) {
+ var name = getName(symbol);
+ _declarations[symbol] =
+ JsMethodMirror._instanceMethod(this, symbol, ft);
+ });
+
+ getterType(type) {
+ if (JS<bool>('!', '# instanceof Array', type)) {
+ var array = JS('', '#.slice()', type);
+ type = JS('', '#[0]', array);
+ JS('', '#[0] = #', array, dart.fnType(type, []));
+ return array;
+ } else {
+ return dart.fnType(type, []);
+ }
+ }
+
+ var getters = _toDartMap(dart.getGetters(unwrapped));
+ getters.forEach((symbol, type) {
+ _declarations[symbol] =
+ JsMethodMirror._instanceMethod(this, symbol, getterType(type));
+ });
+
+ setterType(type) {
+ if (JS<bool>('!', '# instanceof Array', type)) {
+ var array = JS('', '#.slice()', type);
+ type = JS('', '#[0]', array);
+ JS('', '#[0] = #', array, dart.fnType(dart.void_, [type]));
+ return array;
+ } else {
+ return dart.fnType(dart.void_, [type]);
+ }
+ }
+
+ var setters = _toDartMap(dart.getSetters(unwrapped));
+ setters.forEach((symbol, type) {
+ var name = getName(symbol) + '=';
+ // Create a separate symbol for the setter.
+ symbol = PrivateSymbol(name, _getESSymbol(symbol));
+ _declarations[symbol] =
+ JsMethodMirror._instanceMethod(this, symbol, setterType(type));
+ });
+
+ var staticFields = _toDartMap(dart.getStaticFields(unwrapped));
+ staticFields.forEach((symbol, t) {
+ _declarations[symbol] = JsVariableMirror._fromField(symbol, t);
+ });
+ var statics = _toDartMap(dart.getStaticMethods(unwrapped));
+ statics.forEach((symbol, ft) {
+ _declarations[symbol] = JsMethodMirror._staticMethod(this, symbol, ft);
+ });
+
+ var staticGetters = _toDartMap(dart.getStaticGetters(unwrapped));
+ staticGetters.forEach((symbol, type) {
+ _declarations[symbol] =
+ JsMethodMirror._staticMethod(this, symbol, getterType(type));
+ });
+
+ var staticSetters = _toDartMap(dart.getStaticSetters(unwrapped));
+ staticSetters.forEach((symbol, type) {
+ _declarations[symbol] =
+ JsMethodMirror._staticMethod(this, symbol, setterType(type));
+ });
+ _declarations =
+ Map<Symbol, DeclarationMirror>.unmodifiable(_declarations);
+ }
+ return _declarations;
+ }
+
+ JsClassMirror._(Type cls, {bool instantiated = true})
+ : _cls = cls,
+ _raw = instantiated ? dart.getGenericClass(dart.unwrapType(cls)) : null,
+ simpleName = Symbol(JS<String>('!', '#.name', dart.unwrapType(cls))) {
+ var typeArgs = dart.getGenericArgs(dart.unwrapType(_cls));
+ if (typeArgs == null) {
+ _typeArguments = const [];
+ } else {
+ _typeArguments =
+ List.unmodifiable(typeArgs.map((t) => reflectType(dart.wrapType(t))));
+ }
+ }
+
+ InstanceMirror newInstance(Symbol constructorName, List args,
+ [Map<Symbol, dynamic> namedArgs]) {
+ // TODO(vsm): Support named arguments.
+ var name = getName(constructorName);
+ assert(namedArgs == null || namedArgs.isEmpty);
+ // Default constructors are mapped to new.
+ if (name == '') name = 'new';
+ var cls = dart.unwrapType(_cls);
+ var ctr = JS('', '#.#', cls, name);
+ // Only generative Dart constructors are wired up as real JS constructors.
+ var instance = JS<bool>('!', '#.prototype == #.prototype', cls, ctr)
+ // Generative
+ ? JS('', 'new #(...#)', ctr, args)
+ // Factory
+ : JS('', '#(...#)', ctr, args);
+ return reflect(instance);
+ }
+
+ // TODO(vsm): Need to check for NSM, types on accessors below. Unlike the
+ // InstanceMirror case, there is no dynamic helper to delegate to - we never
+ // need a dload, etc. on a static.
+
+ InstanceMirror getField(Symbol symbol) {
+ var name = getName(symbol);
+ return reflect(JS('', '#[#]', dart.unwrapType(_cls), name));
+ }
+
+ InstanceMirror setField(Symbol symbol, Object value) {
+ var name = getName(symbol);
+ JS('', '#[#] = #', dart.unwrapType(_cls), name, value);
+ return reflect(value);
+ }
+
+ InstanceMirror invoke(Symbol symbol, List<dynamic> args,
+ [Map<Symbol, dynamic> namedArgs]) {
+ var name = getName(symbol);
+ if (namedArgs != null) {
+ args = List.from(args);
+ args.add(_toJsMap(namedArgs));
+ }
+ var result = JS('', '#.#(...#)', dart.unwrapType(_cls), name, args);
+ return reflect(result);
+ }
+
+ List<ClassMirror> get superinterfaces {
+ _Lazy<List<Type>> interfaceThunk =
+ JS('', '#[dart.implements]', dart.unwrapType(_cls));
+ if (interfaceThunk == null) {
+ return [];
+ } else {
+ List<Type> interfaces = interfaceThunk();
+ return interfaces.map((t) => reflectType(t)).toList();
+ }
+ }
+
+ bool get hasReflectedType => true;
+ Type get reflectedType {
+ return _cls;
+ }
+
+ bool get isOriginalDeclaration => _raw == null;
+
+ List<TypeMirror> get typeArguments => _typeArguments;
+
+ TypeMirror get originalDeclaration {
+ if (_raw == null) {
+ return this;
+ }
+ if (_originalDeclaration != null) {
+ return _originalDeclaration;
+ }
+ _originalDeclaration = JsClassMirror._(dart.wrapType(JS('', '#()', _raw)),
+ instantiated: false);
+ return _originalDeclaration;
+ }
+
+ ClassMirror get superclass {
+ if (_cls == Object) {
+ return null;
+ } else {
+ return reflectType(
+ dart.wrapType(JS<Type>('!', '#.__proto__', dart.unwrapType(_cls))));
+ }
+ }
+
+ ClassMirror get mixin {
+ if (_mixin != null) {
+ return _mixin;
+ }
+ var mixin = dart.getMixin(dart.unwrapType(_cls));
+ if (mixin == null) {
+ // If there is no mixin, return this mirror per API.
+ _mixin = this;
+ return _mixin;
+ }
+ _mixin = reflectType(dart.wrapType(mixin));
+ return _mixin;
+ }
+
+ String toString() => "ClassMirror on '$_cls'";
+}
+
+class JsVariableMirror extends JsMirror implements VariableMirror {
+ final Symbol _symbol;
+ final String _name;
+ final TypeMirror type;
+ final List<InstanceMirror> metadata;
+ final bool isFinal;
+
+ // TODO(vsm): Refactor this out.
+ Symbol get simpleName => _symbol;
+
+ // TODO(vsm): Fix this
+ final bool isStatic = false;
+
+ JsVariableMirror._(Symbol symbol, Type t, List annotations,
+ {this.isFinal = false})
+ : _symbol = symbol,
+ _name = getName(symbol),
+ type = reflectType(t),
+ metadata =
+ List<InstanceMirror>.unmodifiable(annotations?.map(reflect) ?? []);
+
+ JsVariableMirror._fromField(Symbol symbol, fieldInfo)
+ : this._(symbol, dart.wrapType(JS('', '#.type', fieldInfo)),
+ JS('', '#.metadata', fieldInfo),
+ isFinal: JS<bool>('!', '#.isFinal', fieldInfo));
+
+ String toString() => "VariableMirror on '$_name'";
+}
+
+class JsParameterMirror extends JsVariableMirror implements ParameterMirror {
+ JsParameterMirror._(Symbol member, Type t, List annotations)
+ : super._(member, t, annotations);
+
+ String toString() => "ParameterMirror on '$_name'";
+}
+
+class JsMethodMirror extends JsMirror implements MethodMirror {
+ final Symbol _symbol;
+ final String _name;
+ List<ParameterMirror> _params;
+ List<InstanceMirror> _metadata;
+ final bool isConstructor;
+ final bool isStatic;
+
+ // TODO(vsm): Fix this
+ final bool isFinal = false;
+ bool get isSetter => _name.endsWith('=');
+ bool get isPrivate => _name.startsWith('_');
+
+ // TODO(vsm): Refactor this out.
+ Symbol get simpleName => _symbol;
+
+ JsMethodMirror._constructor(JsClassMirror cls, Symbol symbol, ftype)
+ : _symbol = symbol,
+ _name = getName(symbol),
+ isConstructor = true,
+ isStatic = false {
+ _createParameterMirrorList(ftype);
+ }
+
+ JsMethodMirror._instanceMethod(JsClassMirror cls, Symbol symbol, ftype)
+ : _symbol = symbol,
+ _name = getName(symbol),
+ isConstructor = false,
+ isStatic = false {
+ _createParameterMirrorList(ftype);
+ }
+
+ JsMethodMirror._staticMethod(JsClassMirror cls, Symbol symbol, ftype)
+ : _symbol = symbol,
+ _name = getName(symbol),
+ isConstructor = false,
+ isStatic = true {
+ _createParameterMirrorList(ftype);
+ }
+
+ // TODO(vsm): Support named constructors.
+ Symbol get constructorName => isConstructor ? _symbol : null;
+ List<ParameterMirror> get parameters => _params;
+ List<InstanceMirror> get metadata => _metadata;
+
+ void _createParameterMirrorList(ftype) {
+ if (ftype == null) {
+ // TODO(vsm): No explicit constructor. Verify this.
+ _params = const [];
+ _metadata = const [];
+ return;
+ }
+
+ // TODO(vsm): Why does generic function type trigger true for List?
+ if (ftype is! Function && ftype is List) {
+ // Record metadata
+ _metadata = List<InstanceMirror>.unmodifiable(
+ ftype.skip(1).map((a) => reflect(a)));
+ ftype = ftype[0];
+ } else {
+ _metadata = const [];
+ }
+
+ // TODO(vsm): Handle generic function types properly. Or deprecate mirrors
+ // before we need to!
+ ftype = dart.getFunctionTypeMirror(ftype);
+
+ // TODO(vsm): Add named args.
+ List args = ftype.args;
+ List opts = ftype.optionals;
+ var params = List<ParameterMirror>(args.length + opts.length);
+
+ for (var i = 0; i < args.length; ++i) {
+ var type = args[i];
+ var metadata = ftype.metadata[i];
+ // TODO(vsm): Recover the param name.
+ var param =
+ JsParameterMirror._(Symbol(''), dart.wrapType(type), metadata);
+ params[i] = param;
+ }
+
+ for (var i = 0; i < opts.length; ++i) {
+ var type = opts[i];
+ var metadata = ftype.metadata[args.length + i];
+ // TODO(vsm): Recover the param name.
+ var param =
+ JsParameterMirror._(Symbol(''), dart.wrapType(type), metadata);
+ params[i + args.length] = param;
+ }
+
+ _params = List.unmodifiable(params);
+ }
+
+ String toString() => "MethodMirror on '$_name'";
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_number.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_number.dart
new file mode 100644
index 0000000..5f8c7e0
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_number.dart
@@ -0,0 +1,627 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._interceptors;
+
+/**
+ * The implementation of Dart's int & double methods.
+ * These are made available as extension methods on `Number` in JS.
+ */
+@JsPeerInterface(name: 'Number')
+class JSNumber extends Interceptor implements int, double {
+ const JSNumber();
+
+ @notNull
+ int compareTo(@nullCheck num b) {
+ if (this < b) {
+ return -1;
+ } else if (this > b) {
+ return 1;
+ } else if (this == b) {
+ if (this == 0) {
+ bool bIsNegative = b.isNegative;
+ if (isNegative == bIsNegative) return 0;
+ if (isNegative) return -1;
+ return 1;
+ }
+ return 0;
+ } else if (isNaN) {
+ if (b.isNaN) {
+ return 0;
+ }
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+
+ @notNull
+ bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0;
+
+ @notNull
+ bool get isNaN => JS<bool>('!', r'isNaN(#)', this);
+
+ @notNull
+ bool get isInfinite {
+ return JS<bool>('!', r'# == (1/0)', this) ||
+ JS<bool>('!', r'# == (-1/0)', this);
+ }
+
+ @notNull
+ bool get isFinite => JS<bool>('!', r'isFinite(#)', this);
+
+ @notNull
+ JSNumber remainder(@nullCheck num b) {
+ return JS<num>('!', r'# % #', this, b);
+ }
+
+ @notNull
+ JSNumber abs() => JS<num>('!', r'Math.abs(#)', this);
+
+ @notNull
+ JSNumber get sign => this > 0 ? 1 : this < 0 ? -1 : this;
+
+ @notNull
+ static const int _MIN_INT32 = -0x80000000;
+ @notNull
+ static const int _MAX_INT32 = 0x7FFFFFFF;
+
+ @notNull
+ int toInt() {
+ if (this >= _MIN_INT32 && this <= _MAX_INT32) {
+ return JS<int>('!', '# | 0', this);
+ }
+ if (JS<bool>('!', r'isFinite(#)', this)) {
+ return JS<int>(
+ '!', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0.
+ }
+ // This is either NaN, Infinity or -Infinity.
+ throw UnsupportedError(JS("String", '"" + #', this));
+ }
+
+ @notNull
+ int truncate() => toInt();
+
+ @notNull
+ int ceil() => ceilToDouble().toInt();
+
+ @notNull
+ int floor() => floorToDouble().toInt();
+
+ @notNull
+ int round() {
+ if (this > 0) {
+ // This path excludes the special cases -0.0, NaN and -Infinity, leaving
+ // only +Infinity, for which a direct test is faster than [isFinite].
+ if (JS<bool>('!', r'# !== (1/0)', this)) {
+ return JS<int>('!', r'Math.round(#)', this);
+ }
+ } else if (JS<bool>('!', '# > (-1/0)', this)) {
+ // This test excludes NaN and -Infinity, leaving only -0.0.
+ //
+ // Subtraction from zero rather than negation forces -0.0 to 0.0 so code
+ // inside Math.round and code to handle result never sees -0.0, which on
+ // some JavaScript VMs can be a slow path.
+ return JS<int>('!', r'0 - Math.round(0 - #)', this);
+ }
+ // This is either NaN, Infinity or -Infinity.
+ throw UnsupportedError(JS("String", '"" + #', this));
+ }
+
+ @notNull
+ double ceilToDouble() => JS<num>('!', r'Math.ceil(#)', this);
+
+ @notNull
+ double floorToDouble() => JS<num>('!', r'Math.floor(#)', this);
+
+ @notNull
+ double roundToDouble() {
+ if (this < 0) {
+ return JS<num>('!', r'-Math.round(-#)', this);
+ } else {
+ return JS<num>('!', r'Math.round(#)', this);
+ }
+ }
+
+ @notNull
+ double truncateToDouble() => this < 0 ? ceilToDouble() : floorToDouble();
+
+ @notNull
+ num clamp(@nullCheck num lowerLimit, @nullCheck num upperLimit) {
+ if (lowerLimit.compareTo(upperLimit) > 0) {
+ throw argumentErrorValue(lowerLimit);
+ }
+ if (this.compareTo(lowerLimit) < 0) return lowerLimit;
+ if (this.compareTo(upperLimit) > 0) return upperLimit;
+ return this;
+ }
+
+ @notNull
+ double toDouble() => this;
+
+ @notNull
+ String toStringAsFixed(@notNull int fractionDigits) {
+ if (fractionDigits < 0 || fractionDigits > 20) {
+ throw RangeError.range(fractionDigits, 0, 20, "fractionDigits");
+ }
+ String result = JS<String>('!', r'#.toFixed(#)', this, fractionDigits);
+ if (this == 0 && isNegative) return "-$result";
+ return result;
+ }
+
+ @notNull
+ String toStringAsExponential([int fractionDigits]) {
+ String result;
+ if (fractionDigits != null) {
+ @notNull
+ var _fractionDigits = fractionDigits;
+ if (_fractionDigits < 0 || _fractionDigits > 20) {
+ throw RangeError.range(_fractionDigits, 0, 20, "fractionDigits");
+ }
+ result = JS<String>('!', r'#.toExponential(#)', this, _fractionDigits);
+ } else {
+ result = JS<String>('!', r'#.toExponential()', this);
+ }
+ if (this == 0 && isNegative) return "-$result";
+ return result;
+ }
+
+ @notNull
+ String toStringAsPrecision(@nullCheck int precision) {
+ if (precision < 1 || precision > 21) {
+ throw RangeError.range(precision, 1, 21, "precision");
+ }
+ String result = JS<String>('!', r'#.toPrecision(#)', this, precision);
+ if (this == 0 && isNegative) return "-$result";
+ return result;
+ }
+
+ @notNull
+ String toRadixString(@nullCheck int radix) {
+ if (radix < 2 || radix > 36) {
+ throw RangeError.range(radix, 2, 36, "radix");
+ }
+ String result = JS<String>('!', r'#.toString(#)', this, radix);
+ const int rightParenCode = 0x29;
+ if (result.codeUnitAt(result.length - 1) != rightParenCode) {
+ return result;
+ }
+ return _handleIEtoString(result);
+ }
+
+ @notNull
+ static String _handleIEtoString(String result) {
+ // Result is probably IE's untraditional format for large numbers,
+ // e.g., "8.0000000000008(e+15)" for 0x8000000000000800.toString(16).
+ var match = JS<List>(
+ '', r'/^([\da-z]+)(?:\.([\da-z]+))?\(e\+(\d+)\)$/.exec(#)', result);
+ if (match == null) {
+ // Then we don't know how to handle it at all.
+ throw UnsupportedError("Unexpected toString result: $result");
+ }
+ result = JS('!', '#', match[1]);
+ int exponent = JS("!", "+#", match[3]);
+ if (match[2] != null) {
+ result = JS('!', '# + #', result, match[2]);
+ exponent -= JS<int>('!', '#.length', match[2]);
+ }
+ return result + "0" * exponent;
+ }
+
+ // Note: if you change this, also change the function [S].
+ @notNull
+ String toString() {
+ if (this == 0 && JS<bool>('!', '(1 / #) < 0', this)) {
+ return '-0.0';
+ } else {
+ return JS<String>('!', r'"" + (#)', this);
+ }
+ }
+
+ @notNull
+ int get hashCode {
+ int intValue = JS<int>('!', '# | 0', this);
+ // Fast exit for integers in signed 32-bit range. Masking converts -0.0 to 0
+ // and ensures that result fits in JavaScript engine's Smi range.
+ if (this == intValue) return 0x1FFFFFFF & intValue;
+
+ // We would like to access the exponent and mantissa as integers but there
+ // are no JavaScript operations that do this, so use log2-floor-pow-divide
+ // to extract the values.
+ num absolute = JS<num>('!', 'Math.abs(#)', this);
+ num lnAbsolute = JS<num>('!', 'Math.log(#)', absolute);
+ num log2 = lnAbsolute / ln2;
+ // Floor via '# | 0' converts NaN to zero so the final result is not NaN.
+ int floorLog2 = JS<int>('!', '# | 0', log2);
+ num factor = JS<num>('!', 'Math.pow(2, #)', floorLog2);
+ num scaled = absolute < 1 ? absolute / factor : factor / absolute;
+ // [scaled] is in the range [0.5, 1].
+
+ // Multiply and truncate to pick up all the mantissa bits. Multiplying by
+ // 0x20000000000000 (which has 53 zero bits) converts the mantissa into an
+ // integer. There are interesting subsets where all the bit variance is in
+ // the most significant bits of the mantissa (e.g. 0.5, 0.625, 0.75), so we
+ // need to mix in the most significant bits. We do this by scaling with a
+ // constant that has many bits set to use the multiplier to mix in bits from
+ // all over the mantissa into low positions.
+ num rescaled1 = scaled * 0x20000000000000;
+ num rescaled2 = scaled * 0x0C95A6C285A6C9;
+ int d1 = JS<int>('!', '# | 0', rescaled1);
+ int d2 = JS<int>('!', '# | 0', rescaled2);
+ // Mix in exponent to distinguish e.g. 1.25 from 2.5.
+ int d3 = floorLog2;
+ int h = 0x1FFFFFFF & ((d1 + d2) * (601 * 997) + d3 * (1259));
+ return h;
+ }
+
+ @notNull
+ JSNumber operator -() => JS<num>('!', r'-#', this);
+
+ @notNull
+ JSNumber operator +(@nullCheck num other) {
+ return JS<num>('!', '# + #', this, other);
+ }
+
+ @notNull
+ JSNumber operator -(@nullCheck num other) {
+ return JS<num>('!', '# - #', this, other);
+ }
+
+ @notNull
+ double operator /(@nullCheck num other) {
+ return JS<num>('!', '# / #', this, other);
+ }
+
+ @notNull
+ JSNumber operator *(@nullCheck num other) {
+ return JS<num>('!', '# * #', this, other);
+ }
+
+ @notNull
+ JSNumber operator %(@nullCheck num other) {
+ // Euclidean Modulo.
+ num result = JS<num>('!', r'# % #', this, other);
+ if (result == 0) return (0 as JSNumber); // Make sure we don't return -0.0.
+ if (result > 0) return result;
+ if (JS<num>('!', '#', other) < 0) {
+ return result - JS<num>('!', '#', other);
+ } else {
+ return result + JS<num>('!', '#', other);
+ }
+ }
+
+ @notNull
+ bool _isInt32(@notNull num value) =>
+ JS<bool>('!', '(# | 0) === #', value, value);
+
+ @notNull
+ int operator ~/(@nullCheck num other) {
+ if (_isInt32(this) && _isInt32(other) && 0 != other && -1 != other) {
+ return JS<int>('!', r'(# / #) | 0', this, other);
+ } else {
+ return _tdivSlow(other);
+ }
+ }
+
+ @notNull
+ int _tdivSlow(num other) {
+ return (JS<num>('!', r'# / #', this, other)).toInt();
+ }
+
+ // TODO(ngeoffray): Move the bit operations below to [JSInt] and
+ // make them take an int. Because this will make operations slower,
+ // we define these methods on number for now but we need to decide
+ // the grain at which we do the type checks.
+
+ @notNull
+ int operator <<(@nullCheck num other) {
+ if (other < 0) throwArgumentErrorValue(other);
+ return _shlPositive(other);
+ }
+
+ @notNull
+ int _shlPositive(@notNull num other) {
+ // JavaScript only looks at the last 5 bits of the shift-amount. Shifting
+ // by 33 is hence equivalent to a shift by 1.
+ return JS<bool>('!', r'# > 31', other)
+ ? 0
+ : JS<int>('!', r'(# << #) >>> 0', this, other);
+ }
+
+ @notNull
+ int operator >>(@nullCheck num other) {
+ if (JS<num>('!', '#', other) < 0) throwArgumentErrorValue(other);
+ return _shrOtherPositive(other);
+ }
+
+ @notNull
+ int _shrOtherPositive(@notNull num other) {
+ return JS<num>('!', '#', this) > 0
+ ? _shrBothPositive(other)
+ // For negative numbers we just clamp the shift-by amount.
+ // `this` could be negative but not have its 31st bit set.
+ // The ">>" would then shift in 0s instead of 1s. Therefore
+ // we cannot simply return 0xFFFFFFFF.
+ : JS<int>('!', r'(# >> #) >>> 0', this, other > 31 ? 31 : other);
+ }
+
+ @notNull
+ int _shrBothPositive(@notNull num other) {
+ return JS<bool>('!', r'# > 31', other)
+ // JavaScript only looks at the last 5 bits of the shift-amount. In JS
+ // shifting by 33 is hence equivalent to a shift by 1. Shortcut the
+ // computation when that happens.
+ ? 0
+ // Given that `this` is positive we must not use '>>'. Otherwise a
+ // number that has the 31st bit set would be treated as negative and
+ // shift in ones.
+ : JS<int>('!', r'# >>> #', this, other);
+ }
+
+ @notNull
+ int operator &(@nullCheck num other) {
+ return JS<int>('!', r'(# & #) >>> 0', this, other);
+ }
+
+ @notNull
+ int operator |(@nullCheck num other) {
+ return JS<int>('!', r'(# | #) >>> 0', this, other);
+ }
+
+ @notNull
+ int operator ^(@nullCheck num other) {
+ return JS<int>('!', r'(# ^ #) >>> 0', this, other);
+ }
+
+ @notNull
+ bool operator <(@nullCheck num other) {
+ return JS<bool>('!', '# < #', this, other);
+ }
+
+ @notNull
+ bool operator >(@nullCheck num other) {
+ return JS<bool>('!', '# > #', this, other);
+ }
+
+ @notNull
+ bool operator <=(@nullCheck num other) {
+ return JS<bool>('!', '# <= #', this, other);
+ }
+
+ @notNull
+ bool operator >=(@nullCheck num other) {
+ return JS<bool>('!', '# >= #', this, other);
+ }
+
+ // int members.
+ // TODO(jmesserly): all numbers will have these in dynamic dispatch.
+ // We can fix by checking it at dispatch time but we'd need to structure them
+ // differently.
+
+ @notNull
+ bool get isEven => (this & 1) == 0;
+
+ @notNull
+ bool get isOdd => (this & 1) == 1;
+
+ @notNull
+ int toUnsigned(@nullCheck int width) {
+ return this & ((1 << width) - 1);
+ }
+
+ @notNull
+ int toSigned(@nullCheck int width) {
+ int signMask = 1 << (width - 1);
+ return (this & (signMask - 1)) - (this & signMask);
+ }
+
+ @notNull
+ int get bitLength {
+ int nonneg = this < 0 ? -this - 1 : this;
+ int wordBits = 32;
+ while (nonneg >= 0x100000000) {
+ nonneg = nonneg ~/ 0x100000000;
+ wordBits += 32;
+ }
+ return wordBits - _clz32(nonneg);
+ }
+
+ @notNull
+ static int _clz32(@notNull int uint32) {
+ // TODO(sra): Use `Math.clz32(uint32)` (not available on IE11).
+ return 32 - _bitCount(_spread(uint32));
+ }
+
+ // Returns pow(this, e) % m.
+ @notNull
+ int modPow(@nullCheck int e, @nullCheck int m) {
+ if (e < 0) throw RangeError.range(e, 0, null, "exponent");
+ if (m <= 0) throw RangeError.range(m, 1, null, "modulus");
+ if (e == 0) return 1;
+
+ const int maxPreciseInteger = 9007199254740991;
+
+ // Reject inputs that are outside the range of integer values that can be
+ // represented precisely as a Number (double).
+ if (this < -maxPreciseInteger || this > maxPreciseInteger) {
+ throw RangeError.range(
+ this, -maxPreciseInteger, maxPreciseInteger, 'receiver');
+ }
+ if (e > maxPreciseInteger) {
+ throw RangeError.range(e, 0, maxPreciseInteger, 'exponent');
+ }
+ if (m > maxPreciseInteger) {
+ throw RangeError.range(e, 1, maxPreciseInteger, 'modulus');
+ }
+
+ // This is floor(sqrt(maxPreciseInteger)).
+ const int maxValueThatCanBeSquaredWithoutTruncation = 94906265;
+ if (m > maxValueThatCanBeSquaredWithoutTruncation) {
+ // Use BigInt version to avoid truncation in multiplications below. The
+ // 'maxPreciseInteger' check on [m] ensures that toInt() does not round.
+ return BigInt.from(this).modPow(BigInt.from(e), BigInt.from(m)).toInt();
+ }
+
+ int b = this;
+ if (b < 0 || b > m) {
+ b %= m;
+ }
+ int r = 1;
+ while (e > 0) {
+ if (e.isOdd) {
+ r = (r * b) % m;
+ }
+ e ~/= 2;
+ b = (b * b) % m;
+ }
+ return r;
+ }
+
+ // If inv is false, returns gcd(x, y).
+ // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
+ // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
+ @notNull
+ static int _binaryGcd(@notNull int x, @notNull int y, @notNull bool inv) {
+ int s = 1;
+ if (!inv) {
+ while (x.isEven && y.isEven) {
+ x ~/= 2;
+ y ~/= 2;
+ s *= 2;
+ }
+ if (y.isOdd) {
+ var t = x;
+ x = y;
+ y = t;
+ }
+ }
+ final bool ac = x.isEven;
+ int u = x;
+ int v = y;
+ int a = 1, b = 0, c = 0, d = 1;
+ do {
+ while (u.isEven) {
+ u ~/= 2;
+ if (ac) {
+ if (!a.isEven || !b.isEven) {
+ a += y;
+ b -= x;
+ }
+ a ~/= 2;
+ } else if (!b.isEven) {
+ b -= x;
+ }
+ b ~/= 2;
+ }
+ while (v.isEven) {
+ v ~/= 2;
+ if (ac) {
+ if (!c.isEven || !d.isEven) {
+ c += y;
+ d -= x;
+ }
+ c ~/= 2;
+ } else if (!d.isEven) {
+ d -= x;
+ }
+ d ~/= 2;
+ }
+ if (u >= v) {
+ u -= v;
+ if (ac) a -= c;
+ b -= d;
+ } else {
+ v -= u;
+ if (ac) c -= a;
+ d -= b;
+ }
+ } while (u != 0);
+ if (!inv) return s * v;
+ if (v != 1) throw Exception("Not coprime");
+ if (d < 0) {
+ d += x;
+ if (d < 0) d += x;
+ } else if (d > x) {
+ d -= x;
+ if (d > x) d -= x;
+ }
+ return d;
+ }
+
+ // Returns 1/this % m, with m > 0.
+ @notNull
+ int modInverse(@nullCheck int m) {
+ if (m <= 0) throw RangeError.range(m, 1, null, "modulus");
+ if (m == 1) return 0;
+ int t = this;
+ if ((t < 0) || (t >= m)) t %= m;
+ if (t == 1) return 1;
+ if ((t == 0) || (t.isEven && m.isEven)) {
+ throw Exception("Not coprime");
+ }
+ return _binaryGcd(m, t, true);
+ }
+
+ // Returns gcd of abs(this) and abs(other).
+ @notNull
+ int gcd(@nullCheck int other) {
+ int x = this.abs();
+ int y = other.abs();
+ if (x == 0) return y;
+ if (y == 0) return x;
+ if ((x == 1) || (y == 1)) return 1;
+ return _binaryGcd(x, y, false);
+ }
+
+ // Assumes i is <= 32-bit and unsigned.
+ @notNull
+ static int _bitCount(@notNull int i) {
+ // See "Hacker's Delight", section 5-1, "Counting 1-Bits".
+
+ // The basic strategy is to use "divide and conquer" to
+ // add pairs (then quads, etc.) of bits together to obtain
+ // sub-counts.
+ //
+ // A straightforward approach would look like:
+ //
+ // i = (i & 0x55555555) + ((i >> 1) & 0x55555555);
+ // i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
+ // i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F);
+ // i = (i & 0x00FF00FF) + ((i >> 8) & 0x00FF00FF);
+ // i = (i & 0x0000FFFF) + ((i >> 16) & 0x0000FFFF);
+ //
+ // The code below removes unnecessary &'s and uses a
+ // trick to remove one instruction in the first line.
+
+ i = _shru(i, 0) - (_shru(i, 1) & 0x55555555);
+ i = (i & 0x33333333) + (_shru(i, 2) & 0x33333333);
+ i = 0x0F0F0F0F & (i + _shru(i, 4));
+ i += _shru(i, 8);
+ i += _shru(i, 16);
+ return (i & 0x0000003F);
+ }
+
+ @notNull
+ static int _shru(int value, int shift) =>
+ JS<int>('!', '# >>> #', value, shift);
+ @notNull
+ static int _shrs(int value, int shift) =>
+ JS<int>('!', '# >> #', value, shift);
+ @notNull
+ static int _ors(int a, int b) => JS<int>('!', '# | #', a, b);
+
+ // Assumes i is <= 32-bit
+ @notNull
+ static int _spread(@notNull int i) {
+ i = _ors(i, _shrs(i, 1));
+ i = _ors(i, _shrs(i, 2));
+ i = _ors(i, _shrs(i, 4));
+ i = _ors(i, _shrs(i, 8));
+ i = _shru(_ors(i, _shrs(i, 16)), 0);
+ return i;
+ }
+
+ @notNull
+ int operator ~() => JS<int>('!', r'(~#) >>> 0', this);
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_primitives.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_primitives.dart
new file mode 100644
index 0000000..1347b62
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_primitives.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// dart2js "primitives", that is, features that cannot be implemented without
+/// access to JavaScript features.
+library dart2js._js_primitives;
+
+import 'dart:_foreign_helper' show JS;
+
+/**
+ * This is the low-level method that is used to implement [print]. It is
+ * possible to override this function from JavaScript by defining a function in
+ * JavaScript called "dartPrint".
+ *
+ * Notice that it is also possible to intercept calls to [print] from within a
+ * Dart program using zones. This means that there is no guarantee that a call
+ * to print ends in this method.
+ */
+void printString(String string) {
+ if (JS<bool>('!', r'typeof dartPrint == "function"')) {
+ // Support overriding print from JavaScript.
+ JS('void', r'dartPrint(#)', string);
+ return;
+ }
+
+ // Inside browser or nodejs.
+ if (JS<bool>('!', r'typeof console == "object"') &&
+ JS<bool>('!', r'typeof console.log != "undefined"')) {
+ JS('void', r'console.log(#)', string);
+ return;
+ }
+
+ // Don't throw inside IE, the console is only defined if dev tools is open.
+ if (JS<bool>('!', r'typeof window == "object"')) {
+ return;
+ }
+
+ // Running in d8, the V8 developer shell, or in Firefox' js-shell.
+ if (JS<bool>('!', r'typeof print == "function"')) {
+ JS('void', r'print(#)', string);
+ return;
+ }
+
+ // This is somewhat nasty, but we don't want to drag in a bunch of
+ // dependencies to handle a situation that cannot happen. So we
+ // avoid using Dart [:throw:] and Dart [toString].
+ JS('void', 'throw "Unable to print message: " + String(#)', string);
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_rti.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_rti.dart
new file mode 100644
index 0000000..015c83e
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_rti.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._js_helper;
+
+// TODO(leafp): Maybe get rid of this? Currently used by the interceptors
+// library, but that should probably be culled as well.
+Type getRuntimeType(var object) =>
+ JS('Type|null', 'dart.getReifiedType(#)', object);
+
+/// Returns the property [index] of the JavaScript array [array].
+getIndex(var array, int index) {
+ assert(isJsArray(array));
+ return JS('var', r'#[#]', array, index);
+}
+
+/// Returns the length of the JavaScript array [array].
+int getLength(var array) {
+ assert(isJsArray(array));
+ return JS<int>('!', r'#.length', array);
+}
+
+/// Returns whether [value] is a JavaScript array.
+bool isJsArray(var value) {
+ return value is JSArray;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_string.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_string.dart
new file mode 100644
index 0000000..4271d34
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_string.dart
@@ -0,0 +1,507 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._interceptors;
+
+/**
+ * The interceptor class for [String]. The compiler recognizes this
+ * class as an interceptor, and changes references to [:this:] to
+ * actually use the receiver of the method, which is generated as an extra
+ * argument added to each member.
+ */
+@JsPeerInterface(name: 'String')
+class JSString extends Interceptor implements String, JSIndexable<String> {
+ const JSString();
+
+ @notNull
+ int codeUnitAt(@nullCheck int index) {
+ // Suppress 2nd null check on index and null check on length
+ // (JS String.length cannot be null).
+ final len = this.length;
+ if (index < 0 || index >= len) {
+ throw RangeError.index(index, this, 'index', null, len);
+ }
+ return JS<int>('!', r'#.charCodeAt(#)', this, index);
+ }
+
+ @notNull
+ Iterable<Match> allMatches(@nullCheck String string,
+ [@nullCheck int start = 0]) {
+ final len = string.length;
+ if (0 > start || start > len) {
+ throw RangeError.range(start, 0, len);
+ }
+ return allMatchesInStringUnchecked(this, string, start);
+ }
+
+ Match matchAsPrefix(@nullCheck String string, [@nullCheck int start = 0]) {
+ int stringLength = JS('!', '#.length', string);
+ if (start < 0 || start > stringLength) {
+ throw RangeError.range(start, 0, stringLength);
+ }
+ int thisLength = JS('!', '#.length', this);
+ if (start + thisLength > stringLength) return null;
+ for (int i = 0; i < thisLength; i++) {
+ if (string.codeUnitAt(start + i) != this.codeUnitAt(i)) {
+ return null;
+ }
+ }
+ return StringMatch(start, string, this);
+ }
+
+ @notNull
+ String operator +(@nullCheck String other) {
+ return JS<String>('!', r'# + #', this, other);
+ }
+
+ @notNull
+ bool endsWith(@nullCheck String other) {
+ var otherLength = other.length;
+ var thisLength = this.length;
+ if (otherLength > thisLength) return false;
+ return other == substring(thisLength - otherLength);
+ }
+
+ @notNull
+ String replaceAll(Pattern from, @nullCheck String to) {
+ return stringReplaceAllUnchecked(this, from, to);
+ }
+
+ @notNull
+ String replaceAllMapped(Pattern from, String convert(Match match)) {
+ return this.splitMapJoin(from, onMatch: convert);
+ }
+
+ @notNull
+ String splitMapJoin(Pattern from,
+ {String onMatch(Match match), String onNonMatch(String nonMatch)}) {
+ return stringReplaceAllFuncUnchecked(this, from, onMatch, onNonMatch);
+ }
+
+ @notNull
+ String replaceFirst(Pattern from, @nullCheck String to,
+ [@nullCheck int startIndex = 0]) {
+ RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex");
+ return stringReplaceFirstUnchecked(this, from, to, startIndex);
+ }
+
+ @notNull
+ String replaceFirstMapped(
+ Pattern from, @nullCheck String replace(Match match),
+ [@nullCheck int startIndex = 0]) {
+ RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex");
+ return stringReplaceFirstMappedUnchecked(this, from, replace, startIndex);
+ }
+
+ @notNull
+ List<String> split(@nullCheck Pattern pattern) {
+ if (pattern is String) {
+ return JSArray.of(JS('', r'#.split(#)', this, pattern));
+ } else if (pattern is JSSyntaxRegExp && regExpCaptureCount(pattern) == 0) {
+ var re = regExpGetNative(pattern);
+ return JSArray.of(JS('', r'#.split(#)', this, re));
+ } else {
+ return _defaultSplit(pattern);
+ }
+ }
+
+ @notNull
+ String replaceRange(
+ @nullCheck int start, int end, @nullCheck String replacement) {
+ end = RangeError.checkValidRange(start, end, this.length);
+ return stringReplaceRangeUnchecked(this, start, end, replacement);
+ }
+
+ @notNull
+ List<String> _defaultSplit(Pattern pattern) {
+ List<String> result = <String>[];
+ // End of most recent match. That is, start of next part to add to result.
+ int start = 0;
+ // Length of most recent match.
+ // Set >0, so no match on the empty string causes the result to be [""].
+ int length = 1;
+ for (var match in pattern.allMatches(this)) {
+ @notNull
+ int matchStart = match.start;
+ @notNull
+ int matchEnd = match.end;
+ length = matchEnd - matchStart;
+ if (length == 0 && start == matchStart) {
+ // An empty match right after another match is ignored.
+ // This includes an empty match at the start of the string.
+ continue;
+ }
+ int end = matchStart;
+ result.add(this.substring(start, end));
+ start = matchEnd;
+ }
+ if (start < this.length || length > 0) {
+ // An empty match at the end of the string does not cause a "" at the end.
+ // A non-empty match ending at the end of the string does add a "".
+ result.add(this.substring(start));
+ }
+ return result;
+ }
+
+ @notNull
+ bool startsWith(Pattern pattern, [@nullCheck int index = 0]) {
+ // Suppress null check on length and all but the first
+ // reference to index.
+ int length = JS<int>('!', '#.length', this);
+ if (index < 0 || JS<int>('!', '#', index) > length) {
+ throw RangeError.range(index, 0, this.length);
+ }
+ if (pattern is String) {
+ String other = pattern;
+ int otherLength = JS<int>('!', '#.length', other);
+ int endIndex = index + otherLength;
+ if (endIndex > length) return false;
+ return other ==
+ JS<String>('!', r'#.substring(#, #)', this, index, endIndex);
+ }
+ return pattern.matchAsPrefix(this, index) != null;
+ }
+
+ @notNull
+ String substring(@nullCheck int startIndex, [int _endIndex]) {
+ var length = this.length;
+ final endIndex = _endIndex ?? length;
+ if (startIndex < 0) throw RangeError.value(startIndex);
+ if (startIndex > endIndex) throw RangeError.value(startIndex);
+ if (endIndex > length) throw RangeError.value(endIndex);
+ return JS<String>('!', r'#.substring(#, #)', this, startIndex, endIndex);
+ }
+
+ @notNull
+ String toLowerCase() {
+ return JS<String>('!', r'#.toLowerCase()', this);
+ }
+
+ @notNull
+ String toUpperCase() {
+ return JS<String>('!', r'#.toUpperCase()', this);
+ }
+
+ // Characters with Whitespace property (Unicode 6.3).
+ // 0009..000D ; White_Space # Cc <control-0009>..<control-000D>
+ // 0020 ; White_Space # Zs SPACE
+ // 0085 ; White_Space # Cc <control-0085>
+ // 00A0 ; White_Space # Zs NO-BREAK SPACE
+ // 1680 ; White_Space # Zs OGHAM SPACE MARK
+ // 2000..200A ; White_Space # Zs EN QUAD..HAIR SPACE
+ // 2028 ; White_Space # Zl LINE SEPARATOR
+ // 2029 ; White_Space # Zp PARAGRAPH SEPARATOR
+ // 202F ; White_Space # Zs NARROW NO-BREAK SPACE
+ // 205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE
+ // 3000 ; White_Space # Zs IDEOGRAPHIC SPACE
+ //
+ // BOM: 0xFEFF
+ @notNull
+ static bool _isWhitespace(@notNull int codeUnit) {
+ // Most codeUnits should be less than 256. Special case with a smaller
+ // switch.
+ if (codeUnit < 256) {
+ switch (codeUnit) {
+ case 0x09:
+ case 0x0A:
+ case 0x0B:
+ case 0x0C:
+ case 0x0D:
+ case 0x20:
+ case 0x85:
+ case 0xA0:
+ return true;
+ default:
+ return false;
+ }
+ }
+ switch (codeUnit) {
+ case 0x1680:
+ case 0x2000:
+ case 0x2001:
+ case 0x2002:
+ case 0x2003:
+ case 0x2004:
+ case 0x2005:
+ case 0x2006:
+ case 0x2007:
+ case 0x2008:
+ case 0x2009:
+ case 0x200A:
+ case 0x2028:
+ case 0x2029:
+ case 0x202F:
+ case 0x205F:
+ case 0x3000:
+ case 0xFEFF:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /// Finds the index of the first non-whitespace character, or the
+ /// end of the string. Start looking at position [index].
+ @notNull
+ static int _skipLeadingWhitespace(String string, @nullCheck int index) {
+ const int SPACE = 0x20;
+ const int CARRIAGE_RETURN = 0x0D;
+ var stringLength = string.length;
+ while (index < stringLength) {
+ int codeUnit = string.codeUnitAt(index);
+ if (codeUnit != SPACE &&
+ codeUnit != CARRIAGE_RETURN &&
+ !_isWhitespace(codeUnit)) {
+ break;
+ }
+ index++;
+ }
+ return index;
+ }
+
+ /// Finds the index after the last non-whitespace character, or 0.
+ /// Start looking at position [index - 1].
+ @notNull
+ static int _skipTrailingWhitespace(String string, @nullCheck int index) {
+ const int SPACE = 0x20;
+ const int CARRIAGE_RETURN = 0x0D;
+ while (index > 0) {
+ int codeUnit = string.codeUnitAt(index - 1);
+ if (codeUnit != SPACE &&
+ codeUnit != CARRIAGE_RETURN &&
+ !_isWhitespace(codeUnit)) {
+ break;
+ }
+ index--;
+ }
+ return index;
+ }
+
+ // Dart2js can't use JavaScript trim directly,
+ // because JavaScript does not trim
+ // the NEXT LINE (NEL) character (0x85).
+ @notNull
+ String trim() {
+ const int NEL = 0x85;
+
+ // Start by doing JS trim. Then check if it leaves a NEL at
+ // either end of the string.
+ String result = JS('!', '#.trim()', this);
+ final length = result.length;
+ if (length == 0) return result;
+ int firstCode = result.codeUnitAt(0);
+ int startIndex = 0;
+ if (firstCode == NEL) {
+ startIndex = _skipLeadingWhitespace(result, 1);
+ if (startIndex == length) return "";
+ }
+
+ int endIndex = length;
+ // We know that there is at least one character that is non-whitespace.
+ // Therefore we don't need to verify that endIndex > startIndex.
+ int lastCode = result.codeUnitAt(endIndex - 1);
+ if (lastCode == NEL) {
+ endIndex = _skipTrailingWhitespace(result, endIndex - 1);
+ }
+ if (startIndex == 0 && endIndex == length) return result;
+ return JS<String>('!', r'#.substring(#, #)', result, startIndex, endIndex);
+ }
+
+ // Dart2js can't use JavaScript trimLeft directly,
+ // because it is not in ES5, so not every browser implements it,
+ // and because those that do will not trim the NEXT LINE character (0x85).
+ @notNull
+ String trimLeft() {
+ const int NEL = 0x85;
+
+ // Start by doing JS trim. Then check if it leaves a NEL at
+ // the beginning of the string.
+ String result;
+ int startIndex = 0;
+ if (JS<bool>('!', 'typeof #.trimLeft != "undefined"', this)) {
+ result = JS<String>('!', '#.trimLeft()', this);
+ if (result.length == 0) return result;
+ int firstCode = result.codeUnitAt(0);
+ if (firstCode == NEL) {
+ startIndex = _skipLeadingWhitespace(result, 1);
+ }
+ } else {
+ result = this;
+ startIndex = _skipLeadingWhitespace(this, 0);
+ }
+ if (startIndex == 0) return result;
+ if (startIndex == result.length) return "";
+ return JS<String>('!', r'#.substring(#)', result, startIndex);
+ }
+
+ // Dart2js can't use JavaScript trimRight directly,
+ // because it is not in ES5 and because JavaScript does not trim
+ // the NEXT LINE character (0x85).
+ @notNull
+ String trimRight() {
+ const int NEL = 0x85;
+
+ // Start by doing JS trim. Then check if it leaves a NEL or BOM at
+ // the end of the string.
+ String result;
+ @notNull
+ int endIndex = 0;
+ // trimRight is implemented by Firefox and Chrome/Blink,
+ // so use it if it is there.
+ if (JS<bool>('!', 'typeof #.trimRight != "undefined"', this)) {
+ result = JS<String>('!', '#.trimRight()', this);
+ endIndex = result.length;
+ if (endIndex == 0) return result;
+ int lastCode = result.codeUnitAt(endIndex - 1);
+ if (lastCode == NEL) {
+ endIndex = _skipTrailingWhitespace(result, endIndex - 1);
+ }
+ } else {
+ result = this;
+ endIndex = _skipTrailingWhitespace(this, this.length);
+ }
+
+ if (endIndex == result.length) return result;
+ if (endIndex == 0) return "";
+ return JS<String>('!', r'#.substring(#, #)', result, 0, endIndex);
+ }
+
+ @notNull
+ String operator *(@nullCheck int times) {
+ if (0 >= times) return '';
+ if (times == 1 || this.length == 0) return this;
+ if (times != JS<int>('!', '# >>> 0', times)) {
+ // times >= 2^32. We can't create a string that big.
+ throw const OutOfMemoryError();
+ }
+ var result = '';
+ String s = this;
+ while (true) {
+ if (times & 1 == 1) result = s + result;
+ times = JS<int>('!', '# >>> 1', times);
+ if (times == 0) break;
+ s += s;
+ }
+ return result;
+ }
+
+ @notNull
+ String padLeft(@nullCheck int width, [String padding = ' ']) {
+ int delta = width - this.length;
+ if (delta <= 0) return this;
+ return padding * delta + this;
+ }
+
+ @notNull
+ String padRight(@nullCheck int width, [String padding = ' ']) {
+ int delta = width - this.length;
+ if (delta <= 0) return this;
+ return this + padding * delta;
+ }
+
+ @notNull
+ List<int> get codeUnits => CodeUnits(this);
+
+ @notNull
+ Runes get runes => Runes(this);
+
+ @notNull
+ int indexOf(@nullCheck Pattern pattern, [@nullCheck int start = 0]) {
+ if (start < 0 || start > this.length) {
+ throw RangeError.range(start, 0, this.length);
+ }
+ if (pattern is String) {
+ return stringIndexOfStringUnchecked(this, pattern, start);
+ }
+ if (pattern is JSSyntaxRegExp) {
+ JSSyntaxRegExp re = pattern;
+ Match match = firstMatchAfter(re, this, start);
+ return (match == null) ? -1 : match.start;
+ }
+ var length = this.length;
+ for (int i = start; i <= length; i++) {
+ if (pattern.matchAsPrefix(this, i) != null) return i;
+ }
+ return -1;
+ }
+
+ @notNull
+ int lastIndexOf(@nullCheck Pattern pattern, [int _start]) {
+ var length = this.length;
+ var start = _start ?? length;
+ if (start < 0 || start > length) {
+ throw RangeError.range(start, 0, length);
+ }
+ if (pattern is String) {
+ String other = pattern;
+ if (start + other.length > length) {
+ start = length - other.length;
+ }
+ return stringLastIndexOfUnchecked(this, other, start);
+ }
+ for (int i = start; i >= 0; i--) {
+ if (pattern.matchAsPrefix(this, i) != null) return i;
+ }
+ return -1;
+ }
+
+ @notNull
+ bool contains(@nullCheck Pattern other, [@nullCheck int startIndex = 0]) {
+ if (startIndex < 0 || startIndex > this.length) {
+ throw RangeError.range(startIndex, 0, this.length);
+ }
+ return stringContainsUnchecked(this, other, startIndex);
+ }
+
+ @notNull
+ bool get isEmpty => JS<int>('!', '#.length', this) == 0;
+
+ @notNull
+ bool get isNotEmpty => !isEmpty;
+
+ @notNull
+ int compareTo(@nullCheck String other) {
+ return this == other ? 0 : JS<bool>('!', r'# < #', this, other) ? -1 : 1;
+ }
+
+ // Note: if you change this, also change the function [S].
+ @notNull
+ String toString() => this;
+
+ /**
+ * This is the [Jenkins hash function][1] but using masking to keep
+ * values in SMI range.
+ *
+ * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+ */
+ @notNull
+ int get hashCode {
+ // TODO(ahe): This method shouldn't have to use JS. Update when our
+ // optimizations are smarter.
+ int hash = 0;
+ int length = JS('!', '#.length', this);
+ for (int i = 0; i < length; i++) {
+ hash = 0x1fffffff & (hash + JS<int>('!', r'#.charCodeAt(#)', this, i));
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+ hash = JS<int>('!', '# ^ (# >> 6)', hash, hash);
+ }
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+ hash = JS<int>('!', '# ^ (# >> 11)', hash, hash);
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+ }
+
+ @notNull
+ Type get runtimeType => String;
+
+ @notNull
+ final int length;
+
+ @notNull
+ String operator [](@nullCheck int index) {
+ if (index >= JS<int>('!', '#.length', this) || index < 0) {
+ throw diagnoseIndexError(this, index);
+ }
+ return JS<String>('!', '#[#]', this, index);
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/linked_hash_map.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/linked_hash_map.dart
new file mode 100644
index 0000000..1c03db8
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/linked_hash_map.dart
@@ -0,0 +1,278 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Efficient JavaScript based implementation of a linked hash map used as a
+// backing map for constant maps and the [LinkedHashMap] patch
+
+part of dart._js_helper;
+
+abstract class InternalMap<K, V> extends MapBase<K, V>
+ implements LinkedHashMap<K, V>, HashMap<K, V> {
+ @notNull
+ get _map;
+
+ @notNull
+ int get _modifications;
+
+ void forEach(void action(K key, V value)) {
+ int modifications = _modifications;
+ for (var entry in JS('Iterable', '#.entries()', _map)) {
+ action(JS('', '#[0]', entry), JS('', '#[1]', entry));
+ if (modifications != _modifications) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ }
+}
+
+/// A linked hash map implementation based on ES6 Map.
+///
+/// Items that can use identity semantics are stored directly in the backing
+/// map.
+///
+/// Items that have a custom equality/hashCode are first canonicalized by
+/// looking up the canonical key by its hashCode.
+class LinkedMap<K, V> extends InternalMap<K, V> {
+ /// The backing store for this map.
+ ///
+ /// Keys that use identity equality are stored directly. For other types of
+ /// keys, we first look them up (by hashCode) in the [_keyMap] map, then
+ /// we lookup the key in this map.
+ @notNull
+ final _map = JS('', 'new Map()');
+
+ /// Items that use custom equality semantics.
+ ///
+ /// This maps from the item's hashCode to the canonical key, which is then
+ /// used to lookup the item in [_map]. Keeping the data in our primary backing
+ /// map gives us the ordering semantics requred by [LinkedHashMap], while
+ /// also providing convenient access to keys/values.
+ @notNull
+ final _keyMap = JS('', 'new Map()');
+
+ // We track the number of modifications done to the key set of the
+ // hash map to be able to throw when the map is modified while being
+ // iterated over.
+ //
+ // Value cycles after 2^30 modifications so that modification counts are
+ // always unboxed (Smi) values. Modification detection will be missed if you
+ // make exactly some multiple of 2^30 modifications between advances of an
+ // iterator.
+ @notNull
+ int _modifications = 0;
+
+ LinkedMap();
+
+ /// Called by generated code for a map literal.
+ LinkedMap.from(JSArray entries) {
+ var map = _map;
+ var keyMap = _keyMap;
+ for (int i = 0, n = JS('!', '#.length', entries); i < n; i += 2) {
+ K key = JS('', '#[#]', entries, i);
+ V value = JS('', '#[#]', entries, i + 1);
+ if (key == null) {
+ key = null;
+ } else if (JS<bool>('!', '#[#] !== #', key,
+ dart.extensionSymbol('_equals'), dart.identityEquals)) {
+ key = putLinkedMapKey(key, keyMap);
+ }
+ JS('', '#.set(#, #)', map, key, value);
+ }
+ }
+
+ @notNull
+ int get length => JS<int>('!', '#.size', _map);
+
+ @notNull
+ bool get isEmpty => JS<bool>('!', '#.size == 0', _map);
+
+ @notNull
+ bool get isNotEmpty => JS<bool>('!', '#.size != 0', _map);
+
+ Iterable<K> get keys => _JSMapIterable<K>(this, true);
+ Iterable<V> get values => _JSMapIterable<V>(this, false);
+
+ @notNull
+ bool containsKey(Object key) {
+ if (key == null) {
+ key = null;
+ } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+ dart.identityEquals)) {
+ @notNull
+ var k = key;
+ var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
+ if (buckets != null) {
+ for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+ k = JS('', '#[#]', buckets, i);
+ if (k == key) return true;
+ }
+ }
+ return false;
+ }
+ return JS<bool>('!', '#.has(#)', _map, key);
+ }
+
+ bool containsValue(Object value) {
+ for (var v in JS('', '#.values()', _map)) {
+ if (v == value) return true;
+ }
+ return false;
+ }
+
+ void addAll(Map<K, V> other) {
+ var map = _map;
+ int length = JS('', '#.size', map);
+ other.forEach((K key, V value) {
+ if (key == null) {
+ key = null;
+ } else if (JS<bool>('!', '#[#] !== #', key,
+ dart.extensionSymbol('_equals'), dart.identityEquals)) {
+ key = putLinkedMapKey(key, _keyMap);
+ }
+ JS('', '#.set(#, #)', _map, key, value);
+ });
+ if (length != JS<int>('!', '#.size', map)) {
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ }
+
+ V operator [](Object key) {
+ if (key == null) {
+ key = null;
+ } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+ dart.identityEquals)) {
+ @notNull
+ var k = key;
+ var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
+ if (buckets != null) {
+ for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+ k = JS('', '#[#]', buckets, i);
+ if (k == key) return JS('', '#.get(#)', _map, k);
+ }
+ }
+ return null;
+ }
+ V value = JS('', '#.get(#)', _map, key);
+ return value == null ? null : value; // coerce undefined to null.
+ }
+
+ void operator []=(K key, V value) {
+ if (key == null) {
+ key = null;
+ } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+ dart.identityEquals)) {
+ key = putLinkedMapKey(key, _keyMap);
+ }
+ var map = _map;
+ int length = JS('', '#.size', map);
+ JS('', '#.set(#, #)', map, key, value);
+ if (length != JS<int>('!', '#.size', map)) {
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ }
+
+ V putIfAbsent(K key, V ifAbsent()) {
+ var map = _map;
+ if (key == null) {
+ key = null;
+ if (JS<bool>('!', '#.has(null)', map)) return JS('', '#.get(null)', map);
+ } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+ dart.identityEquals)) {
+ @notNull
+ K k = key;
+ var hash = JS<int>('!', '# & 0x3ffffff', k.hashCode);
+ var buckets = JS('', '#.get(#)', _keyMap, hash);
+ if (buckets == null) {
+ JS('', '#.set(#, [#])', _keyMap, hash, key);
+ } else {
+ for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+ k = JS('', '#[#]', buckets, i);
+ if (k == key) return JS('', '#.get(#)', map, k);
+ }
+ JS('', '#.push(#)', buckets, key);
+ }
+ } else if (JS<bool>('!', '#.has(#)', map, key)) {
+ return JS('', '#.get(#)', map, key);
+ }
+ V value = ifAbsent();
+ if (value == null) value = null; // coerce undefined to null.
+ JS('', '#.set(#, #)', map, key, value);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ return value;
+ }
+
+ V remove(Object key) {
+ if (key == null) {
+ key = null;
+ } else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+ dart.identityEquals)) {
+ @notNull
+ var k = key;
+ var hash = JS<int>('!', '# & 0x3ffffff', k.hashCode);
+ var buckets = JS('', '#.get(#)', _keyMap, hash);
+ if (buckets == null) return null; // not found
+ for (int i = 0, n = JS('!', '#.length', buckets);;) {
+ k = JS('', '#[#]', buckets, i);
+ if (k == key) {
+ key = k;
+ if (n == 1) {
+ JS('', '#.delete(#)', _keyMap, hash);
+ } else {
+ JS('', '#.splice(#, 1)', buckets, i);
+ }
+ break;
+ }
+ if (++i >= n) return null; // not found
+ }
+ }
+ var map = _map;
+ V value = JS('', '#.get(#)', map, key);
+ if (JS<bool>('!', '#.delete(#)', map, key)) {
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ return value == null ? null : value; // coerce undefined to null.
+ }
+
+ void clear() {
+ var map = _map;
+ if (JS<int>('!', '#.size', map) > 0) {
+ JS('', '#.clear()', map);
+ JS('', '#.clear()', _keyMap);
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+ }
+}
+
+@NoReifyGeneric()
+K putLinkedMapKey<K>(@notNull K key, keyMap) {
+ var hash = JS<int>('!', '# & 0x3ffffff', key.hashCode);
+ var buckets = JS('', '#.get(#)', keyMap, hash);
+ if (buckets == null) {
+ JS('', '#.set(#, [#])', keyMap, hash, key);
+ return key;
+ }
+ for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
+ @notNull
+ K k = JS('', '#[#]', buckets, i);
+ if (k == key) return k;
+ }
+ JS('', '#.push(#)', buckets, key);
+ return key;
+}
+
+class ImmutableMap<K, V> extends LinkedMap<K, V> {
+ ImmutableMap.from(JSArray entries) : super.from(entries);
+
+ void operator []=(Object key, Object value) {
+ throw _unsupported();
+ }
+
+ void addAll(Object other) => throw _unsupported();
+ void clear() => throw _unsupported();
+ V remove(Object key) => throw _unsupported();
+ V putIfAbsent(Object key, Object ifAbsent()) => throw _unsupported();
+
+ static Error _unsupported() =>
+ UnsupportedError("Cannot modify unmodifiable map");
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/mirror_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/mirror_helper.dart
new file mode 100644
index 0000000..f78926a
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/mirror_helper.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+/**
+ * Helps dealing with reflection in the case that the source code has been
+ * changed as a result of compiling with dart2dart.
+ */
+library dart._mirror_helper;
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_helper.dart
new file mode 100644
index 0000000..cc214e8
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_helper.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._js_helper;
+
+// Obsolete in dart dev compiler. Added only so that the same version of
+// dart:html can be used in dart2js an dev compiler.
+F convertDartClosureToJS<F>(F closure, int arity) {
+ return closure;
+}
+
+// Warning: calls to these methods need to be removed before custom elements
+// and cross-frame dom objects behave correctly in ddc
+// https://github.com/dart-lang/sdk/issues/28326
+setNativeSubclassDispatchRecord(proto, interceptor) {}
+findDispatchTagForInterceptorClass(interceptorClassConstructor) {}
+makeLeafDispatchRecord(interceptor) {}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart
new file mode 100644
index 0000000..2a7a621
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart
@@ -0,0 +1,1902 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Specialized integers and floating point numbers,
+ * with SIMD support and efficient lists.
+ */
+library dart.typed_data.implementation;
+
+import 'dart:collection';
+import 'dart:_internal';
+import 'dart:_interceptors' show JSIndexable;
+import 'dart:_js_helper'
+ show
+ Creates,
+ JavaScriptIndexingBehavior,
+ JSName,
+ Native,
+ Null,
+ Returns,
+ diagnoseIndexError,
+ diagnoseRangeError;
+import 'dart:_foreign_helper' show JS;
+import 'dart:math' as Math;
+
+import 'dart:typed_data';
+
+@Native("ArrayBuffer")
+class NativeByteBuffer implements ByteBuffer {
+ @JSName('byteLength')
+ external int get lengthInBytes;
+
+ Type get runtimeType => ByteBuffer;
+
+ Uint8List asUint8List([int offsetInBytes = 0, int length]) {
+ return NativeUint8List.view(this, offsetInBytes, length);
+ }
+
+ Int8List asInt8List([int offsetInBytes = 0, int length]) {
+ return NativeInt8List.view(this, offsetInBytes, length);
+ }
+
+ Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]) {
+ return NativeUint8ClampedList.view(this, offsetInBytes, length);
+ }
+
+ Uint16List asUint16List([int offsetInBytes = 0, int length]) {
+ return NativeUint16List.view(this, offsetInBytes, length);
+ }
+
+ Int16List asInt16List([int offsetInBytes = 0, int length]) {
+ return NativeInt16List.view(this, offsetInBytes, length);
+ }
+
+ Uint32List asUint32List([int offsetInBytes = 0, int length]) {
+ return NativeUint32List.view(this, offsetInBytes, length);
+ }
+
+ Int32List asInt32List([int offsetInBytes = 0, int length]) {
+ return NativeInt32List.view(this, offsetInBytes, length);
+ }
+
+ Uint64List asUint64List([int offsetInBytes = 0, int length]) {
+ throw UnsupportedError("Uint64List not supported by dart2js.");
+ }
+
+ Int64List asInt64List([int offsetInBytes = 0, int length]) {
+ throw UnsupportedError("Int64List not supported by dart2js.");
+ }
+
+ Int32x4List asInt32x4List([int offsetInBytes = 0, int length]) {
+ NativeInt32List storage =
+ this.asInt32List(offsetInBytes, length != null ? length * 4 : null);
+ return NativeInt32x4List._externalStorage(storage);
+ }
+
+ Float32List asFloat32List([int offsetInBytes = 0, int length]) {
+ return NativeFloat32List.view(this, offsetInBytes, length);
+ }
+
+ Float64List asFloat64List([int offsetInBytes = 0, int length]) {
+ return NativeFloat64List.view(this, offsetInBytes, length);
+ }
+
+ Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]) {
+ NativeFloat32List storage =
+ this.asFloat32List(offsetInBytes, length != null ? length * 4 : null);
+ return NativeFloat32x4List._externalStorage(storage);
+ }
+
+ Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]) {
+ NativeFloat64List storage =
+ this.asFloat64List(offsetInBytes, length != null ? length * 2 : null);
+ return NativeFloat64x2List._externalStorage(storage);
+ }
+
+ ByteData asByteData([int offsetInBytes = 0, int length]) {
+ return NativeByteData.view(this, offsetInBytes, length);
+ }
+}
+
+/**
+ * A fixed-length list of Float32x4 numbers that is viewable as a
+ * [TypedData]. For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+class NativeFloat32x4List extends Object
+ with ListMixin<Float32x4>, FixedLengthListMixin<Float32x4>
+ implements Float32x4List {
+ final NativeFloat32List _storage;
+
+ /**
+ * Creates a [Float32x4List] of the specified length (in elements),
+ * all of whose elements are initially zero.
+ */
+ NativeFloat32x4List(int length) : _storage = NativeFloat32List(length * 4);
+
+ NativeFloat32x4List._externalStorage(this._storage);
+
+ NativeFloat32x4List._slowFromList(List<Float32x4> list)
+ : _storage = NativeFloat32List(list.length * 4) {
+ for (int i = 0; i < list.length; i++) {
+ var e = list[i];
+ _storage[(i * 4) + 0] = e.x;
+ _storage[(i * 4) + 1] = e.y;
+ _storage[(i * 4) + 2] = e.z;
+ _storage[(i * 4) + 3] = e.w;
+ }
+ }
+
+ Type get runtimeType => Float32x4List;
+
+ /**
+ * Creates a [Float32x4List] with the same size as the [elements] list
+ * and copies over the elements.
+ */
+ factory NativeFloat32x4List.fromList(List<Float32x4> list) {
+ if (list is NativeFloat32x4List) {
+ return NativeFloat32x4List._externalStorage(
+ NativeFloat32List.fromList(list._storage));
+ } else {
+ return NativeFloat32x4List._slowFromList(list);
+ }
+ }
+
+ ByteBuffer get buffer => _storage.buffer;
+
+ int get lengthInBytes => _storage.lengthInBytes;
+
+ int get offsetInBytes => _storage.offsetInBytes;
+
+ int get elementSizeInBytes => Float32x4List.bytesPerElement;
+
+ int get length => _storage.length ~/ 4;
+
+ Float32x4 operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ double _x = _storage[(index * 4) + 0];
+ double _y = _storage[(index * 4) + 1];
+ double _z = _storage[(index * 4) + 2];
+ double _w = _storage[(index * 4) + 3];
+ return NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ void operator []=(int index, Float32x4 value) {
+ _checkValidIndex(index, this, this.length);
+ _storage[(index * 4) + 0] = value.x;
+ _storage[(index * 4) + 1] = value.y;
+ _storage[(index * 4) + 2] = value.z;
+ _storage[(index * 4) + 3] = value.w;
+ }
+
+ Float32x4List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ return NativeFloat32x4List._externalStorage(
+ _storage.sublist(start * 4, end * 4));
+ }
+}
+
+/**
+ * A fixed-length list of Int32x4 numbers that is viewable as a
+ * [TypedData]. For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+class NativeInt32x4List extends Object
+ with ListMixin<Int32x4>, FixedLengthListMixin<Int32x4>
+ implements Int32x4List {
+ final Int32List _storage;
+
+ /**
+ * Creates a [Int32x4List] of the specified length (in elements),
+ * all of whose elements are initially zero.
+ */
+ NativeInt32x4List(int length) : _storage = NativeInt32List(length * 4);
+
+ NativeInt32x4List._externalStorage(Int32List storage) : _storage = storage;
+
+ NativeInt32x4List._slowFromList(List<Int32x4> list)
+ : _storage = NativeInt32List(list.length * 4) {
+ for (int i = 0; i < list.length; i++) {
+ var e = list[i];
+ _storage[(i * 4) + 0] = e.x;
+ _storage[(i * 4) + 1] = e.y;
+ _storage[(i * 4) + 2] = e.z;
+ _storage[(i * 4) + 3] = e.w;
+ }
+ }
+
+ Type get runtimeType => Int32x4List;
+
+ /**
+ * Creates a [Int32x4List] with the same size as the [elements] list
+ * and copies over the elements.
+ */
+ factory NativeInt32x4List.fromList(List<Int32x4> list) {
+ if (list is NativeInt32x4List) {
+ return NativeInt32x4List._externalStorage(
+ NativeInt32List.fromList(list._storage));
+ } else {
+ return NativeInt32x4List._slowFromList(list);
+ }
+ }
+
+ ByteBuffer get buffer => _storage.buffer;
+
+ int get lengthInBytes => _storage.lengthInBytes;
+
+ int get offsetInBytes => _storage.offsetInBytes;
+
+ int get elementSizeInBytes => Int32x4List.bytesPerElement;
+
+ int get length => _storage.length ~/ 4;
+
+ Int32x4 operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ int _x = _storage[(index * 4) + 0];
+ int _y = _storage[(index * 4) + 1];
+ int _z = _storage[(index * 4) + 2];
+ int _w = _storage[(index * 4) + 3];
+ return NativeInt32x4._truncated(_x, _y, _z, _w);
+ }
+
+ void operator []=(int index, Int32x4 value) {
+ _checkValidIndex(index, this, this.length);
+ _storage[(index * 4) + 0] = value.x;
+ _storage[(index * 4) + 1] = value.y;
+ _storage[(index * 4) + 2] = value.z;
+ _storage[(index * 4) + 3] = value.w;
+ }
+
+ Int32x4List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ return NativeInt32x4List._externalStorage(
+ _storage.sublist(start * 4, end * 4));
+ }
+}
+
+/**
+ * A fixed-length list of Float64x2 numbers that is viewable as a
+ * [TypedData]. For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+class NativeFloat64x2List extends Object
+ with ListMixin<Float64x2>, FixedLengthListMixin<Float64x2>
+ implements Float64x2List {
+ final NativeFloat64List _storage;
+
+ /**
+ * Creates a [Float64x2List] of the specified length (in elements),
+ * all of whose elements are initially zero.
+ */
+ NativeFloat64x2List(int length) : _storage = NativeFloat64List(length * 2);
+
+ NativeFloat64x2List._externalStorage(this._storage);
+
+ NativeFloat64x2List._slowFromList(List<Float64x2> list)
+ : _storage = NativeFloat64List(list.length * 2) {
+ for (int i = 0; i < list.length; i++) {
+ var e = list[i];
+ _storage[(i * 2) + 0] = e.x;
+ _storage[(i * 2) + 1] = e.y;
+ }
+ }
+
+ /**
+ * Creates a [Float64x2List] with the same size as the [elements] list
+ * and copies over the elements.
+ */
+ factory NativeFloat64x2List.fromList(List<Float64x2> list) {
+ if (list is NativeFloat64x2List) {
+ return NativeFloat64x2List._externalStorage(
+ NativeFloat64List.fromList(list._storage));
+ } else {
+ return NativeFloat64x2List._slowFromList(list);
+ }
+ }
+
+ Type get runtimeType => Float64x2List;
+
+ ByteBuffer get buffer => _storage.buffer;
+
+ int get lengthInBytes => _storage.lengthInBytes;
+
+ int get offsetInBytes => _storage.offsetInBytes;
+
+ int get elementSizeInBytes => Float64x2List.bytesPerElement;
+
+ int get length => _storage.length ~/ 2;
+
+ Float64x2 operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ double _x = _storage[(index * 2) + 0];
+ double _y = _storage[(index * 2) + 1];
+ return Float64x2(_x, _y);
+ }
+
+ void operator []=(int index, Float64x2 value) {
+ _checkValidIndex(index, this, this.length);
+ _storage[(index * 2) + 0] = value.x;
+ _storage[(index * 2) + 1] = value.y;
+ }
+
+ Float64x2List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ return NativeFloat64x2List._externalStorage(
+ _storage.sublist(start * 2, end * 2));
+ }
+}
+
+@Native("ArrayBufferView")
+class NativeTypedData implements TypedData {
+ /**
+ * Returns the byte buffer associated with this object.
+ */
+ @Creates('NativeByteBuffer')
+ // May be Null for IE's CanvasPixelArray.
+ @Returns('NativeByteBuffer|Null')
+ external ByteBuffer get buffer;
+
+ /**
+ * Returns the length of this view, in bytes.
+ */
+ @JSName('byteLength')
+ external int get lengthInBytes;
+
+ /**
+ * Returns the offset in bytes into the underlying byte buffer of this view.
+ */
+ @JSName('byteOffset')
+ external int get offsetInBytes;
+
+ /**
+ * Returns the number of bytes in the representation of each element in this
+ * list.
+ */
+ @JSName('BYTES_PER_ELEMENT')
+ external int get elementSizeInBytes;
+
+ void _invalidPosition(int position, int length, String name) {
+ if (position is! int) {
+ throw ArgumentError.value(position, name, 'Invalid list position');
+ } else {
+ throw RangeError.range(position, 0, length, name);
+ }
+ }
+
+ void _checkPosition(int position, int length, String name) {
+ if (JS<bool>('!', '(# >>> 0) !== #', position, position) ||
+ JS<int>('!', '#', position) > length) {
+ // 'int' guaranteed by above test.
+ _invalidPosition(position, length, name);
+ }
+ }
+}
+
+// Validates the unnamed constructor length argument. Checking is necessary
+// because passing unvalidated values to the native constructors can cause
+// conversions or create views.
+int _checkLength(length) {
+ if (length is! int) throw ArgumentError('Invalid length $length');
+ return length;
+}
+
+// Validates `.view` constructor arguments. Checking is necessary because
+// passing unvalidated values to the native constructors can cause conversions
+// (e.g. String arguments) or create typed data objects that are not actually
+// views of the input.
+void _checkViewArguments(buffer, offsetInBytes, length) {
+ if (buffer is! NativeByteBuffer) {
+ throw ArgumentError('Invalid view buffer');
+ }
+ if (offsetInBytes is! int) {
+ throw ArgumentError('Invalid view offsetInBytes $offsetInBytes');
+ }
+ if (length != null && length is! int) {
+ throw ArgumentError('Invalid view length $length');
+ }
+}
+
+// Ensures that [list] is a JavaScript Array or a typed array. If necessary,
+// returns a copy of the list.
+List _ensureNativeList(List list) {
+ if (list is JSIndexable) return list;
+ List result = List(list.length);
+ for (int i = 0; i < list.length; i++) {
+ result[i] = list[i];
+ }
+ return result;
+}
+
+@Native("DataView")
+class NativeByteData extends NativeTypedData implements ByteData {
+ /**
+ * Creates a [ByteData] of the specified length (in elements), all of
+ * whose elements are initially zero.
+ */
+ factory NativeByteData(int length) => _create1(_checkLength(length));
+
+ /**
+ * Creates an [ByteData] _view_ of the specified region in the specified
+ * byte buffer. Changes in the [ByteData] will be visible in the byte
+ * buffer and vice versa. If the [offsetInBytes] index of the region is not
+ * specified, it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to null, which indicates
+ * that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ */
+ factory NativeByteData.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => ByteData;
+
+ int get elementSizeInBytes => 1;
+
+ /**
+ * Returns the floating point number represented by the four bytes at
+ * the specified [byteOffset] in this object, in IEEE 754
+ * single-precision binary floating-point format (binary32).
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 4` is greater than the length of this object.
+ */
+ double getFloat32(int byteOffset, [Endian endian = Endian.big]) =>
+ _getFloat32(byteOffset, Endian.little == endian);
+
+ @JSName('getFloat32')
+ @Returns('double')
+ double _getFloat32(int byteOffset, [bool littleEndian]) native;
+
+ /**
+ * Returns the floating point number represented by the eight bytes at
+ * the specified [byteOffset] in this object, in IEEE 754
+ * double-precision binary floating-point format (binary64).
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 8` is greater than the length of this object.
+ */
+ double getFloat64(int byteOffset, [Endian endian = Endian.big]) =>
+ _getFloat64(byteOffset, Endian.little == endian);
+
+ @JSName('getFloat64')
+ @Returns('double')
+ double _getFloat64(int byteOffset, [bool littleEndian]) native;
+
+ /**
+ * Returns the (possibly negative) integer represented by the two bytes at
+ * the specified [byteOffset] in this object, in two's complement binary
+ * form.
+ * The return value will be between 2<sup>15</sup> and 2<sup>15</sup> - 1,
+ * inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 2` is greater than the length of this object.
+ */
+ int getInt16(int byteOffset, [Endian endian = Endian.big]) =>
+ _getInt16(byteOffset, Endian.little == endian);
+
+ @JSName('getInt16')
+ @Returns('int')
+ int _getInt16(int byteOffset, [bool littleEndian]) native;
+
+ /**
+ * Returns the (possibly negative) integer represented by the four bytes at
+ * the specified [byteOffset] in this object, in two's complement binary
+ * form.
+ * The return value will be between 2<sup>31</sup> and 2<sup>31</sup> - 1,
+ * inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 4` is greater than the length of this object.
+ */
+ int getInt32(int byteOffset, [Endian endian = Endian.big]) =>
+ _getInt32(byteOffset, Endian.little == endian);
+
+ @JSName('getInt32')
+ @Returns('int')
+ int _getInt32(int byteOffset, [bool littleEndian]) native;
+
+ /**
+ * Returns the (possibly negative) integer represented by the eight bytes at
+ * the specified [byteOffset] in this object, in two's complement binary
+ * form.
+ * The return value will be between 2<sup>63</sup> and 2<sup>63</sup> - 1,
+ * inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 8` is greater than the length of this object.
+ */
+ int getInt64(int byteOffset, [Endian endian = Endian.big]) {
+ throw UnsupportedError('Int64 accessor not supported by dart2js.');
+ }
+
+ /**
+ * Returns the (possibly negative) integer represented by the byte at the
+ * specified [byteOffset] in this object, in two's complement binary
+ * representation. The return value will be between -128 and 127, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * greater than or equal to the length of this object.
+ */
+ int getInt8(int byteOffset) native;
+
+ /**
+ * Returns the positive integer represented by the two bytes starting
+ * at the specified [byteOffset] in this object, in unsigned binary
+ * form.
+ * The return value will be between 0 and 2<sup>16</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 2` is greater than the length of this object.
+ */
+ int getUint16(int byteOffset, [Endian endian = Endian.big]) =>
+ _getUint16(byteOffset, Endian.little == endian);
+
+ @JSName('getUint16')
+ @Returns('int')
+ int _getUint16(int byteOffset, [bool littleEndian]) native;
+
+ /**
+ * Returns the positive integer represented by the four bytes starting
+ * at the specified [byteOffset] in this object, in unsigned binary
+ * form.
+ * The return value will be between 0 and 2<sup>32</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 4` is greater than the length of this object.
+ */
+ int getUint32(int byteOffset, [Endian endian = Endian.big]) =>
+ _getUint32(byteOffset, Endian.little == endian);
+
+ @JSName('getUint32')
+ @Returns('int')
+ int _getUint32(int byteOffset, [bool littleEndian]) native;
+
+ /**
+ * Returns the positive integer represented by the eight bytes starting
+ * at the specified [byteOffset] in this object, in unsigned binary
+ * form.
+ * The return value will be between 0 and 2<sup>64</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 8` is greater than the length of this object.
+ */
+ int getUint64(int byteOffset, [Endian endian = Endian.big]) {
+ throw UnsupportedError('Uint64 accessor not supported by dart2js.');
+ }
+
+ /**
+ * Returns the positive integer represented by the byte at the specified
+ * [byteOffset] in this object, in unsigned binary form. The
+ * return value will be between 0 and 255, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * greater than or equal to the length of this object.
+ */
+ int getUint8(int byteOffset) native;
+
+ /**
+ * Sets the four bytes starting at the specified [byteOffset] in this
+ * object to the IEEE 754 single-precision binary floating-point
+ * (binary32) representation of the specified [value].
+ *
+ * **Note that this method can lose precision.** The input [value] is
+ * a 64-bit floating point value, which will be converted to 32-bit
+ * floating point value by IEEE 754 rounding rules before it is stored.
+ * If [value] cannot be represented exactly as a binary32, it will be
+ * converted to the nearest binary32 value. If two binary32 values are
+ * equally close, the one whose least significant bit is zero will be used.
+ * Note that finite (but large) values can be converted to infinity, and
+ * small non-zero values can be converted to zero.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 4` is greater than the length of this object.
+ */
+ void setFloat32(int byteOffset, num value, [Endian endian = Endian.big]) =>
+ _setFloat32(byteOffset, value, Endian.little == endian);
+
+ @JSName('setFloat32')
+ void _setFloat32(int byteOffset, num value, [bool littleEndian]) native;
+
+ /**
+ * Sets the eight bytes starting at the specified [byteOffset] in this
+ * object to the IEEE 754 double-precision binary floating-point
+ * (binary64) representation of the specified [value].
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 8` is greater than the length of this object.
+ */
+ void setFloat64(int byteOffset, num value, [Endian endian = Endian.big]) =>
+ _setFloat64(byteOffset, value, Endian.little == endian);
+
+ @JSName('setFloat64')
+ void _setFloat64(int byteOffset, num value, [bool littleEndian]) native;
+
+ /**
+ * Sets the two bytes starting at the specified [byteOffset] in this
+ * object to the two's complement binary representation of the specified
+ * [value], which must fit in two bytes. In other words, [value] must lie
+ * between 2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 2` is greater than the length of this object.
+ */
+ void setInt16(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _setInt16(byteOffset, value, Endian.little == endian);
+
+ @JSName('setInt16')
+ void _setInt16(int byteOffset, int value, [bool littleEndian]) native;
+
+ /**
+ * Sets the four bytes starting at the specified [byteOffset] in this
+ * object to the two's complement binary representation of the specified
+ * [value], which must fit in four bytes. In other words, [value] must lie
+ * between 2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 4` is greater than the length of this object.
+ */
+ void setInt32(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _setInt32(byteOffset, value, Endian.little == endian);
+
+ @JSName('setInt32')
+ void _setInt32(int byteOffset, int value, [bool littleEndian]) native;
+
+ /**
+ * Sets the eight bytes starting at the specified [byteOffset] in this
+ * object to the two's complement binary representation of the specified
+ * [value], which must fit in eight bytes. In other words, [value] must lie
+ * between 2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 8` is greater than the length of this object.
+ */
+ void setInt64(int byteOffset, int value, [Endian endian = Endian.big]) {
+ throw UnsupportedError('Int64 accessor not supported by dart2js.');
+ }
+
+ /**
+ * Sets the byte at the specified [byteOffset] in this object to the
+ * two's complement binary representation of the specified [value], which
+ * must fit in a single byte. In other words, [value] must be between
+ * -128 and 127, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * greater than or equal to the length of this object.
+ */
+ void setInt8(int byteOffset, int value) native;
+
+ /**
+ * Sets the two bytes starting at the specified [byteOffset] in this object
+ * to the unsigned binary representation of the specified [value],
+ * which must fit in two bytes. in other words, [value] must be between
+ * 0 and 2<sup>16</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 2` is greater than the length of this object.
+ */
+ void setUint16(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _setUint16(byteOffset, value, Endian.little == endian);
+
+ @JSName('setUint16')
+ void _setUint16(int byteOffset, int value, [bool littleEndian]) native;
+
+ /**
+ * Sets the four bytes starting at the specified [byteOffset] in this object
+ * to the unsigned binary representation of the specified [value],
+ * which must fit in four bytes. in other words, [value] must be between
+ * 0 and 2<sup>32</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 4` is greater than the length of this object.
+ */
+ void setUint32(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _setUint32(byteOffset, value, Endian.little == endian);
+
+ @JSName('setUint32')
+ void _setUint32(int byteOffset, int value, [bool littleEndian]) native;
+
+ /**
+ * Sets the eight bytes starting at the specified [byteOffset] in this object
+ * to the unsigned binary representation of the specified [value],
+ * which must fit in eight bytes. in other words, [value] must be between
+ * 0 and 2<sup>64</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 8` is greater than the length of this object.
+ */
+ void setUint64(int byteOffset, int value, [Endian endian = Endian.big]) {
+ throw UnsupportedError('Uint64 accessor not supported by dart2js.');
+ }
+
+ /**
+ * Sets the byte at the specified [byteOffset] in this object to the
+ * unsigned binary representation of the specified [value], which must fit
+ * in a single byte. in other words, [value] must be between 0 and 255,
+ * inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative,
+ * or greater than or equal to the length of this object.
+ */
+ void setUint8(int byteOffset, int value) native;
+
+ static NativeByteData _create1(arg) =>
+ JS('NativeByteData', 'new DataView(new ArrayBuffer(#))', arg);
+
+ static NativeByteData _create2(arg1, arg2) =>
+ JS('NativeByteData', 'new DataView(#, #)', arg1, arg2);
+
+ static NativeByteData _create3(arg1, arg2, arg3) =>
+ JS('NativeByteData', 'new DataView(#, #, #)', arg1, arg2, arg3);
+}
+
+abstract class NativeTypedArray extends NativeTypedData
+ implements JavaScriptIndexingBehavior {
+ int get length;
+
+ void _setRangeFast(
+ int start, int end, NativeTypedArray source, int skipCount) {
+ int targetLength = this.length;
+ _checkPosition(start, targetLength, "start");
+ _checkPosition(end, targetLength, "end");
+ if (start > end) throw RangeError.range(start, 0, end);
+ int count = end - start;
+
+ if (skipCount < 0) throw ArgumentError(skipCount);
+
+ int sourceLength = source.length;
+ if (sourceLength - skipCount < count) {
+ throw StateError('Not enough elements');
+ }
+
+ if (skipCount != 0 || sourceLength != count) {
+ // Create a view of the exact subrange that is copied from the source.
+ source = JS('', '#.subarray(#, #)', source, skipCount, skipCount + count);
+ }
+ JS('void', '#.set(#, #)', this, source, start);
+ }
+}
+
+abstract class NativeTypedArrayOfDouble extends NativeTypedArray
+ with ListMixin<double>, FixedLengthListMixin<double> {
+ int get length => JS<int>('!', '#.length', this);
+
+ double operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS<double>('!', '#[#]', this, index);
+ }
+
+ void operator []=(int index, num value) {
+ _checkValidIndex(index, this, this.length);
+ JS('void', '#[#] = #', this, index, value);
+ }
+
+ void setRange(int start, int end, Iterable<double> iterable,
+ [int skipCount = 0]) {
+ if (iterable is NativeTypedArrayOfDouble) {
+ _setRangeFast(start, end, iterable, skipCount);
+ return;
+ }
+ super.setRange(start, end, iterable, skipCount);
+ }
+}
+
+abstract class NativeTypedArrayOfInt extends NativeTypedArray
+ with ListMixin<int>, FixedLengthListMixin<int>
+ implements List<int> {
+ int get length => JS<int>('!', '#.length', this);
+
+ // operator[]() is not here since different versions have different return
+ // types
+
+ void operator []=(int index, int value) {
+ _checkValidIndex(index, this, this.length);
+ JS('void', '#[#] = #', this, index, value);
+ }
+
+ void setRange(int start, int end, Iterable<int> iterable,
+ [int skipCount = 0]) {
+ if (iterable is NativeTypedArrayOfInt) {
+ _setRangeFast(start, end, iterable, skipCount);
+ return;
+ }
+ super.setRange(start, end, iterable, skipCount);
+ }
+}
+
+@Native("Float32Array")
+class NativeFloat32List extends NativeTypedArrayOfDouble
+ implements Float32List {
+ factory NativeFloat32List(int length) => _create1(_checkLength(length));
+
+ factory NativeFloat32List.fromList(List<double> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeFloat32List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Float32List;
+
+ Float32List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source =
+ JS<NativeFloat32List>('!', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeFloat32List _create1(arg) =>
+ JS<NativeFloat32List>('!', 'new Float32Array(#)', arg);
+
+ static NativeFloat32List _create2(arg1, arg2) =>
+ JS<NativeFloat32List>('!', 'new Float32Array(#, #)', arg1, arg2);
+
+ static NativeFloat32List _create3(arg1, arg2, arg3) =>
+ JS<NativeFloat32List>('!', 'new Float32Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Float64Array")
+class NativeFloat64List extends NativeTypedArrayOfDouble
+ implements Float64List {
+ factory NativeFloat64List(int length) => _create1(_checkLength(length));
+
+ factory NativeFloat64List.fromList(List<double> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeFloat64List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Float64List;
+
+ Float64List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS('NativeFloat64List', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeFloat64List _create1(arg) =>
+ JS('NativeFloat64List', 'new Float64Array(#)', arg);
+
+ static NativeFloat64List _create2(arg1, arg2) =>
+ JS('NativeFloat64List', 'new Float64Array(#, #)', arg1, arg2);
+
+ static NativeFloat64List _create3(arg1, arg2, arg3) =>
+ JS('NativeFloat64List', 'new Float64Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Int16Array")
+class NativeInt16List extends NativeTypedArrayOfInt implements Int16List {
+ factory NativeInt16List(int length) => _create1(_checkLength(length));
+
+ factory NativeInt16List.fromList(List<int> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeInt16List.view(
+ NativeByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Int16List;
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS<int>('!', '#[#]', this, index);
+ }
+
+ Int16List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS('NativeInt16List', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeInt16List _create1(arg) =>
+ JS('NativeInt16List', 'new Int16Array(#)', arg);
+
+ static NativeInt16List _create2(arg1, arg2) =>
+ JS('NativeInt16List', 'new Int16Array(#, #)', arg1, arg2);
+
+ static NativeInt16List _create3(arg1, arg2, arg3) =>
+ JS('NativeInt16List', 'new Int16Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Int32Array")
+class NativeInt32List extends NativeTypedArrayOfInt implements Int32List {
+ factory NativeInt32List(int length) => _create1(_checkLength(length));
+
+ factory NativeInt32List.fromList(List<int> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeInt32List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Int32List;
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS<int>('!', '#[#]', this, index);
+ }
+
+ Int32List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS<NativeInt32List>('!', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeInt32List _create1(arg) =>
+ JS<NativeInt32List>('!', 'new Int32Array(#)', arg);
+
+ static NativeInt32List _create2(arg1, arg2) =>
+ JS<NativeInt32List>('!', 'new Int32Array(#, #)', arg1, arg2);
+
+ static NativeInt32List _create3(arg1, arg2, arg3) =>
+ JS<NativeInt32List>('!', 'new Int32Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Int8Array")
+class NativeInt8List extends NativeTypedArrayOfInt implements Int8List {
+ factory NativeInt8List(int length) => _create1(_checkLength(length));
+
+ factory NativeInt8List.fromList(List<int> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeInt8List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Int8List;
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS<int>('!', '#[#]', this, index);
+ }
+
+ Int8List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS<NativeInt8List>('!', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeInt8List _create1(arg) =>
+ JS<NativeInt8List>('!', 'new Int8Array(#)', arg);
+
+ static NativeInt8List _create2(arg1, arg2) =>
+ JS<NativeInt8List>('!', 'new Int8Array(#, #)', arg1, arg2);
+
+ static Int8List _create3(arg1, arg2, arg3) =>
+ JS<NativeInt8List>('!', 'new Int8Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Uint16Array")
+class NativeUint16List extends NativeTypedArrayOfInt implements Uint16List {
+ factory NativeUint16List(int length) => _create1(_checkLength(length));
+
+ factory NativeUint16List.fromList(List<int> list) =>
+ _create1(_ensureNativeList(list));
+
+ factory NativeUint16List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Uint16List;
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS<int>('!', '#[#]', this, index);
+ }
+
+ Uint16List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source =
+ JS<NativeUint16List>('!', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeUint16List _create1(arg) =>
+ JS<NativeUint16List>('!', 'new Uint16Array(#)', arg);
+
+ static NativeUint16List _create2(arg1, arg2) =>
+ JS<NativeUint16List>('!', 'new Uint16Array(#, #)', arg1, arg2);
+
+ static NativeUint16List _create3(arg1, arg2, arg3) =>
+ JS<NativeUint16List>('!', 'new Uint16Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Uint32Array")
+class NativeUint32List extends NativeTypedArrayOfInt implements Uint32List {
+ factory NativeUint32List(int length) => _create1(_checkLength(length));
+
+ factory NativeUint32List.fromList(List<int> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeUint32List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Uint32List;
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS<int>('!', '#[#]', this, index);
+ }
+
+ Uint32List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source =
+ JS<NativeUint32List>('!', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeUint32List _create1(arg) =>
+ JS<NativeUint32List>('!', 'new Uint32Array(#)', arg);
+
+ static NativeUint32List _create2(arg1, arg2) =>
+ JS<NativeUint32List>('!', 'new Uint32Array(#, #)', arg1, arg2);
+
+ static NativeUint32List _create3(arg1, arg2, arg3) =>
+ JS<NativeUint32List>('!', 'new Uint32Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native("Uint8ClampedArray,CanvasPixelArray")
+class NativeUint8ClampedList extends NativeTypedArrayOfInt
+ implements Uint8ClampedList {
+ factory NativeUint8ClampedList(int length) => _create1(_checkLength(length));
+
+ factory NativeUint8ClampedList.fromList(List<int> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeUint8ClampedList.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Uint8ClampedList;
+
+ int get length => JS<int>('!', '#.length', this);
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS<int>('!', '#[#]', this, index);
+ }
+
+ Uint8ClampedList sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source =
+ JS<NativeUint8ClampedList>('!', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeUint8ClampedList _create1(arg) =>
+ JS<NativeUint8ClampedList>('!', 'new Uint8ClampedArray(#)', arg);
+
+ static NativeUint8ClampedList _create2(arg1, arg2) =>
+ JS<NativeUint8ClampedList>(
+ '!', 'new Uint8ClampedArray(#, #)', arg1, arg2);
+
+ static NativeUint8ClampedList _create3(arg1, arg2, arg3) => JS(
+ 'NativeUint8ClampedList',
+ 'new Uint8ClampedArray(#, #, #)',
+ arg1,
+ arg2,
+ arg3);
+}
+
+// On some browsers Uint8ClampedArray is a subtype of Uint8Array. Marking
+// Uint8List as !nonleaf ensures that the native dispatch correctly handles
+// the potential for Uint8ClampedArray to 'accidentally' pick up the
+// dispatch record for Uint8List.
+@Native("Uint8Array,!nonleaf")
+class NativeUint8List extends NativeTypedArrayOfInt implements Uint8List {
+ factory NativeUint8List(int length) => _create1(_checkLength(length));
+
+ factory NativeUint8List.fromList(List<int> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeUint8List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Uint8List;
+
+ int get length => JS<int>('!', '#.length', this);
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS<int>('!', '#[#]', this, index);
+ }
+
+ Uint8List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS<NativeUint8List>('!', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeUint8List _create1(arg) =>
+ JS<NativeUint8List>('!', 'new Uint8Array(#)', arg);
+
+ static NativeUint8List _create2(arg1, arg2) =>
+ JS<NativeUint8List>('!', 'new Uint8Array(#, #)', arg1, arg2);
+
+ static NativeUint8List _create3(arg1, arg2, arg3) =>
+ JS<NativeUint8List>('!', 'new Uint8Array(#, #, #)', arg1, arg2, arg3);
+}
+
+/**
+ * Implementation of Dart Float32x4 immutable value type and operations.
+ * Float32x4 stores 4 32-bit floating point values in "lanes".
+ * The lanes are "x", "y", "z", and "w" respectively.
+ */
+class NativeFloat32x4 implements Float32x4 {
+ final double x;
+ final double y;
+ final double z;
+ final double w;
+
+ static final NativeFloat32List _list = NativeFloat32List(4);
+ static final Uint32List _uint32view = _list.buffer.asUint32List();
+
+ static _truncate(x) {
+ _list[0] = x;
+ return _list[0];
+ }
+
+ NativeFloat32x4(double x, double y, double z, double w)
+ : this.x = _truncate(x),
+ this.y = _truncate(y),
+ this.z = _truncate(z),
+ this.w = _truncate(w) {
+ // We would prefer to check for `double` but in dart2js we can't see the
+ // difference anyway.
+ if (x is! num) throw ArgumentError(x);
+ if (y is! num) throw ArgumentError(y);
+ if (z is! num) throw ArgumentError(z);
+ if (w is! num) throw ArgumentError(w);
+ }
+
+ NativeFloat32x4.splat(double v) : this(v, v, v, v);
+ NativeFloat32x4.zero() : this._truncated(0.0, 0.0, 0.0, 0.0);
+
+ /// Returns a bit-wise copy of [i] as a Float32x4.
+ factory NativeFloat32x4.fromInt32x4Bits(Int32x4 i) {
+ _uint32view[0] = i.x;
+ _uint32view[1] = i.y;
+ _uint32view[2] = i.z;
+ _uint32view[3] = i.w;
+ return NativeFloat32x4._truncated(_list[0], _list[1], _list[2], _list[3]);
+ }
+
+ NativeFloat32x4.fromFloat64x2(Float64x2 v)
+ : this._truncated(_truncate(v.x), _truncate(v.y), 0.0, 0.0);
+
+ /// Creates a new NativeFloat32x4.
+ ///
+ /// Does not verify if the given arguments are non-null.
+ NativeFloat32x4._doubles(double x, double y, double z, double w)
+ : this.x = _truncate(x),
+ this.y = _truncate(y),
+ this.z = _truncate(z),
+ this.w = _truncate(w);
+
+ /// Creates a new NativeFloat32x4.
+ ///
+ /// The constructor does not truncate the arguments. They must already be in
+ /// the correct range. It does not verify the type of the given arguments,
+ /// either.
+ NativeFloat32x4._truncated(this.x, this.y, this.z, this.w);
+
+ String toString() {
+ return '[$x, $y, $z, $w]';
+ }
+
+ /// Addition operator.
+ Float32x4 operator +(Float32x4 other) {
+ double _x = x + other.x;
+ double _y = y + other.y;
+ double _z = z + other.z;
+ double _w = w + other.w;
+ return NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Negate operator.
+ Float32x4 operator -() {
+ return NativeFloat32x4._truncated(-x, -y, -z, -w);
+ }
+
+ /// Subtraction operator.
+ Float32x4 operator -(Float32x4 other) {
+ double _x = x - other.x;
+ double _y = y - other.y;
+ double _z = z - other.z;
+ double _w = w - other.w;
+ return NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Multiplication operator.
+ Float32x4 operator *(Float32x4 other) {
+ double _x = x * other.x;
+ double _y = y * other.y;
+ double _z = z * other.z;
+ double _w = w * other.w;
+ return NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Division operator.
+ Float32x4 operator /(Float32x4 other) {
+ double _x = x / other.x;
+ double _y = y / other.y;
+ double _z = z / other.z;
+ double _w = w / other.w;
+ return NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Relational less than.
+ Int32x4 lessThan(Float32x4 other) {
+ bool _cx = x < other.x;
+ bool _cy = y < other.y;
+ bool _cz = z < other.z;
+ bool _cw = w < other.w;
+ return NativeInt32x4._truncated(
+ _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+ }
+
+ /// Relational less than or equal.
+ Int32x4 lessThanOrEqual(Float32x4 other) {
+ bool _cx = x <= other.x;
+ bool _cy = y <= other.y;
+ bool _cz = z <= other.z;
+ bool _cw = w <= other.w;
+ return NativeInt32x4._truncated(
+ _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+ }
+
+ /// Relational greater than.
+ Int32x4 greaterThan(Float32x4 other) {
+ bool _cx = x > other.x;
+ bool _cy = y > other.y;
+ bool _cz = z > other.z;
+ bool _cw = w > other.w;
+ return NativeInt32x4._truncated(
+ _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+ }
+
+ /// Relational greater than or equal.
+ Int32x4 greaterThanOrEqual(Float32x4 other) {
+ bool _cx = x >= other.x;
+ bool _cy = y >= other.y;
+ bool _cz = z >= other.z;
+ bool _cw = w >= other.w;
+ return NativeInt32x4._truncated(
+ _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+ }
+
+ /// Relational equal.
+ Int32x4 equal(Float32x4 other) {
+ bool _cx = x == other.x;
+ bool _cy = y == other.y;
+ bool _cz = z == other.z;
+ bool _cw = w == other.w;
+ return NativeInt32x4._truncated(
+ _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+ }
+
+ /// Relational not-equal.
+ Int32x4 notEqual(Float32x4 other) {
+ bool _cx = x != other.x;
+ bool _cy = y != other.y;
+ bool _cz = z != other.z;
+ bool _cw = w != other.w;
+ return NativeInt32x4._truncated(
+ _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+ }
+
+ /// Returns a copy of [this] each lane being scaled by [s].
+ Float32x4 scale(double s) {
+ double _x = s * x;
+ double _y = s * y;
+ double _z = s * z;
+ double _w = s * w;
+ return NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Returns the absolute value of this [Float32x4].
+ Float32x4 abs() {
+ double _x = x.abs();
+ double _y = y.abs();
+ double _z = z.abs();
+ double _w = w.abs();
+ return NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
+ Float32x4 clamp(Float32x4 lowerLimit, Float32x4 upperLimit) {
+ double _lx = lowerLimit.x;
+ double _ly = lowerLimit.y;
+ double _lz = lowerLimit.z;
+ double _lw = lowerLimit.w;
+ double _ux = upperLimit.x;
+ double _uy = upperLimit.y;
+ double _uz = upperLimit.z;
+ double _uw = upperLimit.w;
+ double _x = x;
+ double _y = y;
+ double _z = z;
+ double _w = w;
+ // MAX(MIN(self, upper), lower).
+ _x = _x > _ux ? _ux : _x;
+ _y = _y > _uy ? _uy : _y;
+ _z = _z > _uz ? _uz : _z;
+ _w = _w > _uw ? _uw : _w;
+ _x = _x < _lx ? _lx : _x;
+ _y = _y < _ly ? _ly : _y;
+ _z = _z < _lz ? _lz : _z;
+ _w = _w < _lw ? _lw : _w;
+ return NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Extract the sign bit from each lane return them in the first 4 bits.
+ int get signMask {
+ var view = _uint32view;
+ var mx, my, mz, mw;
+ _list[0] = x;
+ _list[1] = y;
+ _list[2] = z;
+ _list[3] = w;
+ // This is correct because dart2js uses the unsigned right shift.
+ mx = (view[0] & 0x80000000) >> 31;
+ my = (view[1] & 0x80000000) >> 30;
+ mz = (view[2] & 0x80000000) >> 29;
+ mw = (view[3] & 0x80000000) >> 28;
+ return mx | my | mz | mw;
+ }
+
+ /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
+ Float32x4 shuffle(int mask) {
+ if ((mask < 0) || (mask > 255)) {
+ throw RangeError.range(mask, 0, 255, "mask");
+ }
+ _list[0] = x;
+ _list[1] = y;
+ _list[2] = z;
+ _list[3] = w;
+
+ double _x = _list[mask & 0x3];
+ double _y = _list[(mask >> 2) & 0x3];
+ double _z = _list[(mask >> 4) & 0x3];
+ double _w = _list[(mask >> 6) & 0x3];
+ return NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Shuffle the lane values in [this] and [other]. The returned
+ /// Float32x4 will have XY lanes from [this] and ZW lanes from [other].
+ /// Uses the same [mask] as [shuffle].
+ Float32x4 shuffleMix(Float32x4 other, int mask) {
+ if ((mask < 0) || (mask > 255)) {
+ throw RangeError.range(mask, 0, 255, "mask");
+ }
+ _list[0] = x;
+ _list[1] = y;
+ _list[2] = z;
+ _list[3] = w;
+ double _x = _list[mask & 0x3];
+ double _y = _list[(mask >> 2) & 0x3];
+
+ _list[0] = other.x;
+ _list[1] = other.y;
+ _list[2] = other.z;
+ _list[3] = other.w;
+ double _z = _list[(mask >> 4) & 0x3];
+ double _w = _list[(mask >> 6) & 0x3];
+ return NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Copy [this] and replace the [x] lane.
+ Float32x4 withX(double newX) {
+ return NativeFloat32x4._truncated(_truncate(newX), y, z, w);
+ }
+
+ /// Copy [this] and replace the [y] lane.
+ Float32x4 withY(double newY) {
+ return NativeFloat32x4._truncated(x, _truncate(newY), z, w);
+ }
+
+ /// Copy [this] and replace the [z] lane.
+ Float32x4 withZ(double newZ) {
+ return NativeFloat32x4._truncated(x, y, _truncate(newZ), w);
+ }
+
+ /// Copy [this] and replace the [w] lane.
+ Float32x4 withW(double newW) {
+ return NativeFloat32x4._truncated(x, y, z, _truncate(newW));
+ }
+
+ /// Returns the lane-wise minimum value in [this] or [other].
+ Float32x4 min(Float32x4 other) {
+ double _x = x < other.x ? x : other.x;
+ double _y = y < other.y ? y : other.y;
+ double _z = z < other.z ? z : other.z;
+ double _w = w < other.w ? w : other.w;
+ return NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Returns the lane-wise maximum value in [this] or [other].
+ Float32x4 max(Float32x4 other) {
+ double _x = x > other.x ? x : other.x;
+ double _y = y > other.y ? y : other.y;
+ double _z = z > other.z ? z : other.z;
+ double _w = w > other.w ? w : other.w;
+ return NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Returns the square root of [this].
+ Float32x4 sqrt() {
+ double _x = Math.sqrt(x);
+ double _y = Math.sqrt(y);
+ double _z = Math.sqrt(z);
+ double _w = Math.sqrt(w);
+ return NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Returns the reciprocal of [this].
+ Float32x4 reciprocal() {
+ double _x = 1.0 / x;
+ double _y = 1.0 / y;
+ double _z = 1.0 / z;
+ double _w = 1.0 / w;
+ return NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Returns the square root of the reciprocal of [this].
+ Float32x4 reciprocalSqrt() {
+ double _x = Math.sqrt(1.0 / x);
+ double _y = Math.sqrt(1.0 / y);
+ double _z = Math.sqrt(1.0 / z);
+ double _w = Math.sqrt(1.0 / w);
+ return NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+}
+
+/**
+ * Interface of Dart Int32x4 and operations.
+ * Int32x4 stores 4 32-bit bit-masks in "lanes".
+ * The lanes are "x", "y", "z", and "w" respectively.
+ */
+class NativeInt32x4 implements Int32x4 {
+ final int x;
+ final int y;
+ final int z;
+ final int w;
+
+ static final _list = NativeInt32List(4);
+
+ static _truncate(x) {
+ _list[0] = x;
+ return _list[0];
+ }
+
+ NativeInt32x4(int x, int y, int z, int w)
+ : this.x = _truncate(x),
+ this.y = _truncate(y),
+ this.z = _truncate(z),
+ this.w = _truncate(w) {
+ if (x != this.x && x is! int) throw ArgumentError(x);
+ if (y != this.y && y is! int) throw ArgumentError(y);
+ if (z != this.z && z is! int) throw ArgumentError(z);
+ if (w != this.w && w is! int) throw ArgumentError(w);
+ }
+
+ NativeInt32x4.bool(bool x, bool y, bool z, bool w)
+ : this.x = x ? -1 : 0,
+ this.y = y ? -1 : 0,
+ this.z = z ? -1 : 0,
+ this.w = w ? -1 : 0;
+
+ /// Returns a bit-wise copy of [f] as a Int32x4.
+ factory NativeInt32x4.fromFloat32x4Bits(Float32x4 f) {
+ NativeFloat32List floatList = NativeFloat32x4._list;
+ floatList[0] = f.x;
+ floatList[1] = f.y;
+ floatList[2] = f.z;
+ floatList[3] = f.w;
+ NativeInt32List view = floatList.buffer.asInt32List();
+ return NativeInt32x4._truncated(view[0], view[1], view[2], view[3]);
+ }
+
+ NativeInt32x4._truncated(this.x, this.y, this.z, this.w);
+
+ String toString() => '[$x, $y, $z, $w]';
+
+ /// The bit-wise or operator.
+ Int32x4 operator |(Int32x4 other) {
+ // Dart2js uses unsigned results for bit-operations.
+ // We use "JS" to fall back to the signed versions.
+ return NativeInt32x4._truncated(
+ JS("int", "# | #", x, other.x),
+ JS("int", "# | #", y, other.y),
+ JS("int", "# | #", z, other.z),
+ JS("int", "# | #", w, other.w));
+ }
+
+ /// The bit-wise and operator.
+ Int32x4 operator &(Int32x4 other) {
+ // Dart2js uses unsigned results for bit-operations.
+ // We use "JS" to fall back to the signed versions.
+ return NativeInt32x4._truncated(
+ JS("int", "# & #", x, other.x),
+ JS("int", "# & #", y, other.y),
+ JS("int", "# & #", z, other.z),
+ JS("int", "# & #", w, other.w));
+ }
+
+ /// The bit-wise xor operator.
+ Int32x4 operator ^(Int32x4 other) {
+ // Dart2js uses unsigned results for bit-operations.
+ // We use "JS" to fall back to the signed versions.
+ return NativeInt32x4._truncated(
+ JS("int", "# ^ #", x, other.x),
+ JS("int", "# ^ #", y, other.y),
+ JS("int", "# ^ #", z, other.z),
+ JS("int", "# ^ #", w, other.w));
+ }
+
+ Int32x4 operator +(Int32x4 other) {
+ // Avoid going through the typed array by "| 0" the result.
+ return NativeInt32x4._truncated(
+ JS("int", "(# + #) | 0", x, other.x),
+ JS("int", "(# + #) | 0", y, other.y),
+ JS("int", "(# + #) | 0", z, other.z),
+ JS("int", "(# + #) | 0", w, other.w));
+ }
+
+ Int32x4 operator -(Int32x4 other) {
+ // Avoid going through the typed array by "| 0" the result.
+ return NativeInt32x4._truncated(
+ JS("int", "(# - #) | 0", x, other.x),
+ JS("int", "(# - #) | 0", y, other.y),
+ JS("int", "(# - #) | 0", z, other.z),
+ JS("int", "(# - #) | 0", w, other.w));
+ }
+
+ Int32x4 operator -() {
+ // Avoid going through the typed array by "| 0" the result.
+ return NativeInt32x4._truncated(
+ JS("int", "(-#) | 0", x),
+ JS("int", "(-#) | 0", y),
+ JS("int", "(-#) | 0", z),
+ JS("int", "(-#) | 0", w));
+ }
+
+ /// Extract the top bit from each lane return them in the first 4 bits.
+ int get signMask {
+ int mx = (x & 0x80000000) >> 31;
+ int my = (y & 0x80000000) >> 31;
+ int mz = (z & 0x80000000) >> 31;
+ int mw = (w & 0x80000000) >> 31;
+ return mx | my << 1 | mz << 2 | mw << 3;
+ }
+
+ /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
+ Int32x4 shuffle(int mask) {
+ if ((mask < 0) || (mask > 255)) {
+ throw RangeError.range(mask, 0, 255, "mask");
+ }
+ _list[0] = x;
+ _list[1] = y;
+ _list[2] = z;
+ _list[3] = w;
+ int _x = _list[mask & 0x3];
+ int _y = _list[(mask >> 2) & 0x3];
+ int _z = _list[(mask >> 4) & 0x3];
+ int _w = _list[(mask >> 6) & 0x3];
+ return NativeInt32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Shuffle the lane values in [this] and [other]. The returned
+ /// Int32x4 will have XY lanes from [this] and ZW lanes from [other].
+ /// Uses the same [mask] as [shuffle].
+ Int32x4 shuffleMix(Int32x4 other, int mask) {
+ if ((mask < 0) || (mask > 255)) {
+ throw RangeError.range(mask, 0, 255, "mask");
+ }
+ _list[0] = x;
+ _list[1] = y;
+ _list[2] = z;
+ _list[3] = w;
+ int _x = _list[mask & 0x3];
+ int _y = _list[(mask >> 2) & 0x3];
+
+ _list[0] = other.x;
+ _list[1] = other.y;
+ _list[2] = other.z;
+ _list[3] = other.w;
+ int _z = _list[(mask >> 4) & 0x3];
+ int _w = _list[(mask >> 6) & 0x3];
+ return NativeInt32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new x value.
+ Int32x4 withX(int x) {
+ int _x = _truncate(x);
+ return NativeInt32x4._truncated(_x, y, z, w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new y value.
+ Int32x4 withY(int y) {
+ int _y = _truncate(y);
+ return NativeInt32x4._truncated(x, _y, z, w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new z value.
+ Int32x4 withZ(int z) {
+ int _z = _truncate(z);
+ return NativeInt32x4._truncated(x, y, _z, w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new w value.
+ Int32x4 withW(int w) {
+ int _w = _truncate(w);
+ return NativeInt32x4._truncated(x, y, z, _w);
+ }
+
+ /// Extracted x value. Returns `false` for 0, `true` for any other value.
+ bool get flagX => x != 0;
+
+ /// Extracted y value. Returns `false` for 0, `true` for any other value.
+ bool get flagY => y != 0;
+
+ /// Extracted z value. Returns `false` for 0, `true` for any other value.
+ bool get flagZ => z != 0;
+
+ /// Extracted w value. Returns `false` for 0, `true` for any other value.
+ bool get flagW => w != 0;
+
+ /// Returns a new [Int32x4] copied from [this] with a new x value.
+ Int32x4 withFlagX(bool flagX) {
+ int _x = flagX ? -1 : 0;
+ return NativeInt32x4._truncated(_x, y, z, w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new y value.
+ Int32x4 withFlagY(bool flagY) {
+ int _y = flagY ? -1 : 0;
+ return NativeInt32x4._truncated(x, _y, z, w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new z value.
+ Int32x4 withFlagZ(bool flagZ) {
+ int _z = flagZ ? -1 : 0;
+ return NativeInt32x4._truncated(x, y, _z, w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new w value.
+ Int32x4 withFlagW(bool flagW) {
+ int _w = flagW ? -1 : 0;
+ return NativeInt32x4._truncated(x, y, z, _w);
+ }
+
+ /// Merge [trueValue] and [falseValue] based on [this]' bit mask:
+ /// Select bit from [trueValue] when bit in [this] is on.
+ /// Select bit from [falseValue] when bit in [this] is off.
+ Float32x4 select(Float32x4 trueValue, Float32x4 falseValue) {
+ var floatList = NativeFloat32x4._list;
+ var intView = NativeFloat32x4._uint32view;
+
+ floatList[0] = trueValue.x;
+ floatList[1] = trueValue.y;
+ floatList[2] = trueValue.z;
+ floatList[3] = trueValue.w;
+ int stx = intView[0];
+ int sty = intView[1];
+ int stz = intView[2];
+ int stw = intView[3];
+
+ floatList[0] = falseValue.x;
+ floatList[1] = falseValue.y;
+ floatList[2] = falseValue.z;
+ floatList[3] = falseValue.w;
+ int sfx = intView[0];
+ int sfy = intView[1];
+ int sfz = intView[2];
+ int sfw = intView[3];
+ int _x = (x & stx) | (~x & sfx);
+ int _y = (y & sty) | (~y & sfy);
+ int _z = (z & stz) | (~z & sfz);
+ int _w = (w & stw) | (~w & sfw);
+ intView[0] = _x;
+ intView[1] = _y;
+ intView[2] = _z;
+ intView[3] = _w;
+ return NativeFloat32x4._truncated(
+ floatList[0], floatList[1], floatList[2], floatList[3]);
+ }
+}
+
+class NativeFloat64x2 implements Float64x2 {
+ final double x;
+ final double y;
+
+ static NativeFloat64List _list = NativeFloat64List(2);
+ static NativeUint32List _uint32View = _list.buffer.asUint32List();
+
+ NativeFloat64x2(this.x, this.y) {
+ if (x is! num) throw ArgumentError(x);
+ if (y is! num) throw ArgumentError(y);
+ }
+
+ NativeFloat64x2.splat(double v) : this(v, v);
+
+ NativeFloat64x2.zero() : this.splat(0.0);
+
+ NativeFloat64x2.fromFloat32x4(Float32x4 v) : this(v.x, v.y);
+
+ /// Arguments [x] and [y] must be doubles.
+ NativeFloat64x2._doubles(this.x, this.y);
+
+ String toString() => '[$x, $y]';
+
+ /// Addition operator.
+ Float64x2 operator +(Float64x2 other) {
+ return NativeFloat64x2._doubles(x + other.x, y + other.y);
+ }
+
+ /// Negate operator.
+ Float64x2 operator -() {
+ return NativeFloat64x2._doubles(-x, -y);
+ }
+
+ /// Subtraction operator.
+ Float64x2 operator -(Float64x2 other) {
+ return NativeFloat64x2._doubles(x - other.x, y - other.y);
+ }
+
+ /// Multiplication operator.
+ Float64x2 operator *(Float64x2 other) {
+ return NativeFloat64x2._doubles(x * other.x, y * other.y);
+ }
+
+ /// Division operator.
+ Float64x2 operator /(Float64x2 other) {
+ return NativeFloat64x2._doubles(x / other.x, y / other.y);
+ }
+
+ /// Returns a copy of [this] each lane being scaled by [s].
+ Float64x2 scale(double s) {
+ return NativeFloat64x2._doubles(x * s, y * s);
+ }
+
+ /// Returns the absolute value of this [Float64x2].
+ Float64x2 abs() {
+ return NativeFloat64x2._doubles(x.abs(), y.abs());
+ }
+
+ /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
+ Float64x2 clamp(Float64x2 lowerLimit, Float64x2 upperLimit) {
+ double _lx = lowerLimit.x;
+ double _ly = lowerLimit.y;
+ double _ux = upperLimit.x;
+ double _uy = upperLimit.y;
+ double _x = x;
+ double _y = y;
+ // MAX(MIN(self, upper), lower).
+ _x = _x > _ux ? _ux : _x;
+ _y = _y > _uy ? _uy : _y;
+ _x = _x < _lx ? _lx : _x;
+ _y = _y < _ly ? _ly : _y;
+ return NativeFloat64x2._doubles(_x, _y);
+ }
+
+ /// Extract the sign bits from each lane return them in the first 2 bits.
+ int get signMask {
+ var view = _uint32View;
+ _list[0] = x;
+ _list[1] = y;
+ var mx = (view[1] & 0x80000000) >> 31;
+ var my = (view[3] & 0x80000000) >> 31;
+ return mx | my << 1;
+ }
+
+ /// Returns a new [Float64x2] copied from [this] with a new x value.
+ Float64x2 withX(double x) {
+ if (x is! num) throw ArgumentError(x);
+ return NativeFloat64x2._doubles(x, y);
+ }
+
+ /// Returns a new [Float64x2] copied from [this] with a new y value.
+ Float64x2 withY(double y) {
+ if (y is! num) throw ArgumentError(y);
+ return NativeFloat64x2._doubles(x, y);
+ }
+
+ /// Returns the lane-wise minimum value in [this] or [other].
+ Float64x2 min(Float64x2 other) {
+ return NativeFloat64x2._doubles(
+ x < other.x ? x : other.x, y < other.y ? y : other.y);
+ }
+
+ /// Returns the lane-wise maximum value in [this] or [other].
+ Float64x2 max(Float64x2 other) {
+ return NativeFloat64x2._doubles(
+ x > other.x ? x : other.x, y > other.y ? y : other.y);
+ }
+
+ /// Returns the lane-wise square root of [this].
+ Float64x2 sqrt() {
+ return NativeFloat64x2._doubles(Math.sqrt(x), Math.sqrt(y));
+ }
+}
+
+/// Checks that the value is a Uint32. If not, it's not valid as an array
+/// index or offset. Also ensures that the value is non-negative.
+bool _isInvalidArrayIndex(int index) {
+ return (JS<bool>('!', '(# >>> 0 !== #)', index, index));
+}
+
+/// Checks that [index] is a valid index into [list] which has length [length].
+///
+/// That is, [index] is an integer in the range `0..length - 1`.
+void _checkValidIndex(int index, List list, int length) {
+ if (_isInvalidArrayIndex(index) || JS<int>('!', '#', index) >= length) {
+ throw diagnoseIndexError(list, index);
+ }
+}
+
+/// Checks that [start] and [end] form a range of a list of length [length].
+///
+/// That is: `start` and `end` are integers with `0 <= start <= end <= length`.
+/// If `end` is `null` in which case it is considered to be `length`
+///
+/// Returns the actual value of `end`, which is `length` if `end` is `null`, and
+/// the original value of `end` otherwise.
+int _checkValidRange(int start, int end, int length) {
+ if (_isInvalidArrayIndex(start) || // Ensures start is non-negative int.
+ ((end == null)
+ ? start > length
+ : (_isInvalidArrayIndex(end) || start > end || end > length))) {
+ throw diagnoseRangeError(start, end, length);
+ }
+ if (end == null) return length;
+ return end;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/README b/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/README
new file mode 100644
index 0000000..7eb614e
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/README
@@ -0,0 +1,17 @@
+The files in this directory polyfill some of the functionality that browsers
+provide. When running command-line JS evaluators it is frequently necessary to
+execute the preambles before executing the output of dart2js.
+
+=Usage=
+- d8:
+ d8 <sdk>/lib/_internal/compiler/js_lib/preambles/d8.js <output>.js
+
+- jsshell:
+ jsshell -f <sdk>/lib/_internal/compiler/js_lib/preambles/d8.js -f <output>.js
+
+- node.js:
+ The d8 preamble file works for most programs.
+
+ Unfortunately we are not aware of any easy way to provide multiple input files
+ to node. It seems to be necessary to concatenate the d8 preamble and the
+ dart2js output.
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/d8.js b/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/d8.js
new file mode 100644
index 0000000..0c432f5
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/d8.js
@@ -0,0 +1,291 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Javascript preamble, that lets the output of dart2js run on V8's d8 shell.
+
+// Node wraps files and provides them with a different `this`. The global
+// `this` can be accessed through `global`.
+
+var self = this;
+if (typeof global != "undefined") self = global; // Node.js.
+
+(function(self) {
+ // Using strict mode to avoid accidentally defining global variables.
+ "use strict"; // Should be first statement of this function.
+
+ // Location (Uri.base)
+
+ var workingDirectory;
+ // TODO(sgjesse): This does not work on Windows.
+ if (typeof os == "object" && "system" in os) {
+ // V8.
+ workingDirectory = os.system("pwd");
+ var length = workingDirectory.length;
+ if (workingDirectory[length - 1] == '\n') {
+ workingDirectory = workingDirectory.substring(0, length - 1);
+ }
+ } else if (typeof process != "undefined" &&
+ typeof process.cwd == "function") {
+ // Node.js.
+ workingDirectory = process.cwd();
+ }
+ self.location = { href: "file://" + workingDirectory + "/" };
+
+ // Event loop.
+ // Task queue as cyclic list queue.
+ var taskQueue = new Array(8); // Length is power of 2.
+ var head = 0;
+ var tail = 0;
+ var mask = taskQueue.length - 1;
+ function addTask(elem) {
+ taskQueue[head] = elem;
+ head = (head + 1) & mask;
+ if (head == tail) _growTaskQueue();
+ }
+ function removeTask() {
+ if (head == tail) return;
+ var result = taskQueue[tail];
+ taskQueue[tail] = undefined;
+ tail = (tail + 1) & mask;
+ return result;
+ }
+ function _growTaskQueue() {
+ // head == tail.
+ var length = taskQueue.length;
+ var split = head;
+ taskQueue.length = length * 2;
+ if (split * 2 < length) { // split < length / 2
+ for (var i = 0; i < split; i++) {
+ taskQueue[length + i] = taskQueue[i];
+ taskQueue[i] = undefined;
+ }
+ head += length;
+ } else {
+ for (var i = split; i < length; i++) {
+ taskQueue[length + i] = taskQueue[i];
+ taskQueue[i] = undefined;
+ }
+ tail += length;
+ }
+ mask = taskQueue.length - 1;
+ }
+
+ // Mapping from timer id to timer function.
+ // The timer id is written on the function as .$timerId.
+ // That field is cleared when the timer is cancelled, but it is not returned
+ // from the queue until its time comes.
+ var timerIds = {};
+ var timerIdCounter = 1; // Counter used to assign ids.
+
+ // Zero-timer queue as simple array queue using push/shift.
+ var zeroTimerQueue = [];
+
+ function addTimer(f, ms) {
+ var id = timerIdCounter++;
+ f.$timerId = id;
+ timerIds[id] = f;
+ if (ms == 0 && !isNextTimerDue()) {
+ zeroTimerQueue.push(f);
+ } else {
+ addDelayedTimer(f, ms);
+ }
+ return id;
+ }
+
+ function nextZeroTimer() {
+ while (zeroTimerQueue.length > 0) {
+ var action = zeroTimerQueue.shift();
+ if (action.$timerId !== undefined) return action;
+ }
+ }
+
+ function nextEvent() {
+ var action = removeTask();
+ if (action) {
+ return action;
+ }
+ do {
+ action = nextZeroTimer();
+ if (action) break;
+ var nextList = nextDelayedTimerQueue();
+ if (!nextList) {
+ return;
+ }
+ var newTime = nextList.shift();
+ advanceTimeTo(newTime);
+ zeroTimerQueue = nextList;
+ } while (true)
+ var id = action.$timerId;
+ clearTimerId(action, id);
+ return action;
+ }
+
+ // Mocking time.
+ var timeOffset = 0;
+ var now = function() {
+ // Install the mock Date object only once.
+ // Following calls to "now" will just use the new (mocked) Date.now
+ // method directly.
+ installMockDate();
+ now = Date.now;
+ return Date.now();
+ };
+ var originalDate = Date;
+ var originalNow = originalDate.now;
+ function advanceTimeTo(time) {
+ var now = originalNow();
+ if (timeOffset < time - now) {
+ timeOffset = time - now;
+ }
+ }
+ function installMockDate() {
+ var NewDate = function Date(Y, M, D, h, m, s, ms) {
+ if (this instanceof Date) {
+ // Assume a construct call.
+ switch (arguments.length) {
+ case 0: return new originalDate(originalNow() + timeOffset);
+ case 1: return new originalDate(Y);
+ case 2: return new originalDate(Y, M);
+ case 3: return new originalDate(Y, M, D);
+ case 4: return new originalDate(Y, M, D, h);
+ case 5: return new originalDate(Y, M, D, h, m);
+ case 6: return new originalDate(Y, M, D, h, m, s);
+ default: return new originalDate(Y, M, D, h, m, s, ms);
+ }
+ }
+ return new originalDate(originalNow() + timeOffset).toString();
+ };
+ NewDate.UTC = originalDate.UTC;
+ NewDate.parse = originalDate.parse;
+ NewDate.now = function now() { return originalNow() + timeOffset; };
+ NewDate.prototype = originalDate.prototype;
+ originalDate.prototype.constructor = NewDate;
+ Date = NewDate;
+ }
+
+ // Heap priority queue with key index.
+ // Each entry is list of [timeout, callback1 ... callbackn].
+ var timerHeap = [];
+ var timerIndex = {};
+ function addDelayedTimer(f, ms) {
+ var timeout = now() + ms;
+ var timerList = timerIndex[timeout];
+ if (timerList == null) {
+ timerList = [timeout, f];
+ timerIndex[timeout] = timerList;
+ var index = timerHeap.length;
+ timerHeap.length += 1;
+ bubbleUp(index, timeout, timerList);
+ } else {
+ timerList.push(f);
+ }
+ }
+
+ function isNextTimerDue() {
+ if (timerHeap.length == 0) return false;
+ var head = timerHeap[0];
+ return head[0] < originalNow() + timeOffset;
+ }
+
+ function nextDelayedTimerQueue() {
+ if (timerHeap.length == 0) return null;
+ var result = timerHeap[0];
+ var last = timerHeap.pop();
+ if (timerHeap.length > 0) {
+ bubbleDown(0, last[0], last);
+ }
+ return result;
+ }
+
+ function bubbleUp(index, key, value) {
+ while (index != 0) {
+ var parentIndex = (index - 1) >> 1;
+ var parent = timerHeap[parentIndex];
+ var parentKey = parent[0];
+ if (key > parentKey) break;
+ timerHeap[index] = parent;
+ index = parentIndex;
+ }
+ timerHeap[index] = value;
+ }
+
+ function bubbleDown(index, key, value) {
+ while (true) {
+ var leftChildIndex = index * 2 + 1;
+ if (leftChildIndex >= timerHeap.length) break;
+ var minChildIndex = leftChildIndex;
+ var minChild = timerHeap[leftChildIndex];
+ var minChildKey = minChild[0];
+ var rightChildIndex = leftChildIndex + 1;
+ if (rightChildIndex < timerHeap.length) {
+ var rightChild = timerHeap[rightChildIndex];
+ var rightKey = rightChild[0];
+ if (rightKey < minChildKey) {
+ minChildIndex = rightChildIndex;
+ minChild = rightChild;
+ minChildKey = rightKey;
+ }
+ }
+ if (minChildKey > key) break;
+ timerHeap[index] = minChild;
+ index = minChildIndex;
+ }
+ timerHeap[index] = value;
+ }
+
+ function addInterval(f, ms) {
+ var id = timerIdCounter++;
+ function repeat() {
+ // Reactivate with the same id.
+ repeat.$timerId = id;
+ timerIds[id] = repeat;
+ addDelayedTimer(repeat, ms);
+ f();
+ }
+ repeat.$timerId = id;
+ timerIds[id] = repeat;
+ addDelayedTimer(repeat, ms);
+ return id;
+ }
+
+ function cancelTimer(id) {
+ var f = timerIds[id];
+ if (f == null) return;
+ clearTimerId(f, id);
+ }
+
+ function clearTimerId(f, id) {
+ f.$timerId = undefined;
+ delete timerIds[id];
+ }
+
+ function eventLoop(action) {
+ while (action) {
+ try {
+ action();
+ } catch (e) {
+ if (typeof onerror == "function") {
+ onerror(e, null, -1);
+ } else {
+ throw e;
+ }
+ }
+ action = nextEvent();
+ }
+ }
+
+ // Global properties. "self" refers to the global object, so adding a
+ // property to "self" defines a global variable.
+ self.dartMainRunner = function(main, args) {
+ // Initialize.
+ var action = function() { main(args); }
+ eventLoop(action);
+ };
+ self.setTimeout = addTimer;
+ self.clearTimeout = cancelTimer;
+ self.setInterval = addInterval;
+ self.clearInterval = cancelTimer;
+ self.scheduleImmediate = addTask;
+ self.self = self;
+})(self);
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/jsshell.js b/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/jsshell.js
new file mode 100644
index 0000000..8f13bcc
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/preambles/jsshell.js
@@ -0,0 +1,19 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Javascript preamble, that lets the output of dart2js run on JSShell.
+
+(function(self) {
+ // Using strict mode to avoid accidentally defining global variables.
+ "use strict"; // Should be first statement of this function.
+
+ // Location (Uri.base)
+
+ var workingDirectory = environment["PWD"];
+ self.location = { href: "file://" + workingDirectory + "/" };
+
+ // Global properties. "self" refers to the global object, so adding a
+ // property to "self" defines a global variable.
+ self.self = self;
+})(this)
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/profile.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/profile.dart
new file mode 100644
index 0000000..d46f7f7
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/profile.dart
@@ -0,0 +1,135 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This file supports profiling dynamic calls.
+part of dart._debugger;
+
+class _MethodStats {
+ final String typeName;
+ final String frame;
+ double count;
+
+ _MethodStats(this.typeName, this.frame) {
+ count = 0.0;
+ }
+}
+
+class _CallMethodRecord {
+ var jsError;
+ var type;
+
+ _CallMethodRecord(this.jsError, this.type);
+}
+
+/// Size for the random sample of dynamic calls.
+int _callRecordSampleSize = 5000;
+
+/// If the number of dynamic calls exceeds [_callRecordSampleSize] this list
+/// will represent a random sample of the dynamic calls made.
+List<_CallMethodRecord> _callMethodRecords = List();
+
+/// If the number of dynamic calls exceeds [_callRecordSampleSize] this value
+/// will be greater than [_callMethodRecords.length].
+int _totalCallRecords = 0;
+
+/// Minimum number of samples to consider a profile entry relevant.
+/// This could be set a lot higher. We set this value so users are not
+/// confused into thinking that a dynamic call that occurred once but was
+/// randomly included in the sample is relevant.
+num _minCount = 2;
+
+/// Cache mapping from raw stack frames to source mapped stack frames to
+/// speedup lookup of source map frames when running the profiler.
+/// The number of source map entries looked up makes caching more important
+/// in this case than for typical source map use cases.
+Map<String, String> _frameMappingCache = Map();
+
+List<List<Object>> getDynamicStats() {
+ // Process the accumulated method stats. This may be quite slow as processing
+ // stack traces is expensive. If there are performance blockers, we should
+ // switch to a sampling approach that caps the number of _callMethodRecords
+ // and uses random sampling to decide whether to add each additional record
+ // to the sample. Main change required is that we need to still show the total
+ // raw number of dynamic calls so that the magnitude of the dynamic call
+ // performance hit is clear to users.
+
+ Map<String, _MethodStats> callMethodStats = Map();
+ if (_callMethodRecords.length > 0) {
+ // Ratio between total record count and sampled records count.
+ var recordRatio = _totalCallRecords / _callMethodRecords.length;
+ for (var record in _callMethodRecords) {
+ String stackStr = JS<String>('!', '#.stack', record.jsError);
+ var frames = stackStr.split('\n');
+ // Skip first two lines as the first couple frames are from the dart
+ // runtime.
+ var src = frames
+ .skip(2)
+ .map((f) =>
+ _frameMappingCache.putIfAbsent(f, () => stackTraceMapper('\n$f')))
+ .firstWhere((f) => !f.startsWith('dart:'), orElse: () => '');
+
+ var actualTypeName = dart.typeName(record.type);
+ callMethodStats
+ .putIfAbsent(
+ "$actualTypeName <$src>", () => _MethodStats(actualTypeName, src))
+ .count += recordRatio;
+ }
+
+ // filter out all calls that did not occur at least _minCount times in the
+ // random sample if we are dealing with a random sample instead of a
+ // complete profile.
+ if (_totalCallRecords != _callMethodRecords.length) {
+ for (var k in callMethodStats.keys.toList()) {
+ var stats = callMethodStats[k];
+ var threshold = _minCount * recordRatio;
+ if (stats.count + 0.001 < threshold) {
+ callMethodStats.remove(k);
+ }
+ }
+ }
+ }
+ _callMethodRecords.clear();
+ _totalCallRecords = 0;
+ var keys = callMethodStats.keys.toList();
+
+ keys.sort(
+ (a, b) => callMethodStats[b].count.compareTo(callMethodStats[a].count));
+ List<List<Object>> ret = [];
+ for (var key in keys) {
+ var stats = callMethodStats[key];
+ ret.add([stats.typeName, stats.frame, stats.count.round()]);
+ }
+ return ret;
+}
+
+clearDynamicStats() {
+ _callMethodRecords.clear();
+}
+
+// We need to set this property while the sdk is only partially initialized
+// so we cannot use a regular Dart field.
+bool get _trackProfile => JS<bool>('!', 'dart.__trackProfile');
+
+trackCall(obj) {
+ if (JS<bool>('!', '!#', _trackProfile)) return;
+ int index = -1;
+ _totalCallRecords++;
+ if (_callMethodRecords.length == _callRecordSampleSize) {
+ // Ensure that each sample has an equal
+ // _callRecordSampleSize / _totalCallRecords chance of inclusion
+ // by choosing to include the new record in the sample the with the
+ // appropriate probability randomly evicting one of the existing records.
+ // Unfortunately we can't use the excellent Random.nextInt method defined
+ // by Dart from within this library.
+ index = JS<int>('!', 'Math.floor(Math.random() * #)', _totalCallRecords);
+ if (index >= _callMethodRecords.length) return; // don't sample
+ }
+ var record =
+ _CallMethodRecord(JS('', 'new Error()'), dart.getReifiedType(obj));
+ if (index == -1) {
+ _callMethodRecords.add(record);
+ } else {
+ _callMethodRecords[index] = record;
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/regexp_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/regexp_helper.dart
new file mode 100644
index 0000000..fadcda0
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/regexp_helper.dart
@@ -0,0 +1,283 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._js_helper;
+
+// Helper method used by internal libraries.
+regExpGetNative(JSSyntaxRegExp regexp) => regexp._nativeRegExp;
+
+/**
+ * Returns a native version of the RegExp with the global flag set.
+ *
+ * The RegExp's `lastIndex` property is zero when it is returned.
+ *
+ * The returned regexp is shared, and its `lastIndex` property may be
+ * modified by other uses, so the returned regexp must be used immediately
+ * when it's returned, with no user-provided code run in between.
+ */
+regExpGetGlobalNative(JSSyntaxRegExp regexp) {
+ var nativeRegexp = regexp._nativeGlobalVersion;
+ JS("void", "#.lastIndex = 0", nativeRegexp);
+ return nativeRegexp;
+}
+
+/**
+ * Computes the number of captures in a regexp.
+ *
+ * This currently involves creating a new RegExp object with a different
+ * source and running it against the empty string (the last part is usually
+ * fast).
+ *
+ * The JSSyntaxRegExp could cache the result, and set the cache any time
+ * it finds a match.
+ */
+int regExpCaptureCount(JSSyntaxRegExp regexp) {
+ var nativeAnchoredRegExp = regexp._nativeAnchoredVersion;
+ JSExtendableArray match =
+ JS('JSExtendableArray', "#.exec('')", nativeAnchoredRegExp);
+ // The native-anchored regexp always have one capture more than the original,
+ // and always matches the empty string.
+ return match.length - 2;
+}
+
+class JSSyntaxRegExp implements RegExp {
+ final String pattern;
+ final _nativeRegExp;
+ var _nativeGlobalRegExp;
+ var _nativeAnchoredRegExp;
+
+ String toString() =>
+ 'RegExp/$pattern/' + JS<String>('!', '#.flags', _nativeRegExp);
+
+ JSSyntaxRegExp(String source,
+ {bool multiLine = false,
+ bool caseSensitive = true,
+ bool unicode = false,
+ bool dotAll = false})
+ : this.pattern = source,
+ this._nativeRegExp = makeNative(
+ source, multiLine, caseSensitive, unicode, dotAll, false);
+
+ get _nativeGlobalVersion {
+ if (_nativeGlobalRegExp != null) return _nativeGlobalRegExp;
+ return _nativeGlobalRegExp = makeNative(
+ pattern, _isMultiLine, _isCaseSensitive, _isUnicode, _isDotAll, true);
+ }
+
+ get _nativeAnchoredVersion {
+ if (_nativeAnchoredRegExp != null) return _nativeAnchoredRegExp;
+ // An "anchored version" of a regexp is created by adding "|()" to the
+ // source. This means that the regexp always matches at the first position
+ // that it tries, and you can see if the original regexp matched, or it
+ // was the added zero-width match that matched, by looking at the last
+ // capture. If it is a String, the match participated, otherwise it didn't.
+ return _nativeAnchoredRegExp = makeNative("$pattern|()", _isMultiLine,
+ _isCaseSensitive, _isUnicode, _isDotAll, true);
+ }
+
+ bool get _isMultiLine => JS("bool", "#.multiline", _nativeRegExp);
+ bool get _isCaseSensitive => JS("bool", "!#.ignoreCase", _nativeRegExp);
+ bool get _isUnicode => JS("bool", "#.unicode", _nativeRegExp);
+ bool get _isDotAll => JS("bool", "#.dotAll", _nativeRegExp);
+
+ static makeNative(@nullCheck String source, bool multiLine,
+ bool caseSensitive, bool unicode, bool dotAll, bool global) {
+ String m = multiLine ? 'm' : '';
+ String i = caseSensitive ? '' : 'i';
+ String u = unicode ? 'u' : '';
+ String s = dotAll ? 's' : '';
+ String g = global ? 'g' : '';
+ // We're using the JavaScript's try catch instead of the Dart one
+ // to avoid dragging in Dart runtime support just because of using
+ // RegExp.
+ var regexp = JS(
+ '',
+ '(function() {'
+ 'try {'
+ 'return new RegExp(#, # + # + # + # + #);'
+ '} catch (e) {'
+ 'return e;'
+ '}'
+ '})()',
+ source,
+ m,
+ i,
+ u,
+ s,
+ g);
+ if (JS<bool>('!', '# instanceof RegExp', regexp)) return regexp;
+ // The returned value is the JavaScript exception. Turn it into a
+ // Dart exception.
+ String errorMessage = JS<String>('!', r'String(#)', regexp);
+ throw FormatException("Illegal RegExp pattern: $source, $errorMessage");
+ }
+
+ RegExpMatch firstMatch(@nullCheck String string) {
+ List m = JS('JSExtendableArray|Null', r'#.exec(#)', _nativeRegExp, string);
+ if (m == null) return null;
+ return _MatchImplementation(this, JSArray<String>.of(m));
+ }
+
+ @notNull
+ bool hasMatch(@nullCheck String string) {
+ return JS<bool>('!', r'#.test(#)', _nativeRegExp, string);
+ }
+
+ String stringMatch(String string) {
+ var match = firstMatch(string);
+ if (match != null) return match.group(0);
+ return null;
+ }
+
+ Iterable<RegExpMatch> allMatches(@nullCheck String string,
+ [@nullCheck int start = 0]) {
+ if (start < 0 || start > string.length) {
+ throw RangeError.range(start, 0, string.length);
+ }
+ return _AllMatchesIterable(this, string, start);
+ }
+
+ RegExpMatch _execGlobal(String string, int start) {
+ Object regexp = _nativeGlobalVersion;
+ JS("void", "#.lastIndex = #", regexp, start);
+ List match = JS("JSExtendableArray|Null", "#.exec(#)", regexp, string);
+ if (match == null) return null;
+ return _MatchImplementation(this, JSArray<String>.of(match));
+ }
+
+ RegExpMatch _execAnchored(String string, int start) {
+ Object regexp = _nativeAnchoredVersion;
+ JS("void", "#.lastIndex = #", regexp, start);
+ List match = JS("JSExtendableArray|Null", "#.exec(#)", regexp, string);
+ if (match == null) return null;
+ // If the last capture group participated, the original regexp did not
+ // match at the start position.
+ if (match[match.length - 1] != null) return null;
+ match.length -= 1;
+ return _MatchImplementation(this, JSArray<String>.of(match));
+ }
+
+ RegExpMatch matchAsPrefix(String string, [int start = 0]) {
+ if (start < 0 || start > string.length) {
+ throw RangeError.range(start, 0, string.length);
+ }
+ return _execAnchored(string, start);
+ }
+
+ bool get isMultiLine => _isMultiLine;
+ bool get isCaseSensitive => _isCaseSensitive;
+ bool get isUnicode => _isUnicode;
+ bool get isDotAll => _isDotAll;
+}
+
+class _MatchImplementation implements RegExpMatch {
+ final Pattern pattern;
+ // Contains a JS RegExp match object.
+ // It is an Array of String values with extra "index" and "input" properties.
+ final List<String> _match;
+
+ _MatchImplementation(this.pattern, this._match) {
+ assert(JS("var", "#.input", _match) is String);
+ assert(JS("var", "#.index", _match) is int);
+ }
+
+ String get input => JS("String", "#.input", _match);
+ int get start => JS("int", "#.index", _match);
+ int get end => start + _match[0].length;
+
+ String group(int index) => _match[index];
+ String operator [](int index) => group(index);
+ int get groupCount => _match.length - 1;
+
+ List<String> groups(List<int> groups) {
+ List<String> out = [];
+ for (int i in groups) {
+ out.add(group(i));
+ }
+ return out;
+ }
+
+ String namedGroup(String name) {
+ var groups = JS('Object', '#.groups', _match);
+ if (groups != null) {
+ var result = JS('String|Null', '#[#]', groups, name);
+ if (result != null || JS<bool>('!', '# in #', name, groups)) {
+ return result;
+ }
+ }
+ throw ArgumentError.value(name, "name", "Not a capture group name");
+ }
+
+ Iterable<String> get groupNames {
+ var groups = JS('Object', '#.groups', _match);
+ if (groups != null) {
+ var keys = JSArray<String>.of(JS('', 'Object.keys(#)', groups));
+ return SubListIterable(keys, 0, null);
+ }
+ return Iterable.empty();
+ }
+}
+
+class _AllMatchesIterable extends IterableBase<RegExpMatch> {
+ final JSSyntaxRegExp _re;
+ final String _string;
+ final int _start;
+
+ _AllMatchesIterable(this._re, this._string, this._start);
+
+ Iterator<RegExpMatch> get iterator =>
+ _AllMatchesIterator(_re, _string, _start);
+}
+
+class _AllMatchesIterator implements Iterator<RegExpMatch> {
+ final JSSyntaxRegExp _regExp;
+ String _string;
+ int _nextIndex;
+ RegExpMatch _current;
+
+ _AllMatchesIterator(this._regExp, this._string, this._nextIndex);
+
+ RegExpMatch get current => _current;
+
+ static bool _isLeadSurrogate(int c) {
+ return c >= 0xd800 && c <= 0xdbff;
+ }
+
+ static bool _isTrailSurrogate(int c) {
+ return c >= 0xdc00 && c <= 0xdfff;
+ }
+
+ bool moveNext() {
+ if (_string == null) return false;
+ if (_nextIndex <= _string.length) {
+ var match = _regExp._execGlobal(_string, _nextIndex);
+ if (match != null) {
+ _current = match;
+ int nextIndex = match.end;
+ if (match.start == nextIndex) {
+ // Zero-width match. Advance by one more, unless the regexp
+ // is in unicode mode and it would put us within a surrogate
+ // pair. In that case, advance past the code point as a whole.
+ if (_regExp.isUnicode &&
+ _nextIndex + 1 < _string.length &&
+ _isLeadSurrogate(_string.codeUnitAt(_nextIndex)) &&
+ _isTrailSurrogate(_string.codeUnitAt(_nextIndex + 1))) {
+ nextIndex++;
+ }
+ nextIndex++;
+ }
+ _nextIndex = nextIndex;
+ return true;
+ }
+ }
+ _current = null;
+ _string = null; // Marks iteration as ended.
+ return false;
+ }
+}
+
+/** Find the first match of [regExp] in [string] at or after [start]. */
+RegExpMatch firstMatchAfter(JSSyntaxRegExp regExp, String string, int start) {
+ return regExp._execGlobal(string, start);
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/string_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/string_helper.dart
new file mode 100644
index 0000000..c1b5c18
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/string_helper.dart
@@ -0,0 +1,297 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._js_helper;
+
+@notNull
+int stringIndexOfStringUnchecked(receiver, other, startIndex) {
+ return JS<int>('!', '#.indexOf(#, #)', receiver, other, startIndex);
+}
+
+@notNull
+String substring1Unchecked(receiver, startIndex) {
+ return JS('!', '#.substring(#)', receiver, startIndex);
+}
+
+@notNull
+String substring2Unchecked(receiver, startIndex, endIndex) {
+ return JS('!', '#.substring(#, #)', receiver, startIndex, endIndex);
+}
+
+@notNull
+bool stringContainsStringUnchecked(receiver, other, startIndex) {
+ return stringIndexOfStringUnchecked(receiver, other, startIndex) >= 0;
+}
+
+class StringMatch implements Match {
+ const StringMatch(int this.start, String this.input, String this.pattern);
+
+ int get end => start + pattern.length;
+ String operator [](int g) => group(g);
+ int get groupCount => 0;
+
+ String group(int group_) {
+ if (group_ != 0) {
+ throw RangeError.value(group_);
+ }
+ return pattern;
+ }
+
+ List<String> groups(List<int> groups_) {
+ List<String> result = List<String>();
+ for (int g in groups_) {
+ result.add(group(g));
+ }
+ return result;
+ }
+
+ final int start;
+ final String input;
+ final String pattern;
+}
+
+Iterable<Match> allMatchesInStringUnchecked(
+ String pattern, String string, int startIndex) {
+ return _StringAllMatchesIterable(string, pattern, startIndex);
+}
+
+class _StringAllMatchesIterable extends Iterable<Match> {
+ final String _input;
+ final String _pattern;
+ final int _index;
+
+ _StringAllMatchesIterable(this._input, this._pattern, this._index);
+
+ Iterator<Match> get iterator =>
+ _StringAllMatchesIterator(_input, _pattern, _index);
+
+ Match get first {
+ int index = stringIndexOfStringUnchecked(_input, _pattern, _index);
+ if (index >= 0) {
+ return StringMatch(index, _input, _pattern);
+ }
+ throw IterableElementError.noElement();
+ }
+}
+
+class _StringAllMatchesIterator implements Iterator<Match> {
+ final String _input;
+ final String _pattern;
+ int _index;
+ Match _current;
+
+ _StringAllMatchesIterator(this._input, this._pattern, this._index);
+
+ bool moveNext() {
+ if (_index + _pattern.length > _input.length) {
+ _current = null;
+ return false;
+ }
+ var index = stringIndexOfStringUnchecked(_input, _pattern, _index);
+ if (index < 0) {
+ _index = _input.length + 1;
+ _current = null;
+ return false;
+ }
+ int end = index + _pattern.length;
+ _current = StringMatch(index, _input, _pattern);
+ // Empty match, don't start at same location again.
+ if (end == _index) end++;
+ _index = end;
+ return true;
+ }
+
+ Match get current => _current;
+}
+
+@notNull
+bool stringContainsUnchecked(
+ @notNull String receiver, @notNull other, int startIndex) {
+ if (other is String) {
+ return stringContainsStringUnchecked(receiver, other, startIndex);
+ } else if (other is JSSyntaxRegExp) {
+ return other.hasMatch(receiver.substring(startIndex));
+ } else {
+ var substr = receiver.substring(startIndex);
+ return other.allMatches(substr).isNotEmpty;
+ }
+}
+
+@notNull
+String stringReplaceJS(String receiver, replacer, String replacement) {
+ // The JavaScript String.replace method recognizes replacement
+ // patterns in the replacement string. Dart does not have that
+ // behavior.
+ replacement = JS<String>('!', r'#.replace(/\$/g, "$$$$")', replacement);
+ return JS<String>('!', r'#.replace(#, #)', receiver, replacer, replacement);
+}
+
+@notNull
+String stringReplaceFirstRE(@notNull String receiver, JSSyntaxRegExp regexp,
+ String replacement, int startIndex) {
+ var match = regexp._execGlobal(receiver, startIndex);
+ if (match == null) return receiver;
+ var start = match.start;
+ var end = match.end;
+ return stringReplaceRangeUnchecked(receiver, start, end, replacement);
+}
+
+/// Returns a string for a RegExp pattern that matches [string]. This is done by
+/// escaping all RegExp metacharacters.
+@notNull
+String quoteStringForRegExp(string) {
+ return JS<String>('!', r'#.replace(/[[\]{}()*+?.\\^$|]/g, "\\$&")', string);
+}
+
+@notNull
+String stringReplaceAllUnchecked(@notNull String receiver,
+ @nullCheck Pattern pattern, @nullCheck String replacement) {
+ if (pattern is String) {
+ if (pattern == "") {
+ if (receiver == "") {
+ return replacement;
+ } else {
+ StringBuffer result = StringBuffer();
+ int length = receiver.length;
+ result.write(replacement);
+ for (int i = 0; i < length; i++) {
+ result.write(receiver[i]);
+ result.write(replacement);
+ }
+ return result.toString();
+ }
+ } else {
+ return JS<String>(
+ '!', '#.split(#).join(#)', receiver, pattern, replacement);
+ }
+ } else if (pattern is JSSyntaxRegExp) {
+ var re = regExpGetGlobalNative(pattern);
+ return stringReplaceJS(receiver, re, replacement);
+ } else {
+ // TODO(floitsch): implement generic String.replace (with patterns).
+ throw "String.replaceAll(Pattern) UNIMPLEMENTED";
+ }
+}
+
+String _matchString(Match match) => match[0];
+String _stringIdentity(String string) => string;
+
+@notNull
+String stringReplaceAllFuncUnchecked(
+ String receiver,
+ @nullCheck Pattern pattern,
+ String onMatch(Match match),
+ String onNonMatch(String nonMatch)) {
+ if (onMatch == null) onMatch = _matchString;
+ if (onNonMatch == null) onNonMatch = _stringIdentity;
+ if (pattern is String) {
+ return stringReplaceAllStringFuncUnchecked(
+ receiver, pattern, onMatch, onNonMatch);
+ }
+ StringBuffer buffer = StringBuffer();
+ int startIndex = 0;
+ for (Match match in pattern.allMatches(receiver)) {
+ buffer.write(onNonMatch(receiver.substring(startIndex, match.start)));
+ buffer.write(onMatch(match));
+ startIndex = match.end;
+ }
+ buffer.write(onNonMatch(receiver.substring(startIndex)));
+ return buffer.toString();
+}
+
+@notNull
+String stringReplaceAllEmptyFuncUnchecked(String receiver,
+ String onMatch(Match match), String onNonMatch(String nonMatch)) {
+ // Pattern is the empty string.
+ StringBuffer buffer = StringBuffer();
+ int length = receiver.length;
+ int i = 0;
+ buffer.write(onNonMatch(""));
+ while (i < length) {
+ buffer.write(onMatch(StringMatch(i, receiver, "")));
+ // Special case to avoid splitting a surrogate pair.
+ int code = receiver.codeUnitAt(i);
+ if ((code & ~0x3FF) == 0xD800 && length > i + 1) {
+ // Leading surrogate;
+ code = receiver.codeUnitAt(i + 1);
+ if ((code & ~0x3FF) == 0xDC00) {
+ // Matching trailing surrogate.
+ buffer.write(onNonMatch(receiver.substring(i, i + 2)));
+ i += 2;
+ continue;
+ }
+ }
+ buffer.write(onNonMatch(receiver[i]));
+ i++;
+ }
+ buffer.write(onMatch(StringMatch(i, receiver, "")));
+ buffer.write(onNonMatch(""));
+ return buffer.toString();
+}
+
+@notNull
+String stringReplaceAllStringFuncUnchecked(String receiver, String pattern,
+ String onMatch(Match match), String onNonMatch(String nonMatch)) {
+ int patternLength = pattern.length;
+ if (patternLength == 0) {
+ return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch);
+ }
+ int length = receiver.length;
+ StringBuffer buffer = StringBuffer();
+ int startIndex = 0;
+ while (startIndex < length) {
+ int position = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
+ if (position == -1) {
+ break;
+ }
+ buffer.write(onNonMatch(receiver.substring(startIndex, position)));
+ buffer.write(onMatch(StringMatch(position, receiver, pattern)));
+ startIndex = position + patternLength;
+ }
+ buffer.write(onNonMatch(receiver.substring(startIndex)));
+ return buffer.toString();
+}
+
+@notNull
+String stringReplaceFirstUnchecked(@notNull String receiver,
+ @nullCheck Pattern pattern, String replacement, int startIndex) {
+ if (pattern is String) {
+ int index = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
+ if (index < 0) return receiver;
+ int end = index + pattern.length;
+ return stringReplaceRangeUnchecked(receiver, index, end, replacement);
+ }
+ if (pattern is JSSyntaxRegExp) {
+ return startIndex == 0
+ ? stringReplaceJS(receiver, regExpGetNative(pattern), replacement)
+ : stringReplaceFirstRE(receiver, pattern, replacement, startIndex);
+ }
+ Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
+ if (!matches.moveNext()) return receiver;
+ Match match = matches.current;
+ return receiver.replaceRange(match.start, match.end, replacement);
+}
+
+@notNull
+String stringReplaceFirstMappedUnchecked(String receiver, Pattern pattern,
+ String replace(Match current), int startIndex) {
+ Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
+ if (!matches.moveNext()) return receiver;
+ Match match = matches.current;
+ String replacement = "${replace(match)}";
+ return receiver.replaceRange(match.start, match.end, replacement);
+}
+
+@notNull
+String stringJoinUnchecked(array, separator) {
+ return JS<String>('!', r'#.join(#)', array, separator);
+}
+
+@notNull
+String stringReplaceRangeUnchecked(
+ String receiver, int start, int end, String replacement) {
+ String prefix = JS('!', '#.substring(0, #)', receiver, start);
+ String suffix = JS('!', '#.substring(#)', receiver, end);
+ return "$prefix$replacement$suffix";
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/.packages b/sdk_nnbd/lib/_internal/js_runtime/.packages
new file mode 100644
index 0000000..adf8b36
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/.packages
@@ -0,0 +1,2 @@
+# Generated by pub on 2015-12-07 17:08:11.724.
+js_runtime:lib/
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/annotations.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/annotations.dart
new file mode 100644
index 0000000..f53c5f3
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/annotations.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _js_helper;
+
+/// Marks a class as native and defines its JavaScript name(s).
+class Native {
+ final String name;
+ const Native(this.name);
+}
+
+class _Patch {
+ const _Patch();
+}
+
+/// Annotation that marks the declaration as a patch.
+const _Patch patch = const _Patch();
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/async_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/async_patch.dart
new file mode 100644
index 0000000..68bcbeb
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/async_patch.dart
@@ -0,0 +1,694 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for the dart:async library.
+
+import 'dart:_js_helper'
+ show
+ patch,
+ ExceptionAndStackTrace,
+ convertDartClosureToJS,
+ getTraceFromException,
+ requiresPreamble,
+ wrapException,
+ unwrapException;
+
+import 'dart:_foreign_helper' show JS, JS_GET_FLAG;
+
+import 'dart:_async_await_error_codes' as async_error_codes;
+
+import "dart:collection" show IterableBase;
+
+@patch
+class _AsyncRun {
+ @patch
+ static void _scheduleImmediate(void callback()) {
+ _scheduleImmediateClosure(callback);
+ }
+
+ // Lazily initialized.
+ static final Function _scheduleImmediateClosure =
+ _initializeScheduleImmediate();
+
+ static Function _initializeScheduleImmediate() {
+ requiresPreamble();
+ if (JS('', 'self.scheduleImmediate') != null) {
+ return _scheduleImmediateJsOverride;
+ }
+ if (JS('', 'self.MutationObserver') != null &&
+ JS('', 'self.document') != null) {
+ // Use mutationObservers.
+ var div = JS('', 'self.document.createElement("div")');
+ var span = JS('', 'self.document.createElement("span")');
+ var storedCallback;
+
+ internalCallback(_) {
+ var f = storedCallback;
+ storedCallback = null;
+ f();
+ }
+
+ var observer = JS('', 'new self.MutationObserver(#)',
+ convertDartClosureToJS(internalCallback, 1));
+ JS('', '#.observe(#, { childList: true })', observer, div);
+
+ return (void callback()) {
+ assert(storedCallback == null);
+ storedCallback = callback;
+ // Because of a broken shadow-dom polyfill we have to change the
+ // children instead a cheap property.
+ JS('', '#.firstChild ? #.removeChild(#): #.appendChild(#)', div, div,
+ span, div, span);
+ };
+ } else if (JS('', 'self.setImmediate') != null) {
+ return _scheduleImmediateWithSetImmediate;
+ }
+ // TODO(20055): We should use DOM promises when available.
+ return _scheduleImmediateWithTimer;
+ }
+
+ static void _scheduleImmediateJsOverride(void callback()) {
+ internalCallback() {
+ callback();
+ }
+
+ JS('void', 'self.scheduleImmediate(#)',
+ convertDartClosureToJS(internalCallback, 0));
+ }
+
+ static void _scheduleImmediateWithSetImmediate(void callback()) {
+ internalCallback() {
+ callback();
+ }
+
+ JS('void', 'self.setImmediate(#)',
+ convertDartClosureToJS(internalCallback, 0));
+ }
+
+ static void _scheduleImmediateWithTimer(void callback()) {
+ Timer._createTimer(Duration.zero, callback);
+ }
+}
+
+@patch
+class DeferredLibrary {
+ @patch
+ Future<Null> load() {
+ throw 'DeferredLibrary not supported. '
+ 'please use the `import "lib.dart" deferred as lib` syntax.';
+ }
+}
+
+@patch
+class Timer {
+ @patch
+ static Timer _createTimer(Duration duration, void callback()) {
+ int milliseconds = duration.inMilliseconds;
+ if (milliseconds < 0) milliseconds = 0;
+ return new _TimerImpl(milliseconds, callback);
+ }
+
+ @patch
+ static Timer _createPeriodicTimer(
+ Duration duration, void callback(Timer timer)) {
+ int milliseconds = duration.inMilliseconds;
+ if (milliseconds < 0) milliseconds = 0;
+ return new _TimerImpl.periodic(milliseconds, callback);
+ }
+}
+
+class _TimerImpl implements Timer {
+ final bool _once;
+ int _handle;
+ int _tick = 0;
+
+ _TimerImpl(int milliseconds, void callback()) : _once = true {
+ if (_hasTimer()) {
+ void internalCallback() {
+ _handle = null;
+ this._tick = 1;
+ callback();
+ }
+
+ _handle = JS('int', 'self.setTimeout(#, #)',
+ convertDartClosureToJS(internalCallback, 0), milliseconds);
+ } else {
+ throw new UnsupportedError('`setTimeout()` not found.');
+ }
+ }
+
+ _TimerImpl.periodic(int milliseconds, void callback(Timer timer))
+ : _once = false {
+ if (_hasTimer()) {
+ int start = JS('int', 'Date.now()');
+ _handle = JS(
+ 'int',
+ 'self.setInterval(#, #)',
+ convertDartClosureToJS(() {
+ int tick = this._tick + 1;
+ if (milliseconds > 0) {
+ int duration = JS('int', 'Date.now()') - start;
+ if (duration > (tick + 1) * milliseconds) {
+ tick = duration ~/ milliseconds;
+ }
+ }
+ this._tick = tick;
+ callback(this);
+ }, 0),
+ milliseconds);
+ } else {
+ throw new UnsupportedError('Periodic timer.');
+ }
+ }
+
+ @override
+ bool get isActive => _handle != null;
+
+ @override
+ int get tick => _tick;
+
+ @override
+ void cancel() {
+ if (_hasTimer()) {
+ if (_handle == null) return;
+ if (_once) {
+ JS('void', 'self.clearTimeout(#)', _handle);
+ } else {
+ JS('void', 'self.clearInterval(#)', _handle);
+ }
+ _handle = null;
+ } else {
+ throw new UnsupportedError('Canceling a timer.');
+ }
+ }
+}
+
+bool _hasTimer() {
+ requiresPreamble();
+ return JS('', 'self.setTimeout') != null;
+}
+
+class _AsyncAwaitCompleter<T> implements Completer<T> {
+ final _future = new _Future<T>();
+ bool isSync;
+
+ _AsyncAwaitCompleter() : isSync = false;
+
+ void complete([FutureOr<T> value]) {
+ if (!isSync || value is Future<T>) {
+ _future._asyncComplete(value);
+ } else {
+ _future._completeWithValue(value);
+ }
+ }
+
+ void completeError(e, [st]) {
+ if (isSync) {
+ _future._completeError(e, st);
+ } else {
+ _future._asyncCompleteError(e, st);
+ }
+ }
+
+ Future<T> get future => _future;
+ bool get isCompleted => !_future._mayComplete;
+}
+
+/// Creates a Completer for an `async` function.
+///
+/// Used as part of the runtime support for the async/await transformation.
+Completer<T> _makeAsyncAwaitCompleter<T>() {
+ return new _AsyncAwaitCompleter<T>();
+}
+
+/// Initiates the computation of an `async` function and starts the body
+/// synchronously.
+///
+/// Used as part of the runtime support for the async/await transformation.
+///
+/// This function sets up the first call into the transformed [bodyFunction].
+/// Independently, it takes the [completer] and returns the future of the
+/// completer for convenience of the transformed code.
+dynamic _asyncStartSync(
+ _WrappedAsyncBody bodyFunction, _AsyncAwaitCompleter completer) {
+ bodyFunction(async_error_codes.SUCCESS, null);
+ completer.isSync = true;
+ return completer.future;
+}
+
+/// Performs the `await` operation of an `async` function.
+///
+/// Used as part of the runtime support for the async/await transformation.
+///
+/// Arranges for [bodyFunction] to be called when the future or value [object]
+/// is completed with a code [async_error_codes.SUCCESS] or
+/// [async_error_codes.ERROR] depending on the success of the future.
+dynamic _asyncAwait(dynamic object, _WrappedAsyncBody bodyFunction) {
+ _awaitOnObject(object, bodyFunction);
+}
+
+/// Completes the future of an `async` function.
+///
+/// Used as part of the runtime support for the async/await transformation.
+///
+/// This function is used when the `async` function returns (explicitly or
+/// implicitly).
+dynamic _asyncReturn(dynamic object, Completer completer) {
+ completer.complete(object);
+}
+
+/// Completes the future of an `async` function with an error.
+///
+/// Used as part of the runtime support for the async/await transformation.
+///
+/// This function is used when the `async` function re-throws an exception.
+dynamic _asyncRethrow(dynamic object, Completer completer) {
+ // The error is a js-error.
+ completer.completeError(
+ unwrapException(object), getTraceFromException(object));
+}
+
+/// Awaits on the given [object].
+///
+/// If the [object] is a Future, registers on it, otherwise wraps it into a
+/// future first.
+///
+/// The [bodyFunction] argument is the continuation that should be invoked
+/// when the future completes.
+void _awaitOnObject(object, _WrappedAsyncBody bodyFunction) {
+ Function thenCallback =
+ (result) => bodyFunction(async_error_codes.SUCCESS, result);
+
+ Function errorCallback = (dynamic error, StackTrace stackTrace) {
+ ExceptionAndStackTrace wrappedException =
+ new ExceptionAndStackTrace(error, stackTrace);
+ bodyFunction(async_error_codes.ERROR, wrappedException);
+ };
+
+ if (object is _Future) {
+ // We can skip the zone registration, since the bodyFunction is already
+ // registered (see [_wrapJsFunctionForAsync]).
+ object._thenAwait(thenCallback, errorCallback);
+ } else if (object is Future) {
+ object.then(thenCallback, onError: errorCallback);
+ } else {
+ _Future future = new _Future().._setValue(object);
+ // We can skip the zone registration, since the bodyFunction is already
+ // registered (see [_wrapJsFunctionForAsync]).
+ future._thenAwait(thenCallback, null);
+ }
+}
+
+typedef void _WrappedAsyncBody(int errorCode, dynamic result);
+
+_WrappedAsyncBody _wrapJsFunctionForAsync(dynamic /* js function */ function) {
+ var protected = JS(
+ '',
+ """
+ (function (fn, ERROR) {
+ // Invokes [function] with [errorCode] and [result].
+ //
+ // If (and as long as) the invocation throws, calls [function] again,
+ // with an error-code.
+ return function(errorCode, result) {
+ while (true) {
+ try {
+ fn(errorCode, result);
+ break;
+ } catch (error) {
+ result = error;
+ errorCode = ERROR;
+ }
+ }
+ }
+ })(#, #)""",
+ function,
+ async_error_codes.ERROR);
+
+ return Zone.current.registerBinaryCallback((int errorCode, dynamic result) {
+ JS('', '#(#, #)', protected, errorCode, result);
+ });
+}
+
+/// Implements the runtime support for async* functions.
+///
+/// Called by the transformed function for each original return, await, yield,
+/// yield* and before starting the function.
+///
+/// When the async* function wants to return it calls this function with
+/// [asyncBody] == [async_error_codes.SUCCESS], the asyncStarHelper takes this
+/// as signal to close the stream.
+///
+/// When the async* function wants to signal that an uncaught error was thrown,
+/// it calls this function with [asyncBody] == [async_error_codes.ERROR],
+/// the streamHelper takes this as signal to addError [object] to the
+/// [controller] and close it.
+///
+/// If the async* function wants to do a yield or yield*, it calls this function
+/// with [object] being an [IterationMarker].
+///
+/// In the case of a yield or yield*, if the stream subscription has been
+/// canceled, schedules [asyncBody] to be called with
+/// [async_error_codes.STREAM_WAS_CANCELED].
+///
+/// If [object] is a single-yield [IterationMarker], adds the value of the
+/// [IterationMarker] to the stream. If the stream subscription has been
+/// paused, return early. Otherwise schedule the helper function to be
+/// executed again.
+///
+/// If [object] is a yield-star [IterationMarker], starts listening to the
+/// yielded stream, and adds all events and errors to our own controller (taking
+/// care if the subscription has been paused or canceled) - when the sub-stream
+/// is done, schedules [asyncBody] again.
+///
+/// If the async* function wants to do an await it calls this function with
+/// [object] not an [IterationMarker].
+///
+/// If [object] is not a [Future], it is wrapped in a `Future.value`.
+/// The [asyncBody] is called on completion of the future (see [asyncHelper].
+void _asyncStarHelper(
+ dynamic object,
+ dynamic /* int | _WrappedAsyncBody */ bodyFunctionOrErrorCode,
+ _AsyncStarStreamController controller) {
+ if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
+ // This happens on return from the async* function.
+ if (controller.isCanceled) {
+ controller.cancelationFuture._completeWithValue(null);
+ } else {
+ controller.close();
+ }
+ return;
+ } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
+ // The error is a js-error.
+ if (controller.isCanceled) {
+ controller.cancelationFuture._completeError(
+ unwrapException(object), getTraceFromException(object));
+ } else {
+ controller.addError(
+ unwrapException(object), getTraceFromException(object));
+ controller.close();
+ }
+ return;
+ }
+
+ if (object is _IterationMarker) {
+ if (controller.isCanceled) {
+ bodyFunctionOrErrorCode(async_error_codes.STREAM_WAS_CANCELED, null);
+ return;
+ }
+ if (object.state == _IterationMarker.YIELD_SINGLE) {
+ controller.add(object.value);
+
+ scheduleMicrotask(() {
+ if (controller.isPaused) {
+ // We only suspend the thread inside the microtask in order to allow
+ // listeners on the output stream to pause in response to the just
+ // output value, and have the stream immediately stop producing.
+ controller.isSuspended = true;
+ return;
+ }
+ bodyFunctionOrErrorCode(null, async_error_codes.SUCCESS);
+ });
+ return;
+ } else if (object.state == _IterationMarker.YIELD_STAR) {
+ Stream stream = object.value;
+ // Errors of [stream] are passed though to the main stream. (see
+ // [AsyncStreamController.addStream]).
+ // TODO(sigurdm): The spec is not very clear here. Clarify with Gilad.
+ controller.addStream(stream).then((_) {
+ // No check for isPaused here because the spec 17.16.2 only
+ // demands checks *before* each element in [stream] not after the last
+ // one. On the other hand we check for isCanceled, as that check happens
+ // after insertion of each element.
+ int errorCode = controller.isCanceled
+ ? async_error_codes.STREAM_WAS_CANCELED
+ : async_error_codes.SUCCESS;
+ bodyFunctionOrErrorCode(errorCode, null);
+ });
+ return;
+ }
+ }
+
+ _awaitOnObject(object, bodyFunctionOrErrorCode);
+}
+
+Stream _streamOfController(_AsyncStarStreamController controller) {
+ return controller.stream;
+}
+
+/// A wrapper around a [StreamController] that keeps track of the state of
+/// the execution of an async* function.
+/// It can be in 1 of 3 states:
+///
+/// - running/scheduled
+/// - suspended
+/// - canceled
+///
+/// If yielding while the subscription is paused it will become suspended. And
+/// only resume after the subscription is resumed or canceled.
+class _AsyncStarStreamController<T> {
+ StreamController<T> controller;
+ Stream get stream => controller.stream;
+
+ /// True when the async* function has yielded while being paused.
+ /// When true execution will only resume after a `onResume` or `onCancel`
+ /// event.
+ bool isSuspended = false;
+
+ bool get isPaused => controller.isPaused;
+
+ _Future cancelationFuture = null;
+
+ /// True after the StreamSubscription has been cancelled.
+ /// When this is true, errors thrown from the async* body should go to the
+ /// [cancelationFuture] instead of adding them to [controller], and
+ /// returning from the async function should complete [cancelationFuture].
+ bool get isCanceled => cancelationFuture != null;
+
+ add(event) => controller.add(event);
+
+ addStream(Stream<T> stream) {
+ return controller.addStream(stream, cancelOnError: false);
+ }
+
+ addError(error, stackTrace) => controller.addError(error, stackTrace);
+
+ close() => controller.close();
+
+ _AsyncStarStreamController(_WrappedAsyncBody body) {
+ _resumeBody() {
+ scheduleMicrotask(() {
+ body(async_error_codes.SUCCESS, null);
+ });
+ }
+
+ controller = new StreamController<T>(onListen: () {
+ _resumeBody();
+ }, onResume: () {
+ // Only schedule again if the async* function actually is suspended.
+ // Resume directly instead of scheduling, so that the sequence
+ // `pause-resume-pause` will result in one extra event produced.
+ if (isSuspended) {
+ isSuspended = false;
+ _resumeBody();
+ }
+ }, onCancel: () {
+ // If the async* is finished we ignore cancel events.
+ if (!controller.isClosed) {
+ cancelationFuture = new _Future();
+ if (isSuspended) {
+ // Resume the suspended async* function to run finalizers.
+ isSuspended = false;
+ scheduleMicrotask(() {
+ body(async_error_codes.STREAM_WAS_CANCELED, null);
+ });
+ }
+ return cancelationFuture;
+ }
+ });
+ }
+}
+
+/// Creates a stream controller for an `async*` function.
+///
+/// Used as part of the runtime support for the async/await transformation.
+_makeAsyncStarStreamController<T>(_WrappedAsyncBody body) {
+ return new _AsyncStarStreamController<T>(body);
+}
+
+class _IterationMarker {
+ static const YIELD_SINGLE = 0;
+ static const YIELD_STAR = 1;
+ static const ITERATION_ENDED = 2;
+ static const UNCAUGHT_ERROR = 3;
+
+ final value;
+ final int state;
+
+ const _IterationMarker._(this.state, this.value);
+
+ static yieldStar(dynamic /* Iterable or Stream */ values) {
+ return new _IterationMarker._(YIELD_STAR, values);
+ }
+
+ static endOfIteration() {
+ return const _IterationMarker._(ITERATION_ENDED, null);
+ }
+
+ static yieldSingle(dynamic value) {
+ return new _IterationMarker._(YIELD_SINGLE, value);
+ }
+
+ static uncaughtError(dynamic error) {
+ return new _IterationMarker._(UNCAUGHT_ERROR, error);
+ }
+
+ toString() => "IterationMarker($state, $value)";
+}
+
+class _SyncStarIterator<T> implements Iterator<T> {
+ // _SyncStarIterator handles stepping a sync* generator body state machine.
+ //
+ // It also handles the stepping over 'nested' iterators to flatten yield*
+ // statements. For non-sync* iterators, [_nestedIterator] contains the
+ // iterator. We delegate to [_nestedIterator] when it is not `null`.
+ //
+ // For nested sync* iterators, [this] iterator acts on behalf of the innermost
+ // nested sync* iterator. The current state machine is suspended on a stack
+ // until the inner state machine ends.
+
+ // The state machine for the innermost _SyncStarIterator.
+ dynamic _body;
+
+ // The current value, unless iterating a non-sync* nested iterator.
+ T _current = null;
+
+ // This is the nested iterator when iterating a yield* of a non-sync iterator.
+ // TODO(32956): In strong-mode, yield* takes an Iterable<T> (possibly checked
+ // with an implicit downcast), so change type to Iterator<T>.
+ Iterator _nestedIterator = null;
+
+ // Stack of suspended state machines when iterating a yield* of a sync*
+ // iterator.
+ List _suspendedBodies = null;
+
+ _SyncStarIterator(this._body);
+
+ T get current {
+ if (_nestedIterator == null) return _current;
+ return _nestedIterator.current;
+ }
+
+ _runBody() {
+ // TODO(sra): Find a way to hard-wire SUCCESS and ERROR codes.
+ return JS(
+ '',
+ '''
+ // Invokes [body] with [errorCode] and [result].
+ //
+ // If (and as long as) the invocation throws, calls [function] again,
+ // with an error-code.
+ (function(body, SUCCESS, ERROR) {
+ var errorValue, errorCode = SUCCESS;
+ while (true) {
+ try {
+ return body(errorCode, errorValue);
+ } catch (error) {
+ errorValue = error;
+ errorCode = ERROR;
+ }
+ }
+ })(#, #, #)''',
+ _body,
+ async_error_codes.SUCCESS,
+ async_error_codes.ERROR);
+ }
+
+ bool moveNext() {
+ while (true) {
+ if (_nestedIterator != null) {
+ if (_nestedIterator.moveNext()) {
+ return true;
+ } else {
+ _nestedIterator = null;
+ }
+ }
+ var value = _runBody();
+ if (value is _IterationMarker) {
+ int state = value.state;
+ if (state == _IterationMarker.ITERATION_ENDED) {
+ if (_suspendedBodies == null || _suspendedBodies.isEmpty) {
+ _current = null;
+ // Rely on [_body] to repeatedly return `ITERATION_ENDED`.
+ return false;
+ }
+ // Resume the innermost suspended iterator.
+ _body = _suspendedBodies.removeLast();
+ continue;
+ } else if (state == _IterationMarker.UNCAUGHT_ERROR) {
+ // Rely on [_body] to repeatedly return `UNCAUGHT_ERROR`.
+ // This is a wrapped exception, so we use JavaScript throw to throw
+ // it.
+ JS('', 'throw #', value.value);
+ } else {
+ assert(state == _IterationMarker.YIELD_STAR);
+ Iterator inner = value.value.iterator;
+ if (inner is _SyncStarIterator) {
+ // Suspend the current state machine and start acting on behalf of
+ // the nested state machine.
+ //
+ // TODO(sra): Recognize "tail yield*" statements and avoid
+ // suspending the current body when all it will do is step without
+ // effect to ITERATION_ENDED.
+ (_suspendedBodies ??= []).add(_body);
+ _body = inner._body;
+ continue;
+ } else {
+ _nestedIterator = inner;
+ // TODO(32956): Change to the following when strong-mode is the only
+ // option:
+ //
+ // _nestedIterator = JS<Iterator<T>>('','#', inner);
+ continue;
+ }
+ }
+ } else {
+ // TODO(32956): Remove this test.
+ _current = JS<T>('', '#', value);
+ return true;
+ }
+ }
+ return false; // TODO(sra): Fix type inference so that this is not needed.
+ }
+}
+
+/// Creates an Iterable for a `sync*` function.
+///
+/// Used as part of the runtime support for the async/await transformation.
+_SyncStarIterable<T> _makeSyncStarIterable<T>(body) {
+ return new _SyncStarIterable<T>(body);
+}
+
+/// An Iterable corresponding to a sync* method.
+///
+/// Each invocation of a sync* method will return a new instance of this class.
+class _SyncStarIterable<T> extends IterableBase<T> {
+ // This is a function that will return a helper function that does the
+ // iteration of the sync*.
+ //
+ // Each invocation should give a body with fresh state.
+ final dynamic /* js function */ _outerHelper;
+
+ _SyncStarIterable(this._outerHelper);
+
+ Iterator<T> get iterator =>
+ new _SyncStarIterator<T>(JS('', '#()', _outerHelper));
+}
+
+@patch
+void _rethrow(Object error, StackTrace stackTrace) {
+ error = wrapException(error);
+ JS('void', '#.stack = #', error, stackTrace.toString());
+ JS('void', 'throw #', error);
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/cli_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/cli_patch.dart
new file mode 100644
index 0000000..6921e60
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/cli_patch.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:_js_helper' show patch;
+
+@patch
+void _waitForEvent(int timeoutMillis) {
+ throw new UnsupportedError("waitForEvent");
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/collection_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/collection_patch.dart
new file mode 100644
index 0000000..300d490
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/collection_patch.dart
@@ -0,0 +1,1727 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:collection classes.
+import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper'
+ show
+ fillLiteralMap,
+ fillLiteralSet,
+ InternalMap,
+ NoInline,
+ NoSideEffects,
+ NoThrows,
+ patch,
+ JsLinkedHashMap,
+ LinkedHashMapCell,
+ LinkedHashMapKeyIterable,
+ LinkedHashMapKeyIterator;
+
+import 'dart:_internal' hide Symbol;
+
+const _USE_ES6_MAPS = const bool.fromEnvironment("dart2js.use.es6.maps");
+
+const int _mask30 = 0x3fffffff; // Low 30 bits.
+
+@patch
+class HashMap<K, V> {
+ @patch
+ factory HashMap(
+ {bool equals(K key1, K key2),
+ int hashCode(K key),
+ bool isValidKey(potentialKey)}) {
+ if (isValidKey == null) {
+ if (hashCode == null) {
+ if (equals == null) {
+ return new _HashMap<K, V>();
+ }
+ hashCode = _defaultHashCode;
+ } else {
+ if (identical(identityHashCode, hashCode) &&
+ identical(identical, equals)) {
+ return new _IdentityHashMap<K, V>();
+ }
+ if (equals == null) {
+ equals = _defaultEquals;
+ }
+ }
+ } else {
+ if (hashCode == null) {
+ hashCode = _defaultHashCode;
+ }
+ if (equals == null) {
+ equals = _defaultEquals;
+ }
+ }
+ return new _CustomHashMap<K, V>(equals, hashCode, isValidKey);
+ }
+
+ @patch
+ factory HashMap.identity() = _IdentityHashMap<K, V>;
+}
+
+class _HashMap<K, V> extends MapBase<K, V> implements HashMap<K, V> {
+ int _length = 0;
+
+ // The hash map contents are divided into three parts: one part for
+ // string keys, one for numeric keys, and one for the rest. String
+ // and numeric keys map directly to their values, but the rest of
+ // the entries are stored in bucket lists of the form:
+ //
+ // [key-0, value-0, key-1, value-1, ...]
+ //
+ // where all keys in the same bucket share the same hash code.
+ var _strings;
+ var _nums;
+ var _rest;
+
+ // When iterating over the hash map, it is very convenient to have a
+ // list of all the keys. We cache that on the instance and clear the
+ // the cache whenever the key set changes. This is also used to
+ // guard against concurrent modifications.
+ List _keys;
+
+ _HashMap();
+
+ int get length => _length;
+ bool get isEmpty => _length == 0;
+ bool get isNotEmpty => !isEmpty;
+
+ Iterable<K> get keys {
+ return new _HashMapKeyIterable<K>(this);
+ }
+
+ Iterable<V> get values {
+ return new MappedIterable<K, V>(keys, (each) => this[each]);
+ }
+
+ bool containsKey(Object key) {
+ if (_isStringKey(key)) {
+ var strings = _strings;
+ return (strings == null) ? false : _hasTableEntry(strings, key);
+ } else if (_isNumericKey(key)) {
+ var nums = _nums;
+ return (nums == null) ? false : _hasTableEntry(nums, key);
+ } else {
+ return _containsKey(key);
+ }
+ }
+
+ bool _containsKey(Object key) {
+ var rest = _rest;
+ if (rest == null) return false;
+ var bucket = _getBucket(rest, key);
+ return _findBucketIndex(bucket, key) >= 0;
+ }
+
+ bool containsValue(Object value) {
+ return _computeKeys().any((each) => this[each] == value);
+ }
+
+ void addAll(Map<K, V> other) {
+ other.forEach((K key, V value) {
+ this[key] = value;
+ });
+ }
+
+ V operator [](Object key) {
+ if (_isStringKey(key)) {
+ var strings = _strings;
+ return JS('', '#', strings == null ? null : _getTableEntry(strings, key));
+ } else if (_isNumericKey(key)) {
+ var nums = _nums;
+ return JS('', '#', nums == null ? null : _getTableEntry(nums, key));
+ } else {
+ return _get(key);
+ }
+ }
+
+ V _get(Object key) {
+ var rest = _rest;
+ if (rest == null) return null;
+ var bucket = _getBucket(rest, key);
+ int index = _findBucketIndex(bucket, key);
+ return (index < 0) ? null : JS('', '#[#]', bucket, index + 1);
+ }
+
+ void operator []=(K key, V value) {
+ if (_isStringKey(key)) {
+ var strings = _strings;
+ if (strings == null) _strings = strings = _newHashTable();
+ _addHashTableEntry(strings, key, value);
+ } else if (_isNumericKey(key)) {
+ var nums = _nums;
+ if (nums == null) _nums = nums = _newHashTable();
+ _addHashTableEntry(nums, key, value);
+ } else {
+ _set(key, value);
+ }
+ }
+
+ void _set(K key, V value) {
+ var rest = _rest;
+ if (rest == null) _rest = rest = _newHashTable();
+ var hash = _computeHashCode(key);
+ var bucket = JS('var', '#[#]', rest, hash);
+ if (bucket == null) {
+ _setTableEntry(rest, hash, JS('var', '[#, #]', key, value));
+ _length++;
+ _keys = null;
+ } else {
+ int index = _findBucketIndex(bucket, key);
+ if (index >= 0) {
+ JS('void', '#[#] = #', bucket, index + 1, value);
+ } else {
+ JS('void', '#.push(#, #)', bucket, key, value);
+ _length++;
+ _keys = null;
+ }
+ }
+ }
+
+ V putIfAbsent(K key, V ifAbsent()) {
+ if (containsKey(key)) return this[key];
+ V value = ifAbsent();
+ this[key] = value;
+ return value;
+ }
+
+ V remove(Object key) {
+ if (_isStringKey(key)) {
+ return _removeHashTableEntry(_strings, key);
+ } else if (_isNumericKey(key)) {
+ return _removeHashTableEntry(_nums, key);
+ } else {
+ return _remove(key);
+ }
+ }
+
+ V _remove(Object key) {
+ var rest = _rest;
+ if (rest == null) return null;
+ var bucket = _getBucket(rest, key);
+ int index = _findBucketIndex(bucket, key);
+ if (index < 0) return null;
+ // TODO(kasperl): Consider getting rid of the bucket list when
+ // the length reaches zero.
+ _length--;
+ _keys = null;
+ // Use splice to remove the two [key, value] elements at the
+ // index and return the value.
+ return JS('var', '#.splice(#, 2)[1]', bucket, index);
+ }
+
+ void clear() {
+ if (_length > 0) {
+ _strings = _nums = _rest = _keys = null;
+ _length = 0;
+ }
+ }
+
+ void forEach(void action(K key, V value)) {
+ List keys = _computeKeys();
+ for (int i = 0, length = keys.length; i < length; i++) {
+ var key = JS('var', '#[#]', keys, i);
+ action(key, this[key]);
+ if (JS('bool', '# !== #', keys, _keys)) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ }
+
+ List _computeKeys() {
+ if (_keys != null) return _keys;
+ List result = new List(_length);
+ int index = 0;
+
+ // Add all string keys to the list.
+ var strings = _strings;
+ if (strings != null) {
+ var names = JS('var', 'Object.getOwnPropertyNames(#)', strings);
+ int entries = JS('int', '#.length', names);
+ for (int i = 0; i < entries; i++) {
+ String key = JS('String', '#[#]', names, i);
+ JS('void', '#[#] = #', result, index, key);
+ index++;
+ }
+ }
+
+ // Add all numeric keys to the list.
+ var nums = _nums;
+ if (nums != null) {
+ var names = JS('var', 'Object.getOwnPropertyNames(#)', nums);
+ int entries = JS('int', '#.length', names);
+ for (int i = 0; i < entries; i++) {
+ // Object.getOwnPropertyNames returns a list of strings, so we
+ // have to convert the keys back to numbers (+).
+ num key = JS('num', '+#[#]', names, i);
+ JS('void', '#[#] = #', result, index, key);
+ index++;
+ }
+ }
+
+ // Add all the remaining keys to the list.
+ var rest = _rest;
+ if (rest != null) {
+ var names = JS('var', 'Object.getOwnPropertyNames(#)', rest);
+ int entries = JS('int', '#.length', names);
+ for (int i = 0; i < entries; i++) {
+ var key = JS('String', '#[#]', names, i);
+ var bucket = JS('var', '#[#]', rest, key);
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i += 2) {
+ var key = JS('var', '#[#]', bucket, i);
+ JS('void', '#[#] = #', result, index, key);
+ index++;
+ }
+ }
+ }
+ assert(index == _length);
+ return _keys = result;
+ }
+
+ void _addHashTableEntry(var table, K key, V value) {
+ if (!_hasTableEntry(table, key)) {
+ _length++;
+ _keys = null;
+ }
+ _setTableEntry(table, key, value);
+ }
+
+ V _removeHashTableEntry(var table, Object key) {
+ if (table != null && _hasTableEntry(table, key)) {
+ V value = _getTableEntry(table, key);
+ _deleteTableEntry(table, key);
+ _length--;
+ _keys = null;
+ return value;
+ } else {
+ return null;
+ }
+ }
+
+ static bool _isStringKey(var key) {
+ return key is String && key != '__proto__';
+ }
+
+ static bool _isNumericKey(var key) {
+ // Only treat unsigned 30-bit integers as numeric keys. This way,
+ // we avoid converting them to strings when we use them as keys in
+ // the JavaScript hash table object.
+ return key is num && JS('bool', '(# & #) === #', key, _mask30, key);
+ }
+
+ int _computeHashCode(var key) {
+ // We force the hash codes to be unsigned 30-bit integers to avoid
+ // issues with problematic keys like '__proto__'. Another option
+ // would be to throw an exception if the hash code isn't a number.
+ return JS('int', '# & #', key.hashCode, _mask30);
+ }
+
+ static bool _hasTableEntry(var table, var key) {
+ var entry = JS('var', '#[#]', table, key);
+ // We take care to only store non-null entries in the table, so we
+ // can check if the table has an entry for the given key with a
+ // simple null check.
+ return entry != null;
+ }
+
+ static _getTableEntry(var table, var key) {
+ var entry = JS('var', '#[#]', table, key);
+ // We store the table itself as the entry to signal that it really
+ // is a null value, so we have to map back to null here.
+ return JS('bool', '# === #', entry, table) ? null : entry;
+ }
+
+ static void _setTableEntry(var table, var key, var value) {
+ // We only store non-null entries in the table, so we have to
+ // change null values to refer to the table itself. Such values
+ // will be recognized and mapped back to null on access.
+ if (value == null) {
+ // Do not update [value] with [table], otherwise our
+ // optimizations could be confused by this opaque object being
+ // now used for more things than storing and fetching from it.
+ JS('void', '#[#] = #', table, key, table);
+ } else {
+ JS('void', '#[#] = #', table, key, value);
+ }
+ }
+
+ static void _deleteTableEntry(var table, var key) {
+ JS('void', 'delete #[#]', table, key);
+ }
+
+ List _getBucket(var table, var key) {
+ var hash = _computeHashCode(key);
+ return JS('var', '#[#]', table, hash);
+ }
+
+ int _findBucketIndex(var bucket, var key) {
+ if (bucket == null) return -1;
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i += 2) {
+ if (JS('var', '#[#]', bucket, i) == key) return i;
+ }
+ return -1;
+ }
+
+ static _newHashTable() {
+ // Create a new JavaScript object to be used as a hash table. Use
+ // Object.create to avoid the properties on Object.prototype
+ // showing up as entries.
+ var table = JS('var', 'Object.create(null)');
+ // Attempt to force the hash table into 'dictionary' mode by
+ // adding a property to it and deleting it again.
+ var temporaryKey = '<non-identifier-key>';
+ _setTableEntry(table, temporaryKey, table);
+ _deleteTableEntry(table, temporaryKey);
+ return table;
+ }
+}
+
+class _IdentityHashMap<K, V> extends _HashMap<K, V> {
+ int _computeHashCode(var key) {
+ // We force the hash codes to be unsigned 30-bit integers to avoid
+ // issues with problematic keys like '__proto__'. Another option
+ // would be to throw an exception if the hash code isn't a number.
+ return JS('int', '# & #', identityHashCode(key), _mask30);
+ }
+
+ int _findBucketIndex(var bucket, var key) {
+ if (bucket == null) return -1;
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i += 2) {
+ if (identical(JS('var', '#[#]', bucket, i), key)) return i;
+ }
+ return -1;
+ }
+}
+
+class _CustomHashMap<K, V> extends _HashMap<K, V> {
+ final _Equality<K> _equals;
+ final _Hasher<K> _hashCode;
+ final _Predicate _validKey;
+
+ _CustomHashMap(this._equals, this._hashCode, bool validKey(potentialKey))
+ : _validKey = (validKey != null) ? validKey : ((v) => v is K);
+
+ V operator [](Object key) {
+ if (!_validKey(key)) return null;
+ return super._get(key);
+ }
+
+ void operator []=(K key, V value) {
+ super._set(key, value);
+ }
+
+ bool containsKey(Object key) {
+ if (!_validKey(key)) return false;
+ return super._containsKey(key);
+ }
+
+ V remove(Object key) {
+ if (!_validKey(key)) return null;
+ return super._remove(key);
+ }
+
+ int _computeHashCode(var key) {
+ // We force the hash codes to be unsigned 30-bit integers to avoid
+ // issues with problematic keys like '__proto__'. Another option
+ // would be to throw an exception if the hash code isn't a number.
+ return JS('int', '# & #', _hashCode(key), _mask30);
+ }
+
+ int _findBucketIndex(var bucket, var key) {
+ if (bucket == null) return -1;
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i += 2) {
+ if (_equals(JS('var', '#[#]', bucket, i), key)) return i;
+ }
+ return -1;
+ }
+}
+
+class _HashMapKeyIterable<E> extends EfficientLengthIterable<E> {
+ final _map;
+ _HashMapKeyIterable(this._map);
+
+ int get length => _map._length;
+ bool get isEmpty => _map._length == 0;
+
+ Iterator<E> get iterator {
+ return new _HashMapKeyIterator<E>(_map, _map._computeKeys());
+ }
+
+ bool contains(Object element) {
+ return _map.containsKey(element);
+ }
+
+ void forEach(void f(E element)) {
+ List keys = _map._computeKeys();
+ for (int i = 0, length = JS('int', '#.length', keys); i < length; i++) {
+ f(JS('var', '#[#]', keys, i));
+ if (JS('bool', '# !== #', keys, _map._keys)) {
+ throw new ConcurrentModificationError(_map);
+ }
+ }
+ }
+}
+
+class _HashMapKeyIterator<E> implements Iterator<E> {
+ final _map;
+ final List _keys;
+ int _offset = 0;
+ E _current;
+
+ _HashMapKeyIterator(this._map, this._keys);
+
+ E get current => _current;
+
+ bool moveNext() {
+ var keys = _keys;
+ int offset = _offset;
+ if (JS('bool', '# !== #', keys, _map._keys)) {
+ throw new ConcurrentModificationError(_map);
+ } else if (offset >= JS('int', '#.length', keys)) {
+ _current = null;
+ return false;
+ } else {
+ _current = JS('var', '#[#]', keys, offset);
+ // TODO(kasperl): For now, we have to tell the type inferrer to
+ // treat the result of doing offset + 1 as an int. Otherwise, we
+ // get unnecessary bailout code.
+ _offset = JS('int', '#', offset + 1);
+ return true;
+ }
+ }
+}
+
+@patch
+class LinkedHashMap<K, V> {
+ @patch
+ factory LinkedHashMap(
+ {bool equals(K key1, K key2),
+ int hashCode(K key),
+ bool isValidKey(potentialKey)}) {
+ if (isValidKey == null) {
+ if (hashCode == null) {
+ if (equals == null) {
+ return new JsLinkedHashMap<K, V>.es6();
+ }
+ hashCode = _defaultHashCode;
+ } else {
+ if (identical(identityHashCode, hashCode) &&
+ identical(identical, equals)) {
+ return new _LinkedIdentityHashMap<K, V>.es6();
+ }
+ if (equals == null) {
+ equals = _defaultEquals;
+ }
+ }
+ } else {
+ if (hashCode == null) {
+ hashCode = _defaultHashCode;
+ }
+ if (equals == null) {
+ equals = _defaultEquals;
+ }
+ }
+ return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey);
+ }
+
+ @patch
+ factory LinkedHashMap.identity() = _LinkedIdentityHashMap<K, V>.es6;
+
+ // Private factory constructor called by generated code for map literals.
+ @pragma('dart2js:noInline')
+ factory LinkedHashMap._literal(List keyValuePairs) {
+ return fillLiteralMap(keyValuePairs, new JsLinkedHashMap<K, V>.es6());
+ }
+
+ // Private factory constructor called by generated code for map literals.
+ @pragma('dart2js:noThrows')
+ @pragma('dart2js:noInline')
+ @pragma('dart2js:noSideEffects')
+ factory LinkedHashMap._empty() {
+ return new JsLinkedHashMap<K, V>.es6();
+ }
+
+ // Private factory static function called by generated code for map literals.
+ // This version is for map literals without type parameters.
+ @pragma('dart2js:noThrows')
+ @pragma('dart2js:noInline')
+ @pragma('dart2js:noSideEffects')
+ static _makeEmpty() => new JsLinkedHashMap();
+
+ // Private factory static function called by generated code for map literals.
+ // This version is for map literals without type parameters.
+ @pragma('dart2js:noInline')
+ static _makeLiteral(keyValuePairs) =>
+ fillLiteralMap(keyValuePairs, new JsLinkedHashMap());
+}
+
+class _LinkedIdentityHashMap<K, V> extends JsLinkedHashMap<K, V> {
+ static bool get _supportsEs6Maps {
+ return JS('returns:bool;depends:none;effects:none;throws:never;gvn:true',
+ 'typeof Map != "undefined"');
+ }
+
+ factory _LinkedIdentityHashMap.es6() {
+ return (_USE_ES6_MAPS && _LinkedIdentityHashMap._supportsEs6Maps)
+ ? new _Es6LinkedIdentityHashMap<K, V>()
+ : new _LinkedIdentityHashMap<K, V>();
+ }
+
+ _LinkedIdentityHashMap();
+
+ int internalComputeHashCode(var key) {
+ // We force the hash codes to be unsigned 30-bit integers to avoid
+ // issues with problematic keys like '__proto__'. Another option
+ // would be to throw an exception if the hash code isn't a number.
+ return JS('int', '# & #', identityHashCode(key), _mask30);
+ }
+
+ int internalFindBucketIndex(var bucket, var key) {
+ if (bucket == null) return -1;
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i++) {
+ LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
+ if (identical(cell.hashMapCellKey, key)) return i;
+ }
+ return -1;
+ }
+}
+
+class _Es6LinkedIdentityHashMap<K, V> extends _LinkedIdentityHashMap<K, V>
+ implements InternalMap {
+ final _map;
+ int _modifications = 0;
+
+ _Es6LinkedIdentityHashMap() : _map = JS('var', 'new Map()');
+
+ int get length => JS('int', '#.size', _map);
+ bool get isEmpty => length == 0;
+ bool get isNotEmpty => !isEmpty;
+
+ Iterable<K> get keys => new _Es6MapIterable<K>(this, true);
+
+ Iterable<V> get values => new _Es6MapIterable<V>(this, false);
+
+ bool containsKey(Object key) {
+ return JS('bool', '#.has(#)', _map, key);
+ }
+
+ bool containsValue(Object value) {
+ return values.any((each) => each == value);
+ }
+
+ void addAll(Map<K, V> other) {
+ other.forEach((K key, V value) {
+ this[key] = value;
+ });
+ }
+
+ V operator [](Object key) {
+ return JS('var', '#.get(#)', _map, key);
+ }
+
+ void operator []=(K key, V value) {
+ JS('var', '#.set(#, #)', _map, key, value);
+ _modified();
+ }
+
+ V putIfAbsent(K key, V ifAbsent()) {
+ if (containsKey(key)) return this[key];
+ V value = ifAbsent();
+ this[key] = value;
+ return value;
+ }
+
+ V remove(Object key) {
+ V value = this[key];
+ JS('bool', '#.delete(#)', _map, key);
+ _modified();
+ return value;
+ }
+
+ void clear() {
+ JS('void', '#.clear()', _map);
+ _modified();
+ }
+
+ void forEach(void action(K key, V value)) {
+ var jsEntries = JS('var', '#.entries()', _map);
+ int modifications = _modifications;
+ while (true) {
+ var next = JS('var', '#.next()', jsEntries);
+ bool done = JS('bool', '#.done', next);
+ if (done) break;
+ var entry = JS('var', '#.value', next);
+ var key = JS('var', '#[0]', entry);
+ var value = JS('var', '#[1]', entry);
+ action(key, value);
+ if (modifications != _modifications) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ }
+
+ void _modified() {
+ // Value cycles after 2^30 modifications so that modification counts are
+ // always unboxed (Smi) values. Modification detection will be missed if you
+ // make exactly some multiple of 2^30 modifications between advances of an
+ // iterator.
+ _modifications = _mask30 & (_modifications + 1);
+ }
+}
+
+class _Es6MapIterable<E> extends EfficientLengthIterable<E> {
+ final _map;
+ final bool _isKeys;
+
+ _Es6MapIterable(this._map, this._isKeys);
+
+ int get length => _map.length;
+ bool get isEmpty => _map.isEmpty;
+
+ Iterator<E> get iterator =>
+ new _Es6MapIterator<E>(_map, _map._modifications, _isKeys);
+
+ bool contains(Object element) => _map.containsKey(element);
+
+ void forEach(void f(E element)) {
+ var jsIterator;
+ if (_isKeys) {
+ jsIterator = JS('var', '#.keys()', _map._map);
+ } else {
+ jsIterator = JS('var', '#.values()', _map._map);
+ }
+ int modifications = _map._modifications;
+ while (true) {
+ var next = JS('var', '#.next()', jsIterator);
+ bool done = JS('bool', '#.done', next);
+ if (done) break;
+ var value = JS('var', '#.value', next);
+ f(value);
+ if (modifications != _map._modifications) {
+ throw new ConcurrentModificationError(_map);
+ }
+ }
+ }
+}
+
+class _Es6MapIterator<E> implements Iterator<E> {
+ final _map;
+ final int _modifications;
+ final bool _isKeys;
+ var _jsIterator;
+ var _next;
+ E _current;
+ bool _done;
+
+ _Es6MapIterator(this._map, this._modifications, this._isKeys) {
+ if (_isKeys) {
+ _jsIterator = JS('var', '#.keys()', _map._map);
+ } else {
+ _jsIterator = JS('var', '#.values()', _map._map);
+ }
+ _done = false;
+ }
+
+ E get current => _current;
+
+ bool moveNext() {
+ if (_modifications != _map._modifications) {
+ throw new ConcurrentModificationError(_map);
+ }
+ if (_done) return false;
+ _next = JS('var', '#.next()', _jsIterator);
+ bool done = JS('bool', '#.done', _next);
+ if (done) {
+ _current = null;
+ _done = true;
+ return false;
+ } else {
+ _current = JS('var', '#.value', _next);
+ return true;
+ }
+ }
+}
+
+// TODO(floitsch): use ES6 maps when available.
+class _LinkedCustomHashMap<K, V> extends JsLinkedHashMap<K, V> {
+ final _Equality<K> _equals;
+ final _Hasher<K> _hashCode;
+ final _Predicate _validKey;
+
+ _LinkedCustomHashMap(
+ this._equals, this._hashCode, bool validKey(potentialKey))
+ : _validKey = (validKey != null) ? validKey : ((v) => v is K);
+
+ V operator [](Object key) {
+ if (!_validKey(key)) return null;
+ return super.internalGet(key);
+ }
+
+ void operator []=(K key, V value) {
+ super.internalSet(key, value);
+ }
+
+ bool containsKey(Object key) {
+ if (!_validKey(key)) return false;
+ return super.internalContainsKey(key);
+ }
+
+ V remove(Object key) {
+ if (!_validKey(key)) return null;
+ return super.internalRemove(key);
+ }
+
+ int internalComputeHashCode(var key) {
+ // We force the hash codes to be unsigned 30-bit integers to avoid
+ // issues with problematic keys like '__proto__'. Another option
+ // would be to throw an exception if the hash code isn't a number.
+ return JS('int', '# & #', _hashCode(key), _mask30);
+ }
+
+ int internalFindBucketIndex(var bucket, var key) {
+ if (bucket == null) return -1;
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i++) {
+ LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
+ if (_equals(cell.hashMapCellKey, key)) return i;
+ }
+ return -1;
+ }
+}
+
+@patch
+class HashSet<E> {
+ @patch
+ factory HashSet(
+ {bool equals(E e1, E e2),
+ int hashCode(E e),
+ bool isValidKey(potentialKey)}) {
+ if (isValidKey == null) {
+ if (hashCode == null) {
+ if (equals == null) {
+ return new _HashSet<E>();
+ }
+ hashCode = _defaultHashCode;
+ } else {
+ if (identical(identityHashCode, hashCode) &&
+ identical(identical, equals)) {
+ return new _IdentityHashSet<E>();
+ }
+ if (equals == null) {
+ equals = _defaultEquals;
+ }
+ }
+ } else {
+ if (hashCode == null) {
+ hashCode = _defaultHashCode;
+ }
+ if (equals == null) {
+ equals = _defaultEquals;
+ }
+ }
+ return new _CustomHashSet<E>(equals, hashCode, isValidKey);
+ }
+
+ @patch
+ factory HashSet.identity() = _IdentityHashSet<E>;
+}
+
+class _HashSet<E> extends _SetBase<E> implements HashSet<E> {
+ int _length = 0;
+
+ // The hash set contents are divided into three parts: one part for
+ // string elements, one for numeric elements, and one for the
+ // rest. String and numeric elements map directly to a sentinel
+ // value, but the rest of the entries are stored in bucket lists of
+ // the form:
+ //
+ // [element-0, element-1, element-2, ...]
+ //
+ // where all elements in the same bucket share the same hash code.
+ var _strings;
+ var _nums;
+ var _rest;
+
+ // When iterating over the hash set, it is very convenient to have a
+ // list of all the elements. We cache that on the instance and clear
+ // the cache whenever the set changes. This is also used to
+ // guard against concurrent modifications.
+ List _elements;
+
+ _HashSet();
+
+ Set<E> _newSet() => new _HashSet<E>();
+ Set<R> _newSimilarSet<R>() => new _HashSet<R>();
+
+ // Iterable.
+ Iterator<E> get iterator {
+ return new _HashSetIterator<E>(this, _computeElements());
+ }
+
+ int get length => _length;
+ bool get isEmpty => _length == 0;
+ bool get isNotEmpty => !isEmpty;
+
+ bool contains(Object object) {
+ if (_isStringElement(object)) {
+ var strings = _strings;
+ return (strings == null) ? false : _hasTableEntry(strings, object);
+ } else if (_isNumericElement(object)) {
+ var nums = _nums;
+ return (nums == null) ? false : _hasTableEntry(nums, object);
+ } else {
+ return _contains(object);
+ }
+ }
+
+ bool _contains(Object object) {
+ var rest = _rest;
+ if (rest == null) return false;
+ var bucket = _getBucket(rest, object);
+ return _findBucketIndex(bucket, object) >= 0;
+ }
+
+ E lookup(Object object) {
+ if (_isStringElement(object) || _isNumericElement(object)) {
+ return this.contains(object) ? object : null;
+ }
+ return _lookup(object);
+ }
+
+ E _lookup(Object object) {
+ var rest = _rest;
+ if (rest == null) return null;
+ var bucket = _getBucket(rest, object);
+ var index = _findBucketIndex(bucket, object);
+ if (index < 0) return null;
+ return bucket[index];
+ }
+
+ // Collection.
+ bool add(E element) {
+ if (_isStringElement(element)) {
+ var strings = _strings;
+ if (strings == null) _strings = strings = _newHashTable();
+ return _addHashTableEntry(strings, element);
+ } else if (_isNumericElement(element)) {
+ var nums = _nums;
+ if (nums == null) _nums = nums = _newHashTable();
+ return _addHashTableEntry(nums, element);
+ } else {
+ return _add(element);
+ }
+ }
+
+ bool _add(E element) {
+ var rest = _rest;
+ if (rest == null) _rest = rest = _newHashTable();
+ var hash = _computeHashCode(element);
+ var bucket = JS('var', '#[#]', rest, hash);
+ if (bucket == null) {
+ _setTableEntry(rest, hash, JS('var', '[#]', element));
+ } else {
+ int index = _findBucketIndex(bucket, element);
+ if (index >= 0) return false;
+ JS('void', '#.push(#)', bucket, element);
+ }
+ _length++;
+ _elements = null;
+ return true;
+ }
+
+ void addAll(Iterable<E> objects) {
+ for (E each in objects) {
+ add(each);
+ }
+ }
+
+ bool remove(Object object) {
+ if (_isStringElement(object)) {
+ return _removeHashTableEntry(_strings, object);
+ } else if (_isNumericElement(object)) {
+ return _removeHashTableEntry(_nums, object);
+ } else {
+ return _remove(object);
+ }
+ }
+
+ bool _remove(Object object) {
+ var rest = _rest;
+ if (rest == null) return false;
+ var bucket = _getBucket(rest, object);
+ int index = _findBucketIndex(bucket, object);
+ if (index < 0) return false;
+ // TODO(kasperl): Consider getting rid of the bucket list when
+ // the length reaches zero.
+ _length--;
+ _elements = null;
+ // TODO(kasperl): It would probably be faster to move the
+ // element to the end and reduce the length of the bucket list.
+ JS('void', '#.splice(#, 1)', bucket, index);
+ return true;
+ }
+
+ void clear() {
+ if (_length > 0) {
+ _strings = _nums = _rest = _elements = null;
+ _length = 0;
+ }
+ }
+
+ List _computeElements() {
+ if (_elements != null) return _elements;
+ List result = new List(_length);
+ int index = 0;
+
+ // Add all string elements to the list.
+ var strings = _strings;
+ if (strings != null) {
+ var names = JS('var', 'Object.getOwnPropertyNames(#)', strings);
+ int entries = JS('int', '#.length', names);
+ for (int i = 0; i < entries; i++) {
+ String element = JS('String', '#[#]', names, i);
+ JS('void', '#[#] = #', result, index, element);
+ index++;
+ }
+ }
+
+ // Add all numeric elements to the list.
+ var nums = _nums;
+ if (nums != null) {
+ var names = JS('var', 'Object.getOwnPropertyNames(#)', nums);
+ int entries = JS('int', '#.length', names);
+ for (int i = 0; i < entries; i++) {
+ // Object.getOwnPropertyNames returns a list of strings, so we
+ // have to convert the elements back to numbers (+).
+ num element = JS('num', '+#[#]', names, i);
+ JS('void', '#[#] = #', result, index, element);
+ index++;
+ }
+ }
+
+ // Add all the remaining elements to the list.
+ var rest = _rest;
+ if (rest != null) {
+ var names = JS('var', 'Object.getOwnPropertyNames(#)', rest);
+ int entries = JS('int', '#.length', names);
+ for (int i = 0; i < entries; i++) {
+ var entry = JS('String', '#[#]', names, i);
+ var bucket = JS('var', '#[#]', rest, entry);
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i++) {
+ JS('void', '#[#] = #[#]', result, index, bucket, i);
+ index++;
+ }
+ }
+ }
+ assert(index == _length);
+ return _elements = result;
+ }
+
+ bool _addHashTableEntry(var table, E element) {
+ if (_hasTableEntry(table, element)) return false;
+ _setTableEntry(table, element, 0);
+ _length++;
+ _elements = null;
+ return true;
+ }
+
+ bool _removeHashTableEntry(var table, Object element) {
+ if (table != null && _hasTableEntry(table, element)) {
+ _deleteTableEntry(table, element);
+ _length--;
+ _elements = null;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ static bool _isStringElement(var element) {
+ return element is String && element != '__proto__';
+ }
+
+ static bool _isNumericElement(var element) {
+ // Only treat unsigned 30-bit integers as numeric elements. This
+ // way, we avoid converting them to strings when we use them as
+ // keys in the JavaScript hash table object.
+ return element is num &&
+ JS('bool', '(# & #) === #', element, _mask30, element);
+ }
+
+ int _computeHashCode(var element) {
+ // We force the hash codes to be unsigned 30-bit integers to avoid
+ // issues with problematic elements like '__proto__'. Another
+ // option would be to throw an exception if the hash code isn't a
+ // number.
+ return JS('int', '# & #', element.hashCode, _mask30);
+ }
+
+ static bool _hasTableEntry(var table, var key) {
+ var entry = JS('var', '#[#]', table, key);
+ // We take care to only store non-null entries in the table, so we
+ // can check if the table has an entry for the given key with a
+ // simple null check.
+ return entry != null;
+ }
+
+ static void _setTableEntry(var table, var key, var value) {
+ assert(value != null);
+ JS('void', '#[#] = #', table, key, value);
+ }
+
+ static void _deleteTableEntry(var table, var key) {
+ JS('void', 'delete #[#]', table, key);
+ }
+
+ List _getBucket(var table, var element) {
+ var hash = _computeHashCode(element);
+ return JS('var', '#[#]', table, hash);
+ }
+
+ int _findBucketIndex(var bucket, var element) {
+ if (bucket == null) return -1;
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i++) {
+ if (JS('var', '#[#]', bucket, i) == element) return i;
+ }
+ return -1;
+ }
+
+ static _newHashTable() {
+ // Create a new JavaScript object to be used as a hash table. Use
+ // Object.create to avoid the properties on Object.prototype
+ // showing up as entries.
+ var table = JS('var', 'Object.create(null)');
+ // Attempt to force the hash table into 'dictionary' mode by
+ // adding a property to it and deleting it again.
+ var temporaryKey = '<non-identifier-key>';
+ _setTableEntry(table, temporaryKey, table);
+ _deleteTableEntry(table, temporaryKey);
+ return table;
+ }
+}
+
+class _IdentityHashSet<E> extends _HashSet<E> {
+ Set<E> _newSet() => new _IdentityHashSet<E>();
+ Set<R> _newSimilarSet<R>() => new _IdentityHashSet<R>();
+
+ int _computeHashCode(var key) {
+ // We force the hash codes to be unsigned 30-bit integers to avoid
+ // issues with problematic keys like '__proto__'. Another option
+ // would be to throw an exception if the hash code isn't a number.
+ return JS('int', '# & #', identityHashCode(key), _mask30);
+ }
+
+ int _findBucketIndex(var bucket, var element) {
+ if (bucket == null) return -1;
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i++) {
+ if (identical(JS('var', '#[#]', bucket, i), element)) return i;
+ }
+ return -1;
+ }
+}
+
+class _CustomHashSet<E> extends _HashSet<E> {
+ _Equality<E> _equality;
+ _Hasher<E> _hasher;
+ _Predicate _validKey;
+ _CustomHashSet(this._equality, this._hasher, bool validKey(potentialKey))
+ : _validKey = (validKey != null) ? validKey : ((x) => x is E);
+
+ Set<E> _newSet() => new _CustomHashSet<E>(_equality, _hasher, _validKey);
+ Set<R> _newSimilarSet<R>() => new _HashSet<R>();
+
+ int _findBucketIndex(var bucket, var element) {
+ if (bucket == null) return -1;
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i++) {
+ if (_equality(JS('var', '#[#]', bucket, i), element)) return i;
+ }
+ return -1;
+ }
+
+ int _computeHashCode(var element) {
+ // We force the hash codes to be unsigned 30-bit integers to avoid
+ // issues with problematic elements like '__proto__'. Another
+ // option would be to throw an exception if the hash code isn't a
+ // number.
+ return JS('int', '# & #', _hasher(element), _mask30);
+ }
+
+ bool add(E object) => super._add(object);
+
+ bool contains(Object object) {
+ if (!_validKey(object)) return false;
+ return super._contains(object);
+ }
+
+ E lookup(Object object) {
+ if (!_validKey(object)) return null;
+ return super._lookup(object);
+ }
+
+ bool remove(Object object) {
+ if (!_validKey(object)) return false;
+ return super._remove(object);
+ }
+}
+
+// TODO(kasperl): Share this code with _HashMapKeyIterator<E>?
+class _HashSetIterator<E> implements Iterator<E> {
+ final _set;
+ final List _elements;
+ int _offset = 0;
+ E _current;
+
+ _HashSetIterator(this._set, this._elements);
+
+ E get current => _current;
+
+ bool moveNext() {
+ var elements = _elements;
+ int offset = _offset;
+ if (JS('bool', '# !== #', elements, _set._elements)) {
+ throw new ConcurrentModificationError(_set);
+ } else if (offset >= JS('int', '#.length', elements)) {
+ _current = null;
+ return false;
+ } else {
+ _current = JS('var', '#[#]', elements, offset);
+ // TODO(kasperl): For now, we have to tell the type inferrer to
+ // treat the result of doing offset + 1 as an int. Otherwise, we
+ // get unnecessary bailout code.
+ _offset = JS('int', '#', offset + 1);
+ return true;
+ }
+ }
+}
+
+@patch
+class LinkedHashSet<E> {
+ @patch
+ factory LinkedHashSet(
+ {bool equals(E e1, E e2),
+ int hashCode(E e),
+ bool isValidKey(potentialKey)}) {
+ if (isValidKey == null) {
+ if (hashCode == null) {
+ if (equals == null) {
+ return new _LinkedHashSet<E>();
+ }
+ hashCode = _defaultHashCode;
+ } else {
+ if (identical(identityHashCode, hashCode) &&
+ identical(identical, equals)) {
+ return new _LinkedIdentityHashSet<E>();
+ }
+ if (equals == null) {
+ equals = _defaultEquals;
+ }
+ }
+ } else {
+ if (hashCode == null) {
+ hashCode = _defaultHashCode;
+ }
+ if (equals == null) {
+ equals = _defaultEquals;
+ }
+ }
+ return new _LinkedCustomHashSet<E>(equals, hashCode, isValidKey);
+ }
+
+ @patch
+ factory LinkedHashSet.identity() = _LinkedIdentityHashSet<E>;
+
+ // Private factory constructor called by generated code for set literals.
+ @pragma('dart2js:noThrows')
+ @pragma('dart2js:noInline')
+ @pragma('dart2js:noSideEffects')
+ factory LinkedHashSet._empty() => new _LinkedHashSet<E>();
+
+ // Private factory constructor called by generated code for set literals.
+ @pragma('dart2js:noInline')
+ factory LinkedHashSet._literal(List values) =>
+ fillLiteralSet(values, new _LinkedHashSet<E>());
+
+ // Private factory static function called by generated code for set literals.
+ // This version is for set literals without type parameters.
+ @pragma('dart2js:noThrows')
+ @pragma('dart2js:noInline')
+ @pragma('dart2js:noSideEffects')
+ static _makeEmpty() => new _LinkedHashSet();
+
+ // Private factory static function called by generated code for set literals.
+ // This version is for set literals without type parameters.
+ @pragma('dart2js:noInline')
+ static _makeLiteral(List values) =>
+ fillLiteralSet(values, new _LinkedHashSet());
+}
+
+class _LinkedHashSet<E> extends _SetBase<E> implements LinkedHashSet<E> {
+ int _length = 0;
+
+ // The hash set contents are divided into three parts: one part for
+ // string elements, one for numeric elements, and one for the
+ // rest. String and numeric elements map directly to their linked
+ // cells, but the rest of the entries are stored in bucket lists of
+ // the form:
+ //
+ // [cell-0, cell-1, ...]
+ //
+ // where all elements in the same bucket share the same hash code.
+ var _strings;
+ var _nums;
+ var _rest;
+
+ // The elements are stored in cells that are linked together
+ // to form a double linked list.
+ _LinkedHashSetCell _first;
+ _LinkedHashSetCell _last;
+
+ // We track the number of modifications done to the element set to
+ // be able to throw when the set is modified while being iterated
+ // over.
+ int _modifications = 0;
+
+ _LinkedHashSet();
+
+ Set<E> _newSet() => new _LinkedHashSet<E>();
+ Set<R> _newSimilarSet<R>() => new _LinkedHashSet<R>();
+
+ void _unsupported(String operation) {
+ throw 'LinkedHashSet: unsupported $operation';
+ }
+
+ // Iterable.
+ Iterator<E> get iterator {
+ return new _LinkedHashSetIterator(this, _modifications);
+ }
+
+ int get length => _length;
+ bool get isEmpty => _length == 0;
+ bool get isNotEmpty => !isEmpty;
+
+ bool contains(Object object) {
+ if (_isStringElement(object)) {
+ var strings = _strings;
+ if (strings == null) return false;
+ _LinkedHashSetCell cell = _getTableEntry(strings, object);
+ return cell != null;
+ } else if (_isNumericElement(object)) {
+ var nums = _nums;
+ if (nums == null) return false;
+ _LinkedHashSetCell cell = _getTableEntry(nums, object);
+ return cell != null;
+ } else {
+ return _contains(object);
+ }
+ }
+
+ bool _contains(Object object) {
+ var rest = _rest;
+ if (rest == null) return false;
+ var bucket = _getBucket(rest, object);
+ return _findBucketIndex(bucket, object) >= 0;
+ }
+
+ E lookup(Object object) {
+ if (_isStringElement(object) || _isNumericElement(object)) {
+ return this.contains(object) ? object : null;
+ } else {
+ return _lookup(object);
+ }
+ }
+
+ E _lookup(Object object) {
+ var rest = _rest;
+ if (rest == null) return null;
+ var bucket = _getBucket(rest, object);
+ var index = _findBucketIndex(bucket, object);
+ if (index < 0) return null;
+ return bucket[index]._element;
+ }
+
+ void forEach(void action(E element)) {
+ _LinkedHashSetCell cell = _first;
+ int modifications = _modifications;
+ while (cell != null) {
+ action(cell._element);
+ if (modifications != _modifications) {
+ throw new ConcurrentModificationError(this);
+ }
+ cell = cell._next;
+ }
+ }
+
+ E get first {
+ if (_first == null) throw new StateError("No elements");
+ return _first._element;
+ }
+
+ E get last {
+ if (_last == null) throw new StateError("No elements");
+ return _last._element;
+ }
+
+ // Collection.
+ bool add(E element) {
+ if (_isStringElement(element)) {
+ var strings = _strings;
+ if (strings == null) _strings = strings = _newHashTable();
+ return _addHashTableEntry(strings, element);
+ } else if (_isNumericElement(element)) {
+ var nums = _nums;
+ if (nums == null) _nums = nums = _newHashTable();
+ return _addHashTableEntry(nums, element);
+ } else {
+ return _add(element);
+ }
+ }
+
+ bool _add(E element) {
+ var rest = _rest;
+ if (rest == null) _rest = rest = _newHashTable();
+ var hash = _computeHashCode(element);
+ var bucket = JS('var', '#[#]', rest, hash);
+ if (bucket == null) {
+ _LinkedHashSetCell cell = _newLinkedCell(element);
+ _setTableEntry(rest, hash, JS('var', '[#]', cell));
+ } else {
+ int index = _findBucketIndex(bucket, element);
+ if (index >= 0) return false;
+ _LinkedHashSetCell cell = _newLinkedCell(element);
+ JS('void', '#.push(#)', bucket, cell);
+ }
+ return true;
+ }
+
+ bool remove(Object object) {
+ if (_isStringElement(object)) {
+ return _removeHashTableEntry(_strings, object);
+ } else if (_isNumericElement(object)) {
+ return _removeHashTableEntry(_nums, object);
+ } else {
+ return _remove(object);
+ }
+ }
+
+ bool _remove(Object object) {
+ var rest = _rest;
+ if (rest == null) return false;
+ var bucket = _getBucket(rest, object);
+ int index = _findBucketIndex(bucket, object);
+ if (index < 0) return false;
+ // Use splice to remove the [cell] element at the index and
+ // unlink it.
+ _LinkedHashSetCell cell = JS('var', '#.splice(#, 1)[0]', bucket, index);
+ _unlinkCell(cell);
+ return true;
+ }
+
+ void removeWhere(bool test(E element)) {
+ _filterWhere(test, true);
+ }
+
+ void retainWhere(bool test(E element)) {
+ _filterWhere(test, false);
+ }
+
+ void _filterWhere(bool test(E element), bool removeMatching) {
+ _LinkedHashSetCell cell = _first;
+ while (cell != null) {
+ E element = cell._element;
+ _LinkedHashSetCell next = cell._next;
+ int modifications = _modifications;
+ bool shouldRemove = (removeMatching == test(element));
+ if (modifications != _modifications) {
+ throw new ConcurrentModificationError(this);
+ }
+ if (shouldRemove) remove(element);
+ cell = next;
+ }
+ }
+
+ void clear() {
+ if (_length > 0) {
+ _strings = _nums = _rest = _first = _last = null;
+ _length = 0;
+ _modified();
+ }
+ }
+
+ bool _addHashTableEntry(var table, E element) {
+ _LinkedHashSetCell cell = _getTableEntry(table, element);
+ if (cell != null) return false;
+ _setTableEntry(table, element, _newLinkedCell(element));
+ return true;
+ }
+
+ bool _removeHashTableEntry(var table, Object element) {
+ if (table == null) return false;
+ _LinkedHashSetCell cell = _getTableEntry(table, element);
+ if (cell == null) return false;
+ _unlinkCell(cell);
+ _deleteTableEntry(table, element);
+ return true;
+ }
+
+ void _modified() {
+ // Value cycles after 2^30 modifications. If you keep hold of an
+ // iterator for that long, you might miss a modification
+ // detection, and iteration can go sour. Don't do that.
+ _modifications = _mask30 & (_modifications + 1);
+ }
+
+ // Create a new cell and link it in as the last one in the list.
+ _LinkedHashSetCell _newLinkedCell(E element) {
+ _LinkedHashSetCell cell = new _LinkedHashSetCell(element);
+ if (_first == null) {
+ _first = _last = cell;
+ } else {
+ _LinkedHashSetCell last = _last;
+ cell._previous = last;
+ _last = last._next = cell;
+ }
+ _length++;
+ _modified();
+ return cell;
+ }
+
+ // Unlink the given cell from the linked list of cells.
+ void _unlinkCell(_LinkedHashSetCell cell) {
+ _LinkedHashSetCell previous = cell._previous;
+ _LinkedHashSetCell next = cell._next;
+ if (previous == null) {
+ assert(cell == _first);
+ _first = next;
+ } else {
+ previous._next = next;
+ }
+ if (next == null) {
+ assert(cell == _last);
+ _last = previous;
+ } else {
+ next._previous = previous;
+ }
+ _length--;
+ _modified();
+ }
+
+ static bool _isStringElement(var element) {
+ return element is String && element != '__proto__';
+ }
+
+ static bool _isNumericElement(var element) {
+ // Only treat unsigned 30-bit integers as numeric elements. This
+ // way, we avoid converting them to strings when we use them as
+ // keys in the JavaScript hash table object.
+ return element is num &&
+ JS('bool', '(# & #) === #', element, _mask30, element);
+ }
+
+ int _computeHashCode(var element) {
+ // We force the hash codes to be unsigned 30-bit integers to avoid
+ // issues with problematic elements like '__proto__'. Another
+ // option would be to throw an exception if the hash code isn't a
+ // number.
+ return JS('int', '# & #', element.hashCode, _mask30);
+ }
+
+ static _getTableEntry(var table, var key) {
+ return JS('var', '#[#]', table, key);
+ }
+
+ static void _setTableEntry(var table, var key, var value) {
+ assert(value != null);
+ JS('void', '#[#] = #', table, key, value);
+ }
+
+ static void _deleteTableEntry(var table, var key) {
+ JS('void', 'delete #[#]', table, key);
+ }
+
+ List _getBucket(var table, var element) {
+ var hash = _computeHashCode(element);
+ return JS('var', '#[#]', table, hash);
+ }
+
+ int _findBucketIndex(var bucket, var element) {
+ if (bucket == null) return -1;
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i++) {
+ _LinkedHashSetCell cell = JS('var', '#[#]', bucket, i);
+ if (cell._element == element) return i;
+ }
+ return -1;
+ }
+
+ static _newHashTable() {
+ // Create a new JavaScript object to be used as a hash table. Use
+ // Object.create to avoid the properties on Object.prototype
+ // showing up as entries.
+ var table = JS('var', 'Object.create(null)');
+ // Attempt to force the hash table into 'dictionary' mode by
+ // adding a property to it and deleting it again.
+ var temporaryKey = '<non-identifier-key>';
+ _setTableEntry(table, temporaryKey, table);
+ _deleteTableEntry(table, temporaryKey);
+ return table;
+ }
+}
+
+class _LinkedIdentityHashSet<E> extends _LinkedHashSet<E> {
+ Set<E> _newSet() => new _LinkedIdentityHashSet<E>();
+ Set<R> _newSimilarSet<R>() => new _LinkedIdentityHashSet<R>();
+
+ int _computeHashCode(var key) {
+ // We force the hash codes to be unsigned 30-bit integers to avoid
+ // issues with problematic keys like '__proto__'. Another option
+ // would be to throw an exception if the hash code isn't a number.
+ return JS('int', '# & #', identityHashCode(key), _mask30);
+ }
+
+ int _findBucketIndex(var bucket, var element) {
+ if (bucket == null) return -1;
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i++) {
+ _LinkedHashSetCell cell = JS('var', '#[#]', bucket, i);
+ if (identical(cell._element, element)) return i;
+ }
+ return -1;
+ }
+}
+
+class _LinkedCustomHashSet<E> extends _LinkedHashSet<E> {
+ _Equality<E> _equality;
+ _Hasher<E> _hasher;
+ _Predicate _validKey;
+ _LinkedCustomHashSet(
+ this._equality, this._hasher, bool validKey(potentialKey))
+ : _validKey = (validKey != null) ? validKey : ((x) => x is E);
+
+ Set<E> _newSet() =>
+ new _LinkedCustomHashSet<E>(_equality, _hasher, _validKey);
+ Set<R> _newSimilarSet<R>() => new _LinkedHashSet<R>();
+
+ int _findBucketIndex(var bucket, var element) {
+ if (bucket == null) return -1;
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i++) {
+ _LinkedHashSetCell cell = JS('var', '#[#]', bucket, i);
+ if (_equality(cell._element, element)) return i;
+ }
+ return -1;
+ }
+
+ int _computeHashCode(var element) {
+ // We force the hash codes to be unsigned 30-bit integers to avoid
+ // issues with problematic elements like '__proto__'. Another
+ // option would be to throw an exception if the hash code isn't a
+ // number.
+ return JS('int', '# & #', _hasher(element), _mask30);
+ }
+
+ bool add(E element) => super._add(element);
+
+ bool contains(Object object) {
+ if (!_validKey(object)) return false;
+ return super._contains(object);
+ }
+
+ E lookup(Object object) {
+ if (!_validKey(object)) return null;
+ return super._lookup(object);
+ }
+
+ bool remove(Object object) {
+ if (!_validKey(object)) return false;
+ return super._remove(object);
+ }
+
+ bool containsAll(Iterable<Object> elements) {
+ for (Object element in elements) {
+ if (!_validKey(element) || !this.contains(element)) return false;
+ }
+ return true;
+ }
+
+ void removeAll(Iterable<Object> elements) {
+ for (Object element in elements) {
+ if (_validKey(element)) {
+ super._remove(element);
+ }
+ }
+ }
+}
+
+class _LinkedHashSetCell {
+ final _element;
+
+ _LinkedHashSetCell _next;
+ _LinkedHashSetCell _previous;
+
+ _LinkedHashSetCell(this._element);
+}
+
+// TODO(kasperl): Share this code with LinkedHashMapKeyIterator<E>?
+class _LinkedHashSetIterator<E> implements Iterator<E> {
+ final _set;
+ final int _modifications;
+ _LinkedHashSetCell _cell;
+ E _current;
+
+ _LinkedHashSetIterator(this._set, this._modifications) {
+ _cell = _set._first;
+ }
+
+ E get current => _current;
+
+ bool moveNext() {
+ if (_modifications != _set._modifications) {
+ throw new ConcurrentModificationError(_set);
+ } else if (_cell == null) {
+ _current = null;
+ return false;
+ } else {
+ _current = _cell._element;
+ _cell = _cell._next;
+ return true;
+ }
+ }
+}
+
+@patch
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
+ @patch
+ Node _splayMin(Node node) {
+ Node current = node;
+ while (current.left != null) {
+ Node left = current.left;
+ current.left = left.right;
+ left.right = current;
+ current = left;
+ }
+ return current;
+ }
+
+ @patch
+ Node _splayMax(Node node) {
+ Node current = node;
+ while (current.right != null) {
+ Node right = current.right;
+ current.right = right.left;
+ right.left = current;
+ current = right;
+ }
+ return current;
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/constant_map.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/constant_map.dart
new file mode 100644
index 0000000..f7c7936
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/constant_map.dart
@@ -0,0 +1,222 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _js_helper;
+
+class ConstantMapView<K, V> extends UnmodifiableMapView<K, V>
+ implements ConstantMap<K, V> {
+ ConstantMapView(Map<K, V> base) : super(base);
+}
+
+abstract class ConstantMap<K, V> implements Map<K, V> {
+ // Used to create unmodifiable maps from other maps.
+ factory ConstantMap.from(Map other) {
+ List keys = new List<K>.from(other.keys);
+ bool allStrings = true;
+ for (var k in keys) {
+ if (k is! String) {
+ allStrings = false;
+ break;
+ }
+ }
+ if (allStrings) {
+ bool containsProto = false;
+ var protoValue = null;
+ var object = JS('=Object', '{}');
+ int length = 0;
+ for (var k in keys) {
+ V v = other[k];
+ if (k != '__proto__') {
+ if (!jsHasOwnProperty(object, k)) length++;
+ JS('void', '#[#] = #', object, k, v);
+ } else {
+ containsProto = true;
+ protoValue = v;
+ }
+ }
+ if (containsProto) {
+ length++;
+ return new ConstantProtoMap<K, V>._(length, object, keys, protoValue);
+ }
+ return new ConstantStringMap<K, V>._(length, object, keys);
+ }
+ // TODO(lrn): Make a proper unmodifiable map implementation.
+ return new ConstantMapView<K, V>(new Map.from(other));
+ }
+
+ const ConstantMap._();
+
+ Map<RK, RV> cast<RK, RV>() => Map.castFrom<K, V, RK, RV>(this);
+ bool get isEmpty => length == 0;
+
+ bool get isNotEmpty => !isEmpty;
+
+ String toString() => MapBase.mapToString(this);
+
+ static Null _throwUnmodifiable() {
+ throw new UnsupportedError('Cannot modify unmodifiable Map');
+ }
+
+ void operator []=(K key, V val) => _throwUnmodifiable();
+ V putIfAbsent(K key, V ifAbsent()) => _throwUnmodifiable();
+ V remove(Object key) => _throwUnmodifiable();
+ void clear() => _throwUnmodifiable();
+ void addAll(Map<K, V> other) => _throwUnmodifiable();
+
+ Iterable<MapEntry<K, V>> get entries sync* {
+ for (var key in keys) yield new MapEntry<K, V>(key, this[key]);
+ }
+
+ void addEntries(Iterable<MapEntry<K, V>> entries) {
+ for (var entry in entries) this[entry.key] = entry.value;
+ }
+
+ Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> transform(K key, V value)) {
+ var result = <K2, V2>{};
+ this.forEach((K key, V value) {
+ var entry = transform(key, value);
+ result[entry.key] = entry.value;
+ });
+ return result;
+ }
+
+ V update(K key, V update(V value), {V ifAbsent()}) {
+ _throwUnmodifiable();
+ }
+
+ void updateAll(V update(K key, V value)) {
+ _throwUnmodifiable();
+ }
+
+ void removeWhere(bool test(K key, V value)) {
+ _throwUnmodifiable();
+ }
+}
+
+class ConstantStringMap<K, V> extends ConstantMap<K, V> {
+ // This constructor is not used for actual compile-time constants.
+ // The instantiation of constant maps is shortcut by the compiler.
+ const ConstantStringMap._(this._length, this._jsObject, this._keys)
+ : super._();
+
+ // TODO(18131): Ensure type inference knows the precise types of the fields.
+ final int _length;
+ // A constant map is backed by a JavaScript object.
+ final _jsObject;
+ final List<K> _keys;
+
+ int get length => JS('JSUInt31', '#', _length);
+ List<K> get _keysArray => JS('JSUnmodifiableArray', '#', _keys);
+
+ bool containsValue(Object needle) {
+ return values.any((V value) => value == needle);
+ }
+
+ bool containsKey(Object key) {
+ if (key is! String) return false;
+ if ('__proto__' == key) return false;
+ return jsHasOwnProperty(_jsObject, key);
+ }
+
+ V operator [](Object key) {
+ if (!containsKey(key)) return null;
+ return JS('', '#', _fetch(key));
+ }
+
+ // [_fetch] is the indexer for keys for which `containsKey(key)` is true.
+ _fetch(key) => jsPropertyAccess(_jsObject, key);
+
+ void forEach(void f(K key, V value)) {
+ // Use a JS 'cast' to get efficient loop. Type inference doesn't get this
+ // since constant map representation is chosen after type inference and the
+ // instantiation is shortcut by the compiler.
+ var keys = _keysArray;
+ for (int i = 0; i < keys.length; i++) {
+ var key = keys[i];
+ f(key, _fetch(key));
+ }
+ }
+
+ Iterable<K> get keys {
+ return new _ConstantMapKeyIterable<K>(this);
+ }
+
+ Iterable<V> get values {
+ return new MappedIterable<K, V>(_keysArray, (key) => _fetch(key));
+ }
+}
+
+class ConstantProtoMap<K, V> extends ConstantStringMap<K, V> {
+ // This constructor is not used. The instantiation is shortcut by the
+ // compiler. It is here to make the uninitialized final fields legal.
+ ConstantProtoMap._(length, jsObject, keys, this._protoValue)
+ : super._(length, jsObject, keys);
+
+ final V _protoValue;
+
+ bool containsKey(Object key) {
+ if (key is! String) return false;
+ if ('__proto__' == key) return true;
+ return jsHasOwnProperty(_jsObject, key);
+ }
+
+ _fetch(key) =>
+ '__proto__' == key ? _protoValue : jsPropertyAccess(_jsObject, key);
+}
+
+class _ConstantMapKeyIterable<K> extends Iterable<K> {
+ ConstantStringMap<K, dynamic> _map;
+ _ConstantMapKeyIterable(this._map);
+
+ Iterator<K> get iterator => _map._keysArray.iterator;
+
+ int get length => _map._keysArray.length;
+}
+
+class GeneralConstantMap<K, V> extends ConstantMap<K, V> {
+ // This constructor is not used. The instantiation is shortcut by the
+ // compiler. It is here to make the uninitialized final fields legal.
+ GeneralConstantMap(this._jsData) : super._();
+
+ // [_jsData] holds a key-value pair list.
+ final _jsData;
+
+ // We cannot create the backing map on creation since hashCode interceptors
+ // have not been defined when constants are created.
+ Map<K, V> _getMap() {
+ LinkedHashMap<K, V> backingMap = JS('LinkedHashMap|Null', r'#.$map', this);
+ if (backingMap == null) {
+ backingMap = new JsLinkedHashMap<K, V>();
+ fillLiteralMap(_jsData, backingMap);
+ JS('', r'#.$map = #', this, backingMap);
+ }
+ return backingMap;
+ }
+
+ bool containsValue(Object needle) {
+ return _getMap().containsValue(needle);
+ }
+
+ bool containsKey(Object key) {
+ return _getMap().containsKey(key);
+ }
+
+ V operator [](Object key) {
+ return _getMap()[key];
+ }
+
+ void forEach(void f(K key, V value)) {
+ _getMap().forEach(f);
+ }
+
+ Iterable<K> get keys {
+ return _getMap().keys;
+ }
+
+ Iterable<V> get values {
+ return _getMap().values;
+ }
+
+ int get length => _getMap().length;
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/convert_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/convert_patch.dart
new file mode 100644
index 0000000..fa6a0b0
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/convert_patch.dart
@@ -0,0 +1,502 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:convert library.
+
+import 'dart:_js_helper' show argumentErrorValue, patch;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show JSArray, JSExtendableArray;
+import 'dart:_internal' show MappedIterable, ListIterable;
+import 'dart:collection' show LinkedHashMap, MapBase;
+import 'dart:_native_typed_data' show NativeUint8List;
+
+/// Parses [json] and builds the corresponding parsed JSON value.
+///
+/// Parsed JSON values Nare of the types [num], [String], [bool], [Null],
+/// [List]s of parsed JSON values or [Map]s from [String] to parsed
+/// JSON values.
+///
+/// The optional [reviver] function, if provided, is called once for each object
+/// or list property parsed. The arguments are the property name ([String]) or
+/// list index ([int]), and the value is the parsed value. The return value of
+/// the reviver will be used as the value of that property instead of the parsed
+/// value. The top level value is passed to the reviver with the empty string
+/// as a key.
+///
+/// Throws [FormatException] if the input is not valid JSON text.
+@patch
+_parseJson(String source, reviver(key, value)) {
+ if (source is! String) throw argumentErrorValue(source);
+
+ var parsed;
+ try {
+ parsed = JS('=Object|JSExtendableArray|Null|bool|num|String',
+ 'JSON.parse(#)', source);
+ } catch (e) {
+ throw new FormatException(JS('String', 'String(#)', e));
+ }
+
+ if (reviver == null) {
+ return _convertJsonToDartLazy(parsed);
+ } else {
+ return _convertJsonToDart(parsed, reviver);
+ }
+}
+
+/// Walks the raw JavaScript value [json], replacing JavaScript Objects with
+/// Maps. [json] is expected to be freshly allocated so elements can be replaced
+/// in-place.
+_convertJsonToDart(json, reviver(key, value)) {
+ assert(reviver != null);
+ walk(e) {
+ // JavaScript null, string, number, bool are in the correct representation.
+ if (JS('bool', '# == null', e) || JS('bool', 'typeof # != "object"', e)) {
+ return e;
+ }
+
+ // This test is needed to avoid identifying '{"__proto__":[]}' as an Array.
+ // TODO(sra): Replace this test with cheaper '#.constructor === Array' when
+ // bug 621 below is fixed.
+ if (JS('bool', 'Object.getPrototypeOf(#) === Array.prototype', e)) {
+ // In-place update of the elements since JS Array is a Dart List.
+ for (int i = 0; i < JS('int', '#.length', e); i++) {
+ // Use JS indexing to avoid range checks. We know this is the only
+ // reference to the list, but the compiler will likely never be able to
+ // tell that this instance of the list cannot have its length changed by
+ // the reviver even though it later will be passed to the reviver at the
+ // outer level.
+ var item = JS('', '#[#]', e, i);
+ JS('', '#[#]=#', e, i, reviver(i, walk(item)));
+ }
+ return e;
+ }
+
+ // Otherwise it is a plain object, so copy to a JSON map, so we process
+ // and revive all entries recursively.
+ _JsonMap map = new _JsonMap(e);
+ var processed = map._processed;
+ List<String> keys = map._computeKeys();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i];
+ var revived = reviver(key, walk(JS('', '#[#]', e, key)));
+ JS('', '#[#]=#', processed, key, revived);
+ }
+
+ // Update the JSON map structure so future access is cheaper.
+ map._original = processed; // Don't keep two objects around.
+ return map;
+ }
+
+ return reviver(null, walk(json));
+}
+
+_convertJsonToDartLazy(object) {
+ // JavaScript null and undefined are represented as null.
+ if (object == null) return null;
+
+ // JavaScript string, number, bool already has the correct representation.
+ if (JS('bool', 'typeof # != "object"', object)) {
+ return object;
+ }
+
+ // This test is needed to avoid identifying '{"__proto__":[]}' as an array.
+ // TODO(sra): Replace this test with cheaper '#.constructor === Array' when
+ // bug https://code.google.com/p/v8/issues/detail?id=621 is fixed.
+ if (JS('bool', 'Object.getPrototypeOf(#) !== Array.prototype', object)) {
+ return new _JsonMap(object);
+ }
+
+ // Update the elements in place since JS arrays are Dart lists.
+ for (int i = 0; i < JS('int', '#.length', object); i++) {
+ // Use JS indexing to avoid range checks. We know this is the only
+ // reference to the list, but the compiler will likely never be able to
+ // tell that this instance of the list cannot have its length changed by
+ // the reviver even though it later will be passed to the reviver at the
+ // outer level.
+ var item = JS('', '#[#]', object, i);
+ JS('', '#[#]=#', object, i, _convertJsonToDartLazy(item));
+ }
+ return object;
+}
+
+class _JsonMap extends MapBase<String, dynamic> {
+ // The original JavaScript object remains unchanged until
+ // the map is eventually upgraded, in which case we null it
+ // out to reclaim the memory used by it.
+ var _original;
+
+ // We keep track of the map entries that we have already
+ // processed by adding them to a separate JavaScript object.
+ var _processed = _newJavaScriptObject();
+
+ // If the data slot isn't null, it represents either the list
+ // of keys (for non-upgraded JSON maps) or the upgraded map.
+ var _data = null;
+
+ _JsonMap(this._original);
+
+ operator [](key) {
+ if (_isUpgraded) {
+ return _upgradedMap[key];
+ } else if (key is! String) {
+ return null;
+ } else {
+ var result = _getProperty(_processed, key);
+ if (_isUnprocessed(result)) result = _process(key);
+ return result;
+ }
+ }
+
+ int get length => _isUpgraded ? _upgradedMap.length : _computeKeys().length;
+
+ bool get isEmpty => length == 0;
+ bool get isNotEmpty => length > 0;
+
+ Iterable<String> get keys {
+ if (_isUpgraded) return _upgradedMap.keys;
+ return new _JsonMapKeyIterable(this);
+ }
+
+ Iterable get values {
+ if (_isUpgraded) return _upgradedMap.values;
+ return new MappedIterable(_computeKeys(), (each) => this[each]);
+ }
+
+ operator []=(key, value) {
+ if (_isUpgraded) {
+ _upgradedMap[key] = value;
+ } else if (containsKey(key)) {
+ var processed = _processed;
+ _setProperty(processed, key, value);
+ var original = _original;
+ if (!identical(original, processed)) {
+ _setProperty(original, key, null); // Reclaim memory.
+ }
+ } else {
+ _upgrade()[key] = value;
+ }
+ }
+
+ void addAll(Map<String, dynamic> other) {
+ other.forEach((key, value) {
+ this[key] = value;
+ });
+ }
+
+ bool containsValue(value) {
+ if (_isUpgraded) return _upgradedMap.containsValue(value);
+ List<String> keys = _computeKeys();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i];
+ if (this[key] == value) return true;
+ }
+ return false;
+ }
+
+ bool containsKey(key) {
+ if (_isUpgraded) return _upgradedMap.containsKey(key);
+ if (key is! String) return false;
+ return _hasProperty(_original, key);
+ }
+
+ putIfAbsent(key, ifAbsent()) {
+ if (containsKey(key)) return this[key];
+ var value = ifAbsent();
+ this[key] = value;
+ return value;
+ }
+
+ remove(Object key) {
+ if (!_isUpgraded && !containsKey(key)) return null;
+ return _upgrade().remove(key);
+ }
+
+ void clear() {
+ if (_isUpgraded) {
+ _upgradedMap.clear();
+ } else {
+ if (_data != null) {
+ // Clear the list of keys to make sure we force
+ // a concurrent modification error if anyone is
+ // currently iterating over it.
+ _data.clear();
+ }
+ _original = _processed = null;
+ _data = {};
+ }
+ }
+
+ void forEach(void f(String key, value)) {
+ if (_isUpgraded) return _upgradedMap.forEach(f);
+ List<String> keys = _computeKeys();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i];
+
+ // Compute the value under the assumption that the property
+ // is present but potentially not processed.
+ var value = _getProperty(_processed, key);
+ if (_isUnprocessed(value)) {
+ value = _convertJsonToDartLazy(_getProperty(_original, key));
+ _setProperty(_processed, key, value);
+ }
+
+ // Do the callback.
+ f(key, value);
+
+ // Check if invoking the callback function changed
+ // the key set. If so, throw an exception.
+ if (!identical(keys, _data)) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ }
+
+ // ------------------------------------------
+ // Private helper methods.
+ // ------------------------------------------
+
+ bool get _isUpgraded => _processed == null;
+
+ Map<String, dynamic> get _upgradedMap {
+ assert(_isUpgraded);
+ // 'cast' the union type to LinkedHashMap. It would be even better if we
+ // could 'cast' to the implementation type, since LinkedHashMap includes
+ // _JsonMap.
+ return JS('LinkedHashMap', '#', _data);
+ }
+
+ List<String> _computeKeys() {
+ assert(!_isUpgraded);
+ List keys = _data;
+ if (keys == null) {
+ keys = _data = new JSArray<String>.typed(_getPropertyNames(_original));
+ }
+ return JS('JSExtendableArray', '#', keys);
+ }
+
+ Map<String, dynamic> _upgrade() {
+ if (_isUpgraded) return _upgradedMap;
+
+ // Copy all the (key, value) pairs to a freshly allocated
+ // linked hash map thus preserving the ordering.
+ var result = <String, dynamic>{};
+ List<String> keys = _computeKeys();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i];
+ result[key] = this[key];
+ }
+
+ // We only upgrade when we need to extend the map, so we can
+ // safely force a concurrent modification error in case
+ // someone is iterating over the map here.
+ if (keys.isEmpty) {
+ keys.add(null);
+ } else {
+ keys.clear();
+ }
+
+ // Clear out the associated JavaScript objects and mark the
+ // map as having been upgraded.
+ _original = _processed = null;
+ _data = result;
+ assert(_isUpgraded);
+ return result;
+ }
+
+ _process(String key) {
+ if (!_hasProperty(_original, key)) return null;
+ var result = _convertJsonToDartLazy(_getProperty(_original, key));
+ return _setProperty(_processed, key, result);
+ }
+
+ // ------------------------------------------
+ // Private JavaScript helper methods.
+ // ------------------------------------------
+
+ static bool _hasProperty(object, String key) =>
+ JS('bool', 'Object.prototype.hasOwnProperty.call(#,#)', object, key);
+ static _getProperty(object, String key) => JS('', '#[#]', object, key);
+ static _setProperty(object, String key, value) =>
+ JS('', '#[#]=#', object, key, value);
+ static List _getPropertyNames(object) =>
+ JS('JSExtendableArray', 'Object.keys(#)', object);
+ static bool _isUnprocessed(object) =>
+ JS('bool', 'typeof(#)=="undefined"', object);
+ static _newJavaScriptObject() => JS('=Object', 'Object.create(null)');
+}
+
+class _JsonMapKeyIterable extends ListIterable<String> {
+ final _JsonMap _parent;
+
+ _JsonMapKeyIterable(this._parent);
+
+ int get length => _parent.length;
+
+ String elementAt(int index) {
+ return _parent._isUpgraded
+ ? _parent.keys.elementAt(index)
+ : _parent._computeKeys()[index];
+ }
+
+ /// Although [ListIterable] defines its own iterator, we return the iterator
+ /// of the underlying list [_keys] in order to propagate
+ /// [ConcurrentModificationError]s.
+ Iterator<String> get iterator {
+ return _parent._isUpgraded
+ ? _parent.keys.iterator
+ : _parent._computeKeys().iterator;
+ }
+
+ /// Delegate to [parent.containsKey] to ensure the performance expected
+ /// from [Map.keys.containsKey].
+ bool contains(Object key) => _parent.containsKey(key);
+}
+
+@patch
+class JsonDecoder {
+ @patch
+ StringConversionSink startChunkedConversion(Sink<Object> sink) {
+ return new _JsonDecoderSink(_reviver, sink);
+ }
+}
+
+/// Implements the chunked conversion from a JSON string to its corresponding
+/// object.
+///
+/// The sink only creates one object, but its input can be chunked.
+// TODO(floitsch): don't accumulate everything before starting to decode.
+class _JsonDecoderSink extends _StringSinkConversionSink {
+ final Function(Object key, Object value) _reviver;
+ final Sink<Object> _sink;
+
+ _JsonDecoderSink(this._reviver, this._sink) : super(new StringBuffer(''));
+
+ void close() {
+ super.close();
+ StringBuffer buffer = _stringSink;
+ String accumulated = buffer.toString();
+ buffer.clear();
+ Object decoded = _parseJson(accumulated, _reviver);
+ _sink.add(decoded);
+ _sink.close();
+ }
+}
+
+@patch
+class Utf8Decoder {
+ @patch
+ Converter<List<int>, T> fuse<T>(Converter<String, T> next) {
+ return super.fuse(next);
+ }
+
+ @patch
+ static String _convertIntercepted(
+ bool allowMalformed, List<int> codeUnits, int start, int end) {
+ // Test `codeUnits is NativeUint8List`. Dart's NativeUint8List is
+ // implemented by JavaScript's Uint8Array.
+ if (JS('bool', '# instanceof Uint8Array', codeUnits)) {
+ // JS 'cast' to avoid a downcast equivalent to the is-check we hand-coded.
+ NativeUint8List casted = JS('NativeUint8List', '#', codeUnits);
+ return _convertInterceptedUint8List(allowMalformed, casted, start, end);
+ }
+ return null; // This call was not intercepted.
+ }
+
+ static String _convertInterceptedUint8List(
+ bool allowMalformed, NativeUint8List codeUnits, int start, int end) {
+ if (allowMalformed) {
+ // TextDecoder with option {fatal: false} does not produce the same result
+ // as [Utf8Decoder]. It disagrees on the number of `U+FFFD` (REPLACEMENT
+ // CHARACTER) generated for some malformed sequences. We could use
+ // TextDecoder with option {fatal: true}, catch the error, and re-try
+ // without acceleration. That turns out to be extremely slow (the Error
+ // captures a stack trace).
+ // TODO(31370): Bring Utf8Decoder into alignment with TextDecoder.
+ // TODO(sra): If we can't do that, can we detect valid input fast enough
+ // to use a check like the [_unsafe] check below?
+ return null;
+ }
+
+ var decoder = _decoder;
+ if (decoder == null) return null;
+ if (0 == start && end == null) {
+ return _useTextDecoderChecked(decoder, codeUnits);
+ }
+
+ int length = codeUnits.length;
+ end = RangeError.checkValidRange(start, end, length);
+
+ if (0 == start && end == codeUnits.length) {
+ return _useTextDecoderChecked(decoder, codeUnits);
+ }
+
+ return _useTextDecoderChecked(decoder,
+ JS('NativeUint8List', '#.subarray(#, #)', codeUnits, start, end));
+ }
+
+ static String _useTextDecoderChecked(decoder, NativeUint8List codeUnits) {
+ if (_unsafe(codeUnits)) return null;
+ return _useTextDecoderUnchecked(decoder, codeUnits);
+ }
+
+ static String _useTextDecoderUnchecked(decoder, NativeUint8List codeUnits) {
+ // If the input is malformed, catch the exception and return `null` to fall
+ // back on unintercepted decoder. The fallback will either succeed in
+ // decoding, or report the problem better than TextDecoder.
+ try {
+ return JS('String', '#.decode(#)', decoder, codeUnits);
+ } catch (e) {}
+ return null;
+ }
+
+ /// Returns `true` if [codeUnits] contains problematic encodings.
+ ///
+ /// TextDecoder behaves differently to [Utf8Encoder] when the input encodes a
+ /// surrogate (U+D800 through U+DFFF). TextDecoder considers the surrogate to
+ /// be an encoding error and, depending on the `fatal` option, either throws
+ /// and Error or encodes the surrogate as U+FFFD. [Utf8Decoder] does not
+ /// consider the surrogate to be an error and returns the code unit encoded by
+ /// the surrogate.
+ ///
+ /// Throwing an `Error` captures the stack, whoch makes it so expensive that
+ /// it is worth checking the input for surrogates and avoiding TextDecoder in
+ /// this case.
+ static bool _unsafe(NativeUint8List codeUnits) {
+ // Surrogates encode as (hex) ED Ax xx or ED Bx xx.
+ int limit = codeUnits.length - 2;
+ for (int i = 0; i < limit; i++) {
+ int unit1 = codeUnits[i];
+ if (unit1 == 0xED) {
+ int unit2 = codeUnits[i + 1];
+ if ((unit2 & 0xE0) == 0xA0) return true;
+ }
+ }
+ return false;
+ }
+
+ // TextDecoder is not defined on some browsers and on the stand-alone d8 and
+ // jsshell engines. Use a lazy initializer to do feature detection once.
+ static final _decoder = _makeDecoder();
+ static _makeDecoder() {
+ try {
+ // Use `{fatal: true}`. 'fatal' does not correspond exactly to
+ // `!allowMalformed`: TextDecoder rejects unpaired surrogates which
+ // [Utf8Decoder] accepts. In non-fatal mode, TextDecoder translates
+ // unpaired surrogates to REPLACEMENT CHARACTER (U+FFFD) whereas
+ // [Utf8Decoder] leaves the surrogate intact.
+ return JS('', 'new TextDecoder("utf-8", {fatal: true})');
+ } catch (e) {}
+ return null;
+ }
+}
+
+@patch
+int _scanOneByteCharacters(List<int> units, int from, int endIndex) {
+ final to = endIndex;
+ for (var i = from; i < to; i++) {
+ final unit = units[i];
+ if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
+ }
+ return to - from;
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart
new file mode 100644
index 0000000..c655fc2
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart
@@ -0,0 +1,2928 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:core classes.
+import "dart:_internal" hide Symbol, LinkedList, LinkedListEntry;
+import "dart:_internal" as _symbol_dev;
+import 'dart:_interceptors';
+import 'dart:_js_helper'
+ show
+ checkInt,
+ Closure,
+ ConstantMap,
+ getRuntimeType,
+ JsLinkedHashMap,
+ jsonEncodeNative,
+ JSSyntaxRegExp,
+ NoInline,
+ objectHashCode,
+ patch,
+ Primitives,
+ quoteStringForRegExp,
+ stringJoinUnchecked,
+ getTraceFromException,
+ RuntimeError;
+
+import 'dart:_foreign_helper' show JS, JS_GET_FLAG;
+
+import 'dart:_native_typed_data' show NativeUint8List;
+
+import "dart:convert" show Encoding, utf8;
+
+import 'dart:typed_data' show Endian, Uint8List, Uint16List;
+
+String _symbolToString(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
+
+Map<String, dynamic> _symbolMapToStringMap(Map<Symbol, dynamic> map) {
+ if (map == null) return null;
+ var result = new Map<String, dynamic>();
+ map.forEach((Symbol key, value) {
+ result[_symbolToString(key)] = value;
+ });
+ return result;
+}
+
+@patch
+int identityHashCode(Object object) => objectHashCode(object);
+
+// Patch for Object implementation.
+@patch
+class Object {
+ @patch
+ bool operator ==(other) => identical(this, other);
+
+ @patch
+ int get hashCode => Primitives.objectHashCode(this);
+
+ @patch
+ String toString() => Primitives.objectToHumanReadableString(this);
+
+ @patch
+ dynamic noSuchMethod(Invocation invocation) {
+ throw new NoSuchMethodError(this, invocation.memberName,
+ invocation.positionalArguments, invocation.namedArguments);
+ }
+
+ @patch
+ Type get runtimeType => getRuntimeType(this);
+}
+
+@patch
+class Null {
+ @patch
+ int get hashCode => super.hashCode;
+}
+
+// Patch for Function implementation.
+@patch
+class Function {
+ @patch
+ static apply(Function function, List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
+ return Primitives.applyFunction(
+ function,
+ positionalArguments,
+ // Use this form so that if namedArguments is always null, we can
+ // tree-shake _symbolMapToStringMap.
+ namedArguments == null ? null : _symbolMapToStringMap(namedArguments));
+ }
+}
+
+// Patch for Expando implementation.
+@patch
+class Expando<T> {
+ static const String _EXPANDO_PROPERTY_NAME = 'expando\$values';
+
+ // Incremented to make unique keys.
+ static int _keyCount = 0;
+
+ // Stores either a JS WeakMap or a "unique" string key.
+ final Object _jsWeakMapOrKey;
+
+ @patch
+ Expando([String name])
+ : this.name = name,
+ _jsWeakMapOrKey = JS('bool', 'typeof WeakMap == "function"')
+ ? JS('=Object|Null', 'new WeakMap()')
+ : _createKey();
+
+ @patch
+ T operator [](Object object) {
+ if (_jsWeakMapOrKey is! String) {
+ _checkType(object); // WeakMap doesn't check on reading, only writing.
+ return JS('', '#.get(#)', _jsWeakMapOrKey, object);
+ }
+ return _getFromObject(_jsWeakMapOrKey, object);
+ }
+
+ @patch
+ void operator []=(Object object, T value) {
+ if (_jsWeakMapOrKey is! String) {
+ JS('void', '#.set(#, #)', _jsWeakMapOrKey, object, value);
+ } else {
+ _setOnObject(_jsWeakMapOrKey, object, value);
+ }
+ }
+
+ static Object _getFromObject(String key, Object object) {
+ var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
+ return (values == null) ? null : Primitives.getProperty(values, key);
+ }
+
+ static void _setOnObject(String key, Object object, Object value) {
+ var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
+ if (values == null) {
+ values = new Object();
+ Primitives.setProperty(object, _EXPANDO_PROPERTY_NAME, values);
+ }
+ Primitives.setProperty(values, key, value);
+ }
+
+ static String _createKey() => "expando\$key\$${_keyCount++}";
+
+ static _checkType(object) {
+ if (object == null || object is bool || object is num || object is String) {
+ throw new ArgumentError.value(object,
+ "Expandos are not allowed on strings, numbers, booleans or null");
+ }
+ }
+}
+
+@patch
+class int {
+ @patch
+ static int parse(String source,
+ {int radix, @deprecated int onError(String source)}) {
+ int value = tryParse(source, radix: radix);
+ if (value != null) return value;
+ if (onError != null) return onError(source);
+ throw new FormatException(source);
+ }
+
+ @patch
+ static int tryParse(String source, {int radix}) {
+ return Primitives.parseInt(source, radix);
+ }
+}
+
+@patch
+class double {
+ @patch
+ static double parse(String source,
+ [@deprecated double onError(String source)]) {
+ double value = tryParse(source);
+ if (value != null) return value;
+ if (onError != null) return onError(source);
+ throw new FormatException('Invalid double', source);
+ }
+
+ @patch
+ static double tryParse(String source) {
+ return Primitives.parseDouble(source);
+ }
+}
+
+@patch
+class BigInt implements Comparable<BigInt> {
+ @patch
+ static BigInt get zero => _BigIntImpl.zero;
+ @patch
+ static BigInt get one => _BigIntImpl.one;
+ @patch
+ static BigInt get two => _BigIntImpl.two;
+
+ @patch
+ static BigInt parse(String source, {int radix}) =>
+ _BigIntImpl.parse(source, radix: radix);
+
+ @patch
+ static BigInt tryParse(String source, {int radix}) =>
+ _BigIntImpl._tryParse(source, radix: radix);
+
+ @patch
+ factory BigInt.from(num value) = _BigIntImpl.from;
+}
+
+@patch
+class Error {
+ @patch
+ static String _objectToString(Object object) {
+ // Closures all have useful and safe toString methods.
+ if (object is Closure) return object.toString();
+ return Primitives.objectToHumanReadableString(object);
+ }
+
+ @patch
+ static String _stringToSafeString(String string) {
+ return jsonEncodeNative(string);
+ }
+
+ @patch
+ StackTrace get stackTrace => Primitives.extractStackTrace(this);
+}
+
+@patch
+class FallThroughError {
+ @patch
+ FallThroughError._create(String url, int line);
+
+ @patch
+ String toString() => super.toString();
+}
+
+@patch
+class AbstractClassInstantiationError {
+ @patch
+ String toString() => "Cannot instantiate abstract class: '$_className'";
+}
+
+// Patch for DateTime implementation.
+@patch
+class DateTime {
+ @patch
+ DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
+ {bool isUtc: false})
+ // `0 + millisecondsSinceEpoch` forces the inferred result to be non-null.
+ : this._withValue(0 + millisecondsSinceEpoch, isUtc: isUtc);
+
+ @patch
+ DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
+ {bool isUtc: false})
+ : this._withValue(
+ _microsecondInRoundedMilliseconds(microsecondsSinceEpoch),
+ isUtc: isUtc);
+
+ @patch
+ DateTime._internal(int year, int month, int day, int hour, int minute,
+ int second, int millisecond, int microsecond, bool isUtc)
+ // checkBool is manually inlined here because dart2js doesn't inline it
+ // and [isUtc] is usually a constant.
+ : this.isUtc = isUtc is bool
+ ? isUtc
+ : throw new ArgumentError.value(isUtc, 'isUtc'),
+ _value = checkInt(Primitives.valueFromDecomposedDate(
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ millisecond + _microsecondInRoundedMilliseconds(microsecond),
+ isUtc));
+
+ @patch
+ DateTime._now()
+ : isUtc = false,
+ _value = Primitives.dateNow();
+
+ /// Rounds the given [microsecond] to the nearest milliseconds value.
+ ///
+ /// For example, invoked with argument `2600` returns `3`.
+ static int _microsecondInRoundedMilliseconds(int microsecond) {
+ return (microsecond / 1000).round();
+ }
+
+ @patch
+ static int _brokenDownDateToValue(int year, int month, int day, int hour,
+ int minute, int second, int millisecond, int microsecond, bool isUtc) {
+ return Primitives.valueFromDecomposedDate(
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ millisecond + _microsecondInRoundedMilliseconds(microsecond),
+ isUtc);
+ }
+
+ @patch
+ String get timeZoneName {
+ if (isUtc) return "UTC";
+ return Primitives.getTimeZoneName(this);
+ }
+
+ @patch
+ Duration get timeZoneOffset {
+ if (isUtc) return new Duration();
+ return new Duration(minutes: Primitives.getTimeZoneOffsetInMinutes(this));
+ }
+
+ @patch
+ DateTime add(Duration duration) {
+ return new DateTime._withValue(_value + duration.inMilliseconds,
+ isUtc: isUtc);
+ }
+
+ @patch
+ DateTime subtract(Duration duration) {
+ return new DateTime._withValue(_value - duration.inMilliseconds,
+ isUtc: isUtc);
+ }
+
+ @patch
+ Duration difference(DateTime other) {
+ return new Duration(milliseconds: _value - other._value);
+ }
+
+ @patch
+ int get millisecondsSinceEpoch => _value;
+
+ @patch
+ int get microsecondsSinceEpoch => 1000 * _value;
+
+ @patch
+ int get year => Primitives.getYear(this);
+
+ @patch
+ int get month => Primitives.getMonth(this);
+
+ @patch
+ int get day => Primitives.getDay(this);
+
+ @patch
+ int get hour => Primitives.getHours(this);
+
+ @patch
+ int get minute => Primitives.getMinutes(this);
+
+ @patch
+ int get second => Primitives.getSeconds(this);
+
+ @patch
+ int get millisecond => Primitives.getMilliseconds(this);
+
+ @patch
+ int get microsecond => 0;
+
+ @patch
+ int get weekday => Primitives.getWeekday(this);
+
+ @patch
+ bool operator ==(dynamic other) =>
+ other is DateTime &&
+ _value == other.millisecondsSinceEpoch &&
+ isUtc == other.isUtc;
+
+ @patch
+ bool isBefore(DateTime other) => _value < other.millisecondsSinceEpoch;
+
+ @patch
+ bool isAfter(DateTime other) => _value > other.millisecondsSinceEpoch;
+
+ @patch
+ bool isAtSameMomentAs(DateTime other) =>
+ _value == other.millisecondsSinceEpoch;
+
+ @patch
+ int compareTo(DateTime other) =>
+ _value.compareTo(other.millisecondsSinceEpoch);
+}
+
+// Patch for Stopwatch implementation.
+@patch
+class Stopwatch {
+ @patch
+ static void _initTicker() {
+ Primitives.initTicker();
+ _frequency = Primitives.timerFrequency;
+ }
+
+ @patch
+ static int _now() => Primitives.timerTicks();
+
+ @patch
+ int get elapsedMicroseconds {
+ int ticks = elapsedTicks;
+ if (_frequency == 1000000) return ticks;
+ assert(_frequency == 1000);
+ return ticks * 1000;
+ }
+
+ @patch
+ int get elapsedMilliseconds {
+ int ticks = elapsedTicks;
+ if (_frequency == 1000) return ticks;
+ assert(_frequency == 1000000);
+ return ticks ~/ 1000;
+ }
+}
+
+// Patch for List implementation.
+@patch
+class List<E> {
+ @patch
+ factory List([int length]) = JSArray<E>.list;
+
+ @patch
+ factory List.filled(int length, E fill, {bool growable: false}) {
+ List result = growable
+ ? new JSArray<E>.growable(length)
+ : new JSArray<E>.fixed(length);
+ if (length != 0 && fill != null) {
+ for (int i = 0; i < result.length; i++) {
+ result[i] = fill;
+ }
+ }
+ return result;
+ }
+
+ @patch
+ factory List.from(Iterable elements, {bool growable: true}) {
+ List<E> list = <E>[];
+ for (E e in elements) {
+ list.add(e);
+ }
+ if (growable) return list;
+ return makeListFixedLength(list);
+ }
+
+ @patch
+ factory List.unmodifiable(Iterable elements) {
+ List result = new List<E>.from(elements, growable: false);
+ return makeFixedListUnmodifiable(result);
+ }
+}
+
+@patch
+class Map<K, V> {
+ @patch
+ factory Map.unmodifiable(Map other) = ConstantMap<K, V>.from;
+
+ @patch
+ factory Map() = JsLinkedHashMap<K, V>.es6;
+}
+
+@patch
+class String {
+ @patch
+ factory String.fromCharCodes(Iterable<int> charCodes,
+ [int start = 0, int end]) {
+ if (charCodes is JSArray) {
+ JSArray<int> array = charCodes;
+ return _stringFromJSArray(array, start, end);
+ }
+ if (charCodes is NativeUint8List) {
+ return _stringFromUint8List(charCodes, start, end);
+ }
+ return _stringFromIterable(charCodes, start, end);
+ }
+
+ @patch
+ factory String.fromCharCode(int charCode) {
+ return Primitives.stringFromCharCode(charCode);
+ }
+
+ static String _stringFromJSArray(List list, int start, int endOrNull) {
+ int len = list.length;
+ int end = RangeError.checkValidRange(start, endOrNull, len);
+ if (start > 0 || end < len) {
+ list = list.sublist(start, end);
+ }
+ return Primitives.stringFromCharCodes(list);
+ }
+
+ static String _stringFromUint8List(
+ NativeUint8List charCodes, int start, int endOrNull) {
+ int len = charCodes.length;
+ int end = RangeError.checkValidRange(start, endOrNull, len);
+ return Primitives.stringFromNativeUint8List(charCodes, start, end);
+ }
+
+ static String _stringFromIterable(
+ Iterable<int> charCodes, int start, int end) {
+ if (start < 0) throw new RangeError.range(start, 0, charCodes.length);
+ if (end != null && end < start) {
+ throw new RangeError.range(end, start, charCodes.length);
+ }
+ var it = charCodes.iterator;
+ for (int i = 0; i < start; i++) {
+ if (!it.moveNext()) {
+ throw new RangeError.range(start, 0, i);
+ }
+ }
+ var list = [];
+ if (end == null) {
+ while (it.moveNext()) list.add(it.current);
+ } else {
+ for (int i = start; i < end; i++) {
+ if (!it.moveNext()) {
+ throw new RangeError.range(end, start, i);
+ }
+ list.add(it.current);
+ }
+ }
+ return Primitives.stringFromCharCodes(list);
+ }
+}
+
+@patch
+class bool {
+ @patch
+ int get hashCode => super.hashCode;
+}
+
+@patch
+class RegExp {
+ @pragma('dart2js:noInline')
+ @patch
+ factory RegExp(String source,
+ {bool multiLine: false,
+ bool caseSensitive: true,
+ bool unicode: false,
+ bool dotAll: false}) =>
+ new JSSyntaxRegExp(source,
+ multiLine: multiLine,
+ caseSensitive: caseSensitive,
+ unicode: unicode,
+ dotAll: dotAll);
+
+ @patch
+ static String escape(String text) => quoteStringForRegExp(text);
+}
+
+// Patch for 'identical' function.
+@pragma(
+ 'dart2js:noInline') // No inlining since we recognize the call in optimizer.
+@patch
+bool identical(Object a, Object b) {
+ return JS('bool', '(# == null ? # == null : # === #)', a, b, a, b);
+}
+
+@patch
+class StringBuffer {
+ String _contents;
+
+ @patch
+ StringBuffer([Object content = ""]) : _contents = '$content';
+
+ @patch
+ int get length => _contents.length;
+
+ @patch
+ void write(Object obj) {
+ _writeString('$obj');
+ }
+
+ @patch
+ void writeCharCode(int charCode) {
+ _writeString(new String.fromCharCode(charCode));
+ }
+
+ @patch
+ void writeAll(Iterable objects, [String separator = ""]) {
+ _contents = _writeAll(_contents, objects, separator);
+ }
+
+ @patch
+ void writeln([Object obj = ""]) {
+ _writeString('$obj\n');
+ }
+
+ @patch
+ void clear() {
+ _contents = "";
+ }
+
+ @patch
+ String toString() => Primitives.flattenString(_contents);
+
+ void _writeString(str) {
+ _contents = Primitives.stringConcatUnchecked(_contents, str);
+ }
+
+ static String _writeAll(String string, Iterable objects, String separator) {
+ Iterator iterator = objects.iterator;
+ if (!iterator.moveNext()) return string;
+ if (separator.isEmpty) {
+ do {
+ string = _writeOne(string, iterator.current);
+ } while (iterator.moveNext());
+ } else {
+ string = _writeOne(string, iterator.current);
+ while (iterator.moveNext()) {
+ string = _writeOne(string, separator);
+ string = _writeOne(string, iterator.current);
+ }
+ }
+ return string;
+ }
+
+ static String _writeOne(String string, Object obj) {
+ return Primitives.stringConcatUnchecked(string, '$obj');
+ }
+}
+
+@patch
+class NoSuchMethodError {
+ final Object _receiver;
+ final Symbol _memberName;
+ final List _arguments;
+ final Map<Symbol, dynamic> _namedArguments;
+ final List _existingArgumentNames;
+
+ @patch
+ NoSuchMethodError.withInvocation(Object receiver, Invocation invocation)
+ : this(receiver, invocation.memberName, invocation.positionalArguments,
+ invocation.namedArguments);
+
+ @patch
+ NoSuchMethodError(Object receiver, Symbol memberName,
+ List positionalArguments, Map<Symbol, dynamic> namedArguments,
+ [List existingArgumentNames = null])
+ : _receiver = receiver,
+ _memberName = memberName,
+ _arguments = positionalArguments,
+ _namedArguments = namedArguments,
+ _existingArgumentNames = existingArgumentNames;
+
+ @patch
+ String toString() {
+ StringBuffer sb = new StringBuffer('');
+ String comma = '';
+ if (_arguments != null) {
+ for (var argument in _arguments) {
+ sb.write(comma);
+ sb.write(Error.safeToString(argument));
+ comma = ', ';
+ }
+ }
+ if (_namedArguments != null) {
+ _namedArguments.forEach((Symbol key, var value) {
+ sb.write(comma);
+ sb.write(_symbolToString(key));
+ sb.write(": ");
+ sb.write(Error.safeToString(value));
+ comma = ', ';
+ });
+ }
+ String memberName = _symbolToString(_memberName);
+ String receiverText = Error.safeToString(_receiver);
+ String actualParameters = '$sb';
+ if (_existingArgumentNames == null) {
+ return "NoSuchMethodError: method not found: '$memberName'\n"
+ "Receiver: ${receiverText}\n"
+ "Arguments: [$actualParameters]";
+ } else {
+ String formalParameters = _existingArgumentNames.join(', ');
+ return "NoSuchMethodError: incorrect number of arguments passed to "
+ "method named '$memberName'\n"
+ "Receiver: ${receiverText}\n"
+ "Tried calling: $memberName($actualParameters)\n"
+ "Found: $memberName($formalParameters)";
+ }
+ }
+}
+
+class _CompileTimeError extends Error {
+ final String _errorMsg;
+ // TODO(sigmund): consider calling `JS('', 'debugger')`.
+ _CompileTimeError(this._errorMsg);
+ String toString() => _errorMsg;
+}
+
+@patch
+class Uri {
+ @patch
+ static Uri get base {
+ String uri = Primitives.currentUri();
+ if (uri != null) return Uri.parse(uri);
+ throw new UnsupportedError("'Uri.base' is not supported");
+ }
+}
+
+@patch
+class _Uri {
+ @patch
+ static bool get _isWindows => _isWindowsCached;
+
+ static final bool _isWindowsCached = JS(
+ 'bool',
+ 'typeof process != "undefined" && '
+ 'Object.prototype.toString.call(process) == "[object process]" && '
+ 'process.platform == "win32"');
+
+ // Matches a String that _uriEncodes to itself regardless of the kind of
+ // component. This corresponds to [_unreservedTable], i.e. characters that
+ // are not encoded by any encoding table.
+ static final RegExp _needsNoEncoding = new RegExp(r'^[\-\.0-9A-Z_a-z~]*$');
+
+ /// This is the internal implementation of JavaScript's encodeURI function.
+ /// It encodes all characters in the string [text] except for those
+ /// that appear in [canonicalTable], and returns the escaped string.
+ @patch
+ static String _uriEncode(List<int> canonicalTable, String text,
+ Encoding encoding, bool spaceToPlus) {
+ if (identical(encoding, utf8) && _needsNoEncoding.hasMatch(text)) {
+ return text;
+ }
+
+ // Encode the string into bytes then generate an ASCII only string
+ // by percent encoding selected bytes.
+ StringBuffer result = new StringBuffer('');
+ var bytes = encoding.encode(text);
+ for (int i = 0; i < bytes.length; i++) {
+ int byte = bytes[i];
+ if (byte < 128 &&
+ ((canonicalTable[byte >> 4] & (1 << (byte & 0x0f))) != 0)) {
+ result.writeCharCode(byte);
+ } else if (spaceToPlus && byte == _SPACE) {
+ result.write('+');
+ } else {
+ const String hexDigits = '0123456789ABCDEF';
+ result.write('%');
+ result.write(hexDigits[(byte >> 4) & 0x0f]);
+ result.write(hexDigits[byte & 0x0f]);
+ }
+ }
+ return result.toString();
+ }
+}
+
+bool _hasErrorStackProperty = JS('bool', 'new Error().stack != void 0');
+
+@patch
+class StackTrace {
+ @patch
+ @pragma('dart2js:noInline')
+ static StackTrace get current {
+ if (_hasErrorStackProperty) {
+ return getTraceFromException(JS('', 'new Error()'));
+ }
+ // Fallback if new Error().stack does not exist.
+ // Currently only required for IE 11.
+ try {
+ throw '';
+ } catch (_, stackTrace) {
+ return stackTrace;
+ }
+ }
+}
+
+// Called from kernel generated code.
+_malformedTypeError(message) => new RuntimeError(message);
+
+// Called from kernel generated code.
+_genericNoSuchMethod(receiver, memberName, positionalArguments, namedArguments,
+ existingArguments) {
+ return new NoSuchMethodError(
+ receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedConstructorError(receiver, memberName, positionalArguments,
+ namedArguments, existingArguments) {
+ // TODO(sra): Generate an error that reads:
+ //
+ // No constructor '$memberName' declared in class '$receiver'.
+
+ return new NoSuchMethodError(
+ receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedStaticGetterError(receiver, memberName, positionalArguments,
+ namedArguments, existingArguments) {
+ // TODO(sra): Generate customized message.
+ return new NoSuchMethodError(
+ receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedStaticSetterError(receiver, memberName, positionalArguments,
+ namedArguments, existingArguments) {
+ // TODO(sra): Generate customized message.
+ return new NoSuchMethodError(
+ receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedStaticMethodError(receiver, memberName, positionalArguments,
+ namedArguments, existingArguments) {
+ // TODO(sra): Generate customized message.
+ return new NoSuchMethodError(
+ receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedTopLevelGetterError(receiver, memberName, positionalArguments,
+ namedArguments, existingArguments) {
+ // TODO(sra): Generate customized message.
+ return new NoSuchMethodError(
+ receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedTopLevelSetterError(receiver, memberName, positionalArguments,
+ namedArguments, existingArguments) {
+ // TODO(sra): Generate customized message.
+ return new NoSuchMethodError(
+ receiver, memberName, positionalArguments, namedArguments);
+}
+
+// Called from kernel generated code.
+_unresolvedTopLevelMethodError(receiver, memberName, positionalArguments,
+ namedArguments, existingArguments) {
+ // TODO(sra): Generate customized message.
+ return new NoSuchMethodError(
+ receiver, memberName, positionalArguments, namedArguments);
+}
+
+/// Used by Fasta to report a runtime error when a final field with an
+/// initializer is also initialized in a generative constructor.
+///
+/// Note: in strong mode, this is a compile-time error and this class becomes
+/// obsolete.
+class _DuplicatedFieldInitializerError extends Error {
+ final String _name;
+
+ _DuplicatedFieldInitializerError(this._name);
+
+ toString() => "Error: field '$_name' is already initialized.";
+}
+
+// TODO(sra): The rest of this core_patch.dart source should reside in an
+// included part file instead of being inlined. However, part files are not
+// properly supported here.
+
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// part of dart.core;
+
+int _max(int a, int b) => a > b ? a : b;
+int _min(int a, int b) => a < b ? a : b;
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Copyright (c) 2003-2005 Tom Wu
+ * Copyright (c) 2012 Adam Singer (adam@solvr.io)
+ * All Rights Reserved.
+ *
+ * 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" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following condition applies:
+ *
+ * All redistributions must retain an intact copy of this copyright notice
+ * and disclaimer.
+ */
+
+/// An implementation for the arbitrarily large integer.
+///
+/// The integer number is represented by a sign, an array of 16-bit unsigned
+/// integers in little endian format, and a number of used digits in that array.
+class _BigIntImpl implements BigInt {
+ // Bits per digit.
+ static const int _digitBits = 16;
+ static const int _digitBase = 1 << _digitBits;
+ static const int _digitMask = (1 << _digitBits) - 1;
+
+ static final _BigIntImpl zero = new _BigIntImpl._fromInt(0);
+ static final _BigIntImpl one = new _BigIntImpl._fromInt(1);
+ static final _BigIntImpl two = new _BigIntImpl._fromInt(2);
+
+ static final _BigIntImpl _minusOne = -one;
+ static final _BigIntImpl _bigInt10000 = new _BigIntImpl._fromInt(10000);
+
+ // Result cache for last _divRem call.
+ // Result cache for last _divRem call.
+ static Uint16List _lastDividendDigits;
+ static int _lastDividendUsed;
+ static Uint16List _lastDivisorDigits;
+ static int _lastDivisorUsed;
+ static Uint16List _lastQuoRemDigits;
+ static int _lastQuoRemUsed;
+ static int _lastRemUsed;
+ static int _lastRem_nsh;
+
+ /// Whether this bigint is negative.
+ final bool _isNegative;
+
+ /// The unsigned digits of this bigint.
+ ///
+ /// The least significant digit is in slot 0.
+ /// The list may have more digits than needed. That is, `_digits.length` may
+ /// be strictly greater than `_used`.
+ final Uint16List _digits;
+
+ /// The number of used entries in [_digits].
+ ///
+ /// To avoid reallocating [Uint16List]s, lists that are too big are not
+ /// replaced.
+ final int _used;
+
+ /// Parses [source] as a, possibly signed, integer literal and returns its
+ /// value.
+ ///
+ /// The [source] must be a non-empty sequence of base-[radix] digits,
+ /// optionally prefixed with a minus or plus sign ('-' or '+').
+ ///
+ /// The [radix] must be in the range 2..36. The digits used are
+ /// first the decimal digits 0..9, and then the letters 'a'..'z' with
+ /// values 10 through 35. Also accepts upper-case letters with the same
+ /// values as the lower-case ones.
+ ///
+ /// If no [radix] is given then it defaults to 10. In this case, the [source]
+ /// digits may also start with `0x`, in which case the number is interpreted
+ /// as a hexadecimal literal, which effectively means that the `0x` is ignored
+ /// and the radix is instead set to 16.
+ ///
+ /// For any int `n` and radix `r`, it is guaranteed that
+ /// `n == int.parse(n.toRadixString(r), radix: r)`.
+ ///
+ /// Throws a [FormatException] if the [source] is not a valid integer literal,
+ /// optionally prefixed by a sign.
+ static _BigIntImpl parse(String source, {int radix}) {
+ var result = _tryParse(source, radix: radix);
+ if (result == null) {
+ throw new FormatException("Could not parse BigInt", source);
+ }
+ return result;
+ }
+
+ /// Parses a decimal bigint literal.
+ ///
+ /// The [source] must not contain leading or trailing whitespace.
+ static _BigIntImpl _parseDecimal(String source, bool isNegative) {
+ const _0 = 48;
+
+ int part = 0;
+ _BigIntImpl result = zero;
+ // Read in the source 4 digits at a time.
+ // The first part may have a few leading virtual '0's to make the remaining
+ // parts all have exactly 4 digits.
+ int digitInPartCount = 4 - source.length.remainder(4);
+ if (digitInPartCount == 4) digitInPartCount = 0;
+ for (int i = 0; i < source.length; i++) {
+ part = part * 10 + source.codeUnitAt(i) - _0;
+ if (++digitInPartCount == 4) {
+ result = result * _bigInt10000 + new _BigIntImpl._fromInt(part);
+ part = 0;
+ digitInPartCount = 0;
+ }
+ }
+ if (isNegative) return -result;
+ return result;
+ }
+
+ /// Returns the value of a given source digit.
+ ///
+ /// Source digits between "0" and "9" (inclusive) return their decimal value.
+ ///
+ /// Source digits between "a" and "z", or "A" and "Z" (inclusive) return
+ /// 10 + their position in the ASCII alphabet.
+ ///
+ /// The incoming [codeUnit] must be an ASCII code-unit.
+ static int _codeUnitToRadixValue(int codeUnit) {
+ // We know that the characters must be ASCII as otherwise the
+ // regexp wouldn't have matched. Lowercasing by doing `| 0x20` is thus
+ // guaranteed to be a safe operation, since it preserves digits
+ // and lower-cases ASCII letters.
+ const int _0 = 48;
+ const int _9 = 57;
+ const int _a = 97;
+ if (_0 <= codeUnit && codeUnit <= _9) return codeUnit - _0;
+ codeUnit |= 0x20;
+ var result = codeUnit - _a + 10;
+ return result;
+ }
+
+ /// Parses the given [source] string, starting at [startPos], as a hex
+ /// literal.
+ ///
+ /// If [isNegative] is true, negates the result before returning it.
+ ///
+ /// The [source] (substring) must be a valid hex literal.
+ static _BigIntImpl _parseHex(String source, int startPos, bool isNegative) {
+ int hexDigitsPerChunk = _digitBits ~/ 4;
+ int sourceLength = source.length - startPos;
+ int chunkCount = (sourceLength / hexDigitsPerChunk).ceil();
+ var digits = new Uint16List(chunkCount);
+
+ int lastDigitLength = sourceLength - (chunkCount - 1) * hexDigitsPerChunk;
+ int digitIndex = digits.length - 1;
+ int i = startPos;
+ int chunk = 0;
+ for (int j = 0; j < lastDigitLength; j++) {
+ var digitValue = _codeUnitToRadixValue(source.codeUnitAt(i++));
+ if (digitValue >= 16) return null;
+ chunk = chunk * 16 + digitValue;
+ }
+ digits[digitIndex--] = chunk;
+
+ while (i < source.length) {
+ chunk = 0;
+ for (int j = 0; j < hexDigitsPerChunk; j++) {
+ var digitValue = _codeUnitToRadixValue(source.codeUnitAt(i++));
+ if (digitValue >= 16) return null;
+ chunk = chunk * 16 + digitValue;
+ }
+ digits[digitIndex--] = chunk;
+ }
+ if (digits.length == 1 && digits[0] == 0) return zero;
+ return new _BigIntImpl._(isNegative, digits.length, digits);
+ }
+
+ /// Parses the given [source] as a [radix] literal.
+ ///
+ /// The [source] will be checked for invalid characters. If it is invalid,
+ /// this function returns `null`.
+ static _BigIntImpl _parseRadix(String source, int radix, bool isNegative) {
+ var result = zero;
+ var base = new _BigIntImpl._fromInt(radix);
+ for (int i = 0; i < source.length; i++) {
+ var digitValue = _codeUnitToRadixValue(source.codeUnitAt(i));
+ if (digitValue >= radix) return null;
+ result = result * base + new _BigIntImpl._fromInt(digitValue);
+ }
+ if (isNegative) return -result;
+ return result;
+ }
+
+ /// Tries to parse the given [source] as a [radix] literal.
+ ///
+ /// Returns the parsed big integer, or `null` if it failed.
+ ///
+ /// If the [radix] is `null` accepts decimal literals or `0x` hex literals.
+ static _BigIntImpl _tryParse(String source, {int radix}) {
+ if (source == "") return null;
+
+ var re = new RegExp(r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
+ caseSensitive: false);
+ var match = re.firstMatch(source);
+ int signIndex = 1;
+ int hexIndex = 3;
+ int decimalIndex = 4;
+ int nonDecimalHexIndex = 5;
+ if (match == null) return null;
+
+ bool isNegative = match[signIndex] == "-";
+
+ String decimalMatch = match[decimalIndex];
+ String hexMatch = match[hexIndex];
+ String nonDecimalMatch = match[nonDecimalHexIndex];
+
+ if (radix == null) {
+ if (decimalMatch != null) {
+ // Cannot fail because we know that the digits are all decimal.
+ return _parseDecimal(decimalMatch, isNegative);
+ }
+ if (hexMatch != null) {
+ // Cannot fail because we know that the digits are all hex.
+ return _parseHex(hexMatch, 2, isNegative);
+ }
+ return null;
+ }
+
+ if (radix is! int) {
+ throw new ArgumentError.value(radix, 'radix', 'is not an integer');
+ }
+ if (radix < 2 || radix > 36) {
+ throw new RangeError.range(radix, 2, 36, 'radix');
+ }
+ if (radix == 10 && decimalMatch != null) {
+ return _parseDecimal(decimalMatch, isNegative);
+ }
+ if (radix == 16 && (decimalMatch != null || nonDecimalMatch != null)) {
+ return _parseHex(decimalMatch ?? nonDecimalMatch, 0, isNegative);
+ }
+
+ return _parseRadix(
+ decimalMatch ?? nonDecimalMatch ?? hexMatch, radix, isNegative);
+ }
+
+ /// Finds the amount significant digits in the provided [digits] array.
+ static int _normalize(int used, Uint16List digits) {
+ while (used > 0 && digits[used - 1] == 0) used--;
+ return 0 + used; // force inferred result to be non-null.
+ }
+
+ /// Factory returning an instance initialized with the given field values.
+ /// If the [digits] array contains leading 0s, the [used] value is adjusted
+ /// accordingly. The [digits] array is not modified.
+ _BigIntImpl._(bool isNegative, int used, Uint16List digits)
+ : this._normalized(isNegative, _normalize(used, digits), digits);
+
+ _BigIntImpl._normalized(bool isNegative, this._used, this._digits)
+ : _isNegative = _used == 0 ? false : isNegative;
+
+ /// Whether this big integer is zero.
+ bool get _isZero => _used == 0;
+
+ /// Allocates an array of the given [length] and copies the [digits] in the
+ /// range [from] to [to-1], starting at index 0, followed by leading zero
+ /// digits.
+ static Uint16List _cloneDigits(
+ Uint16List digits, int from, int to, int length) {
+ var resultDigits = new Uint16List(length);
+ var n = to - from;
+ for (var i = 0; i < n; i++) {
+ resultDigits[i] = digits[from + i];
+ }
+ return resultDigits;
+ }
+
+ /// Allocates a big integer from the provided [value] number.
+ factory _BigIntImpl.from(num value) {
+ if (value == 0) return zero;
+ if (value == 1) return one;
+ if (value == 2) return two;
+
+ // Given this order dart2js will use the `_fromInt` for smaller value and
+ // then use the bit-manipulating `_fromDouble` for all other values.
+ if (value.abs() < 0x100000000)
+ return new _BigIntImpl._fromInt(value.toInt());
+ if (value is double) return new _BigIntImpl._fromDouble(value);
+ return new _BigIntImpl._fromInt(value);
+ }
+
+ factory _BigIntImpl._fromInt(int value) {
+ bool isNegative = value < 0;
+ assert(_digitBits == 16);
+ if (isNegative) {
+ // Handle the min 64-bit value differently, since its negation is not
+ // positive.
+ const int minInt64 = -0x80000000 * 0x100000000;
+ if (value == minInt64) {
+ var digits = new Uint16List(4);
+ digits[3] = 0x8000;
+ return new _BigIntImpl._(true, 4, digits);
+ }
+ value = -value;
+ }
+ if (value < _digitBase) {
+ var digits = new Uint16List(1);
+ digits[0] = value;
+ return new _BigIntImpl._(isNegative, 1, digits);
+ }
+ if (value <= 0xFFFFFFFF) {
+ var digits = new Uint16List(2);
+ digits[0] = value & _digitMask;
+ digits[1] = value >> _digitBits;
+ return new _BigIntImpl._(isNegative, 2, digits);
+ }
+
+ var bits = value.bitLength;
+ var digits = new Uint16List((bits - 1) ~/ _digitBits + 1);
+ var i = 0;
+ while (value != 0) {
+ digits[i++] = value & _digitMask;
+ value = value ~/ _digitBase;
+ }
+ return new _BigIntImpl._(isNegative, digits.length, digits);
+ }
+
+ /// An 8-byte Uint8List we can reuse for [_fromDouble] to avoid generating
+ /// garbage.
+ static final Uint8List _bitsForFromDouble = new Uint8List(8);
+
+ factory _BigIntImpl._fromDouble(double value) {
+ const int exponentBias = 1075;
+
+ if (value.isNaN || value.isInfinite) {
+ throw new ArgumentError("Value must be finite: $value");
+ }
+ bool isNegative = value < 0;
+ if (isNegative) value = -value;
+
+ value = value.floorToDouble();
+ if (value == 0) return zero;
+
+ var bits = _bitsForFromDouble;
+ for (int i = 0; i < 8; i++) {
+ bits[i] = 0;
+ }
+ bits.buffer.asByteData().setFloat64(0, value, Endian.little);
+ // The exponent is in bits 53..63.
+ var biasedExponent = (bits[7] << 4) + (bits[6] >> 4);
+ var exponent = biasedExponent - exponentBias;
+
+ assert(_digitBits == 16);
+ // The significant bits are in 0 .. 52.
+ var unshiftedDigits = new Uint16List(4);
+ unshiftedDigits[0] = (bits[1] << 8) + bits[0];
+ unshiftedDigits[1] = (bits[3] << 8) + bits[2];
+ unshiftedDigits[2] = (bits[5] << 8) + bits[4];
+ // Don't forget to add the hidden bit.
+ unshiftedDigits[3] = 0x10 | (bits[6] & 0xF);
+
+ var unshiftedBig = new _BigIntImpl._normalized(false, 4, unshiftedDigits);
+ _BigIntImpl absResult = unshiftedBig;
+ if (exponent < 0) {
+ absResult = unshiftedBig >> -exponent;
+ } else if (exponent > 0) {
+ absResult = unshiftedBig << exponent;
+ }
+ if (isNegative) return -absResult;
+ return absResult;
+ }
+
+ /// Return the negative value of this integer.
+ ///
+ /// The result of negating an integer always has the opposite sign, except
+ /// for zero, which is its own negation.
+ _BigIntImpl operator -() {
+ if (_used == 0) return this;
+ return new _BigIntImpl._(!_isNegative, _used, _digits);
+ }
+
+ /// Returns the absolute value of this integer.
+ ///
+ /// For any integer `x`, the result is the same as `x < 0 ? -x : x`.
+ _BigIntImpl abs() => _isNegative ? -this : this;
+
+ /// Returns this << n *_DIGIT_BITS.
+ _BigIntImpl _dlShift(int n) {
+ final used = _used;
+ if (used == 0) {
+ return zero;
+ }
+ final resultUsed = used + n;
+ final digits = _digits;
+ final resultDigits = new Uint16List(resultUsed);
+ for (int i = used - 1; i >= 0; i--) {
+ resultDigits[i + n] = digits[i];
+ }
+ return new _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+ }
+
+ /// Same as [_dlShift] but works on the decomposed big integers.
+ ///
+ /// Returns `resultUsed`.
+ ///
+ /// `resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] << n*_DIGIT_BITS`.
+ static int _dlShiftDigits(
+ Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+ if (xUsed == 0) {
+ return 0;
+ }
+ if (n == 0 && identical(resultDigits, xDigits)) {
+ return xUsed;
+ }
+ final resultUsed = xUsed + n;
+ for (int i = xUsed - 1; i >= 0; i--) {
+ resultDigits[i + n] = xDigits[i];
+ }
+ for (int i = n - 1; i >= 0; i--) {
+ resultDigits[i] = 0;
+ }
+ return resultUsed;
+ }
+
+ /// Returns `this >> n*_DIGIT_BITS`.
+ _BigIntImpl _drShift(int n) {
+ final used = _used;
+ if (used == 0) {
+ return zero;
+ }
+ final resultUsed = used - n;
+ if (resultUsed <= 0) {
+ return _isNegative ? _minusOne : zero;
+ }
+ final digits = _digits;
+ final resultDigits = new Uint16List(resultUsed);
+ for (var i = n; i < used; i++) {
+ resultDigits[i - n] = digits[i];
+ }
+ final result = new _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+ if (_isNegative) {
+ // Round down if any bit was shifted out.
+ for (var i = 0; i < n; i++) {
+ if (digits[i] != 0) {
+ return result - one;
+ }
+ }
+ }
+ return result;
+ }
+
+ /// Shifts the digits of [xDigits] into the right place in [resultDigits].
+ ///
+ /// `resultDigits[ds..xUsed+ds] = xDigits[0..xUsed-1] << (n % _DIGIT_BITS)`
+ /// where `ds = n ~/ _DIGIT_BITS`
+ ///
+ /// Does *not* clear digits below ds.
+ static void _lsh(
+ Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+ assert(xUsed > 0);
+ final digitShift = n ~/ _digitBits;
+ final bitShift = n % _digitBits;
+ final carryBitShift = _digitBits - bitShift;
+ final bitMask = (1 << carryBitShift) - 1;
+ var carry = 0;
+ for (int i = xUsed - 1; i >= 0; i--) {
+ final digit = xDigits[i];
+ resultDigits[i + digitShift + 1] = (digit >> carryBitShift) | carry;
+ carry = (digit & bitMask) << bitShift;
+ }
+ resultDigits[digitShift] = carry;
+ }
+
+ /// Shift the bits of this integer to the left by [shiftAmount].
+ ///
+ /// Shifting to the left makes the number larger, effectively multiplying
+ /// the number by `pow(2, shiftIndex)`.
+ ///
+ /// There is no limit on the size of the result. It may be relevant to
+ /// limit intermediate values by using the "and" operator with a suitable
+ /// mask.
+ ///
+ /// It is an error if [shiftAmount] is negative.
+ _BigIntImpl operator <<(int shiftAmount) {
+ if (shiftAmount < 0) {
+ throw new ArgumentError("shift-amount must be posititve $shiftAmount");
+ }
+ if (_isZero) return this;
+ final digitShift = shiftAmount ~/ _digitBits;
+ final bitShift = shiftAmount % _digitBits;
+ if (bitShift == 0) {
+ return _dlShift(digitShift);
+ }
+ var resultUsed = _used + digitShift + 1;
+ var resultDigits = new Uint16List(resultUsed);
+ _lsh(_digits, _used, shiftAmount, resultDigits);
+ return new _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+ }
+
+ // resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] << n.
+ // Returns resultUsed.
+ static int _lShiftDigits(
+ Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+ final digitsShift = n ~/ _digitBits;
+ final bitShift = n % _digitBits;
+ if (bitShift == 0) {
+ return _dlShiftDigits(xDigits, xUsed, digitsShift, resultDigits);
+ }
+ var resultUsed = xUsed + digitsShift + 1;
+ _lsh(xDigits, xUsed, n, resultDigits);
+ var i = digitsShift;
+ while (--i >= 0) {
+ resultDigits[i] = 0;
+ }
+ if (resultDigits[resultUsed - 1] == 0) {
+ resultUsed--; // Clamp result.
+ }
+ return resultUsed;
+ }
+
+ // resultDigits[0..resultUsed-1] = xDigits[0..xUsed-1] >> n.
+ static void _rsh(
+ Uint16List xDigits, int xUsed, int n, Uint16List resultDigits) {
+ assert(xUsed > 0);
+ final digitsShift = n ~/ _digitBits;
+ final bitShift = n % _digitBits;
+ final carryBitShift = _digitBits - bitShift;
+ final bitMask = (1 << bitShift) - 1;
+ var carry = xDigits[digitsShift] >> bitShift;
+ final last = xUsed - digitsShift - 1;
+ for (var i = 0; i < last; i++) {
+ final digit = xDigits[i + digitsShift + 1];
+ resultDigits[i] = ((digit & bitMask) << carryBitShift) | carry;
+ carry = digit >> bitShift;
+ }
+ resultDigits[last] = carry;
+ }
+
+ /// Shift the bits of this integer to the right by [shiftAmount].
+ ///
+ /// Shifting to the right makes the number smaller and drops the least
+ /// significant bits, effectively doing an integer division by
+ /// `pow(2, shiftIndex)`.
+ ///
+ /// It is an error if [shiftAmount] is negative.
+ _BigIntImpl operator >>(int shiftAmount) {
+ if (shiftAmount < 0) {
+ throw new ArgumentError("shift-amount must be posititve $shiftAmount");
+ }
+ if (_isZero) return this;
+ final digitShift = shiftAmount ~/ _digitBits;
+ final bitShift = shiftAmount % _digitBits;
+ if (bitShift == 0) {
+ return _drShift(digitShift);
+ }
+ final used = _used;
+ final resultUsed = used - digitShift;
+ if (resultUsed <= 0) {
+ return _isNegative ? _minusOne : zero;
+ }
+ final digits = _digits;
+ final resultDigits = new Uint16List(resultUsed);
+ _rsh(digits, used, shiftAmount, resultDigits);
+ final result = new _BigIntImpl._(_isNegative, resultUsed, resultDigits);
+ if (_isNegative) {
+ // Round down if any bit was shifted out.
+ if ((digits[digitShift] & ((1 << bitShift) - 1)) != 0) {
+ return result - one;
+ }
+ for (var i = 0; i < digitShift; i++) {
+ if (digits[i] != 0) {
+ return result - one;
+ }
+ }
+ }
+ return result;
+ }
+
+ /// Compares this to [other] taking the absolute value of both operands.
+ ///
+ /// Returns 0 if abs(this) == abs(other); a positive number if
+ /// abs(this) > abs(other); and a negative number if abs(this) < abs(other).
+ int _absCompare(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ return _compareDigits(_digits, _used, other._digits, other._used);
+ }
+
+ /// Compares this to `other`.
+ ///
+ /// Returns a negative number if `this` is less than `other`, zero if they are
+ /// equal, and a positive number if `this` is greater than `other`.
+ int compareTo(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isNegative == other._isNegative) {
+ var result = _absCompare(other);
+ // Use 0 - result to avoid negative zero in JavaScript.
+ return _isNegative ? 0 - result : result;
+ }
+ return _isNegative ? -1 : 1;
+ }
+
+ /// Compares `digits[0..used-1]` with `otherDigits[0..otherUsed-1]`.
+ ///
+ /// Returns 0 if equal; a positive number if larger;
+ /// and a negative number if smaller.
+ static int _compareDigits(
+ Uint16List digits, int used, Uint16List otherDigits, int otherUsed) {
+ var result = used - otherUsed;
+ if (result == 0) {
+ for (int i = used - 1; i >= 0; i--) {
+ result = digits[i] - otherDigits[i];
+ if (result != 0) return result;
+ }
+ }
+ return result;
+ }
+
+ // resultDigits[0..used] = digits[0..used-1] + otherDigits[0..otherUsed-1].
+ // used >= otherUsed > 0.
+ static void _absAdd(Uint16List digits, int used, Uint16List otherDigits,
+ int otherUsed, Uint16List resultDigits) {
+ assert(used >= otherUsed && otherUsed > 0);
+ var carry = 0;
+ for (var i = 0; i < otherUsed; i++) {
+ carry += digits[i] + otherDigits[i];
+ resultDigits[i] = carry & _digitMask;
+ carry >>= _digitBits;
+ }
+ for (var i = otherUsed; i < used; i++) {
+ carry += digits[i];
+ resultDigits[i] = carry & _digitMask;
+ carry >>= _digitBits;
+ }
+ resultDigits[used] = carry;
+ }
+
+ // resultDigits[0..used-1] = digits[0..used-1] - otherDigits[0..otherUsed-1].
+ // used >= otherUsed > 0.
+ static void _absSub(Uint16List digits, int used, Uint16List otherDigits,
+ int otherUsed, Uint16List resultDigits) {
+ assert(used >= otherUsed && otherUsed > 0);
+
+ var carry = 0;
+ for (var i = 0; i < otherUsed; i++) {
+ carry += digits[i] - otherDigits[i];
+ resultDigits[i] = carry & _digitMask;
+ // Dart2js only supports unsigned shifts.
+ // Since the carry can only be -1 or 0 use this hack.
+ carry = 0 - ((carry >> _digitBits) & 1);
+ }
+ for (var i = otherUsed; i < used; i++) {
+ carry += digits[i];
+ resultDigits[i] = carry & _digitMask;
+ // Dart2js only supports unsigned shifts.
+ // Since the carry can only be -1 or 0 use this hack.
+ carry = 0 - ((carry >> _digitBits) & 1);
+ }
+ }
+
+ /// Returns `abs(this) + abs(other)` with sign set according to [isNegative].
+ _BigIntImpl _absAddSetSign(_BigIntImpl other, bool isNegative) {
+ var used = _used;
+ var otherUsed = other._used;
+ if (used < otherUsed) {
+ return other._absAddSetSign(this, isNegative);
+ }
+ if (used == 0) {
+ assert(!isNegative);
+ return zero;
+ }
+ if (otherUsed == 0) {
+ return _isNegative == isNegative ? this : -this;
+ }
+ var resultUsed = used + 1;
+ var resultDigits = new Uint16List(resultUsed);
+ _absAdd(_digits, used, other._digits, otherUsed, resultDigits);
+ return new _BigIntImpl._(isNegative, resultUsed, resultDigits);
+ }
+
+ /// Returns `abs(this) - abs(other)` with sign set according to [isNegative].
+ ///
+ /// Requirement: `abs(this) >= abs(other)`.
+ _BigIntImpl _absSubSetSign(_BigIntImpl other, bool isNegative) {
+ assert(_absCompare(other) >= 0);
+ var used = _used;
+ if (used == 0) {
+ assert(!isNegative);
+ return zero;
+ }
+ var otherUsed = other._used;
+ if (otherUsed == 0) {
+ return _isNegative == isNegative ? this : -this;
+ }
+ var resultDigits = new Uint16List(used);
+ _absSub(_digits, used, other._digits, otherUsed, resultDigits);
+ return new _BigIntImpl._(isNegative, used, resultDigits);
+ }
+
+ /// Returns `abs(this) & abs(other)` with sign set according to [isNegative].
+ _BigIntImpl _absAndSetSign(_BigIntImpl other, bool isNegative) {
+ var resultUsed = _min(_used, other._used);
+ var digits = _digits;
+ var otherDigits = other._digits;
+ var resultDigits = new Uint16List(resultUsed);
+ for (var i = 0; i < resultUsed; i++) {
+ resultDigits[i] = digits[i] & otherDigits[i];
+ }
+ return new _BigIntImpl._(isNegative, resultUsed, resultDigits);
+ }
+
+ /// Returns `abs(this) &~ abs(other)` with sign set according to [isNegative].
+ _BigIntImpl _absAndNotSetSign(_BigIntImpl other, bool isNegative) {
+ var resultUsed = _used;
+ var digits = _digits;
+ var otherDigits = other._digits;
+ var resultDigits = new Uint16List(resultUsed);
+ var m = _min(resultUsed, other._used);
+ for (var i = 0; i < m; i++) {
+ resultDigits[i] = digits[i] & ~otherDigits[i];
+ }
+ for (var i = m; i < resultUsed; i++) {
+ resultDigits[i] = digits[i];
+ }
+ return new _BigIntImpl._(isNegative, resultUsed, resultDigits);
+ }
+
+ /// Returns `abs(this) | abs(other)` with sign set according to [isNegative].
+ _BigIntImpl _absOrSetSign(_BigIntImpl other, bool isNegative) {
+ var used = _used;
+ var otherUsed = other._used;
+ var resultUsed = _max(used, otherUsed);
+ var digits = _digits;
+ var otherDigits = other._digits;
+ var resultDigits = new Uint16List(resultUsed);
+ var l, m;
+ if (used < otherUsed) {
+ l = other;
+ m = used;
+ } else {
+ l = this;
+ m = otherUsed;
+ }
+ for (var i = 0; i < m; i++) {
+ resultDigits[i] = digits[i] | otherDigits[i];
+ }
+ var lDigits = l._digits;
+ for (var i = m; i < resultUsed; i++) {
+ resultDigits[i] = lDigits[i];
+ }
+ return new _BigIntImpl._(isNegative, resultUsed, resultDigits);
+ }
+
+ /// Returns `abs(this) ^ abs(other)` with sign set according to [isNegative].
+ _BigIntImpl _absXorSetSign(_BigIntImpl other, bool isNegative) {
+ var used = _used;
+ var otherUsed = other._used;
+ var resultUsed = _max(used, otherUsed);
+ var digits = _digits;
+ var otherDigits = other._digits;
+ var resultDigits = new Uint16List(resultUsed);
+ var l, m;
+ if (used < otherUsed) {
+ l = other;
+ m = used;
+ } else {
+ l = this;
+ m = otherUsed;
+ }
+ for (var i = 0; i < m; i++) {
+ resultDigits[i] = digits[i] ^ otherDigits[i];
+ }
+ var lDigits = l._digits;
+ for (var i = m; i < resultUsed; i++) {
+ resultDigits[i] = lDigits[i];
+ }
+ return new _BigIntImpl._(isNegative, resultUsed, resultDigits);
+ }
+
+ /// Bit-wise and operator.
+ ///
+ /// Treating both `this` and [other] as sufficiently large two's component
+ /// integers, the result is a number with only the bits set that are set in
+ /// both `this` and [other]
+ ///
+ /// Of both operands are negative, the result is negative, otherwise
+ /// the result is non-negative.
+ _BigIntImpl operator &(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isZero || other._isZero) return zero;
+ if (_isNegative == other._isNegative) {
+ if (_isNegative) {
+ // (-this) & (-other) == ~(this-1) & ~(other-1)
+ // == ~((this-1) | (other-1))
+ // == -(((this-1) | (other-1)) + 1)
+ _BigIntImpl this1 = _absSubSetSign(one, true);
+ _BigIntImpl other1 = other._absSubSetSign(one, true);
+ // Result cannot be zero if this and other are negative.
+ return this1._absOrSetSign(other1, true)._absAddSetSign(one, true);
+ }
+ return _absAndSetSign(other, false);
+ }
+ // _isNegative != other._isNegative
+ var p, n;
+ if (_isNegative) {
+ p = other;
+ n = this;
+ } else {
+ // & is symmetric.
+ p = this;
+ n = other;
+ }
+ // p & (-n) == p & ~(n-1) == p &~ (n-1)
+ var n1 = n._absSubSetSign(one, false);
+ return p._absAndNotSetSign(n1, false);
+ }
+
+ /// Bit-wise or operator.
+ ///
+ /// Treating both `this` and [other] as sufficiently large two's component
+ /// integers, the result is a number with the bits set that are set in either
+ /// of `this` and [other]
+ ///
+ /// If both operands are non-negative, the result is non-negative,
+ /// otherwise the result us negative.
+ _BigIntImpl operator |(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isZero) return other;
+ if (other._isZero) return this;
+ if (_isNegative == other._isNegative) {
+ if (_isNegative) {
+ // (-this) | (-other) == ~(this-1) | ~(other-1)
+ // == ~((this-1) & (other-1))
+ // == -(((this-1) & (other-1)) + 1)
+ var this1 = _absSubSetSign(one, true);
+ var other1 = other._absSubSetSign(one, true);
+ // Result cannot be zero if this and a are negative.
+ return this1._absAndSetSign(other1, true)._absAddSetSign(one, true);
+ }
+ return _absOrSetSign(other, false);
+ }
+ // _neg != a._neg
+ var p, n;
+ if (_isNegative) {
+ p = other;
+ n = this;
+ } else {
+ // | is symmetric.
+ p = this;
+ n = other;
+ }
+ // p | (-n) == p | ~(n-1) == ~((n-1) &~ p) == -(~((n-1) &~ p) + 1)
+ var n1 = n._absSubSetSign(one, true);
+ // Result cannot be zero if only one of this or a is negative.
+ return n1._absAndNotSetSign(p, true)._absAddSetSign(one, true);
+ }
+
+ /// Bit-wise exclusive-or operator.
+ ///
+ /// Treating both `this` and [other] as sufficiently large two's component
+ /// integers, the result is a number with the bits set that are set in one,
+ /// but not both, of `this` and [other]
+ ///
+ /// If the operands have the same sign, the result is non-negative,
+ /// otherwise the result is negative.
+ _BigIntImpl operator ^(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isZero) return other;
+ if (other._isZero) return this;
+ if (_isNegative == other._isNegative) {
+ if (_isNegative) {
+ // (-this) ^ (-other) == ~(this-1) ^ ~(other-1) == (this-1) ^ (other-1)
+ var this1 = _absSubSetSign(one, true);
+ var other1 = other._absSubSetSign(one, true);
+ return this1._absXorSetSign(other1, false);
+ }
+ return _absXorSetSign(other, false);
+ }
+ // _isNegative != a._isNegative
+ var p, n;
+ if (_isNegative) {
+ p = other;
+ n = this;
+ } else {
+ // ^ is symmetric.
+ p = this;
+ n = other;
+ }
+ // p ^ (-n) == p ^ ~(n-1) == ~(p ^ (n-1)) == -((p ^ (n-1)) + 1)
+ var n1 = n._absSubSetSign(one, true);
+ // Result cannot be zero if only one of this or a is negative.
+ return p._absXorSetSign(n1, true)._absAddSetSign(one, true);
+ }
+
+ /// The bit-wise negate operator.
+ ///
+ /// Treating `this` as a sufficiently large two's component integer,
+ /// the result is a number with the opposite bits set.
+ ///
+ /// This maps any integer `x` to `-x - 1`.
+ _BigIntImpl operator ~() {
+ if (_isZero) return _minusOne;
+ if (_isNegative) {
+ // ~(-this) == ~(~(this-1)) == this-1
+ return _absSubSetSign(one, false);
+ }
+ // ~this == -this-1 == -(this+1)
+ // Result cannot be zero if this is positive.
+ return _absAddSetSign(one, true);
+ }
+
+ /// Addition operator.
+ _BigIntImpl operator +(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isZero) return other;
+ if (other._isZero) return this;
+ var isNegative = _isNegative;
+ if (isNegative == other._isNegative) {
+ // this + other == this + other
+ // (-this) + (-other) == -(this + other)
+ return _absAddSetSign(other, isNegative);
+ }
+ // this + (-other) == this - other == -(this - other)
+ // (-this) + other == other - this == -(this - other)
+ if (_absCompare(other) >= 0) {
+ return _absSubSetSign(other, isNegative);
+ }
+ return other._absSubSetSign(this, !isNegative);
+ }
+
+ /// Subtraction operator.
+ _BigIntImpl operator -(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isZero) return -other;
+ if (other._isZero) return this;
+ var isNegative = _isNegative;
+ if (isNegative != other._isNegative) {
+ // this - (-other) == this + other
+ // (-this) - other == -(this + other)
+ return _absAddSetSign(other, isNegative);
+ }
+ // this - other == this - a == -(this - other)
+ // (-this) - (-other) == other - this == -(this - other)
+ if (_absCompare(other) >= 0) {
+ return _absSubSetSign(other, isNegative);
+ }
+ return other._absSubSetSign(this, !isNegative);
+ }
+
+ /// Multiplies [x] with [multiplicandDigits] and adds the result to
+ /// [accumulatorDigits].
+ ///
+ /// The [multiplicandDigits] in the range [i] to [i]+[n]-1 are the
+ /// multiplicand digits.
+ ///
+ /// The [acculumatorDigits] in the range [j] to [j]+[n]-1 are the accumulator
+ /// digits.
+ ///
+ /// Adds the result of the multiplicand-digits * [x] to the accumulator.
+ ///
+ /// Concretely: `accumulatorDigits[j..j+n] += x * m_digits[i..i+n-1]`.
+ static void _mulAdd(int x, Uint16List multiplicandDigits, int i,
+ Uint16List accumulatorDigits, int j, int n) {
+ if (x == 0) {
+ // No-op if x is 0.
+ return;
+ }
+ int c = 0;
+ while (--n >= 0) {
+ int product = x * multiplicandDigits[i++];
+ int combined = product + accumulatorDigits[j] + c;
+ accumulatorDigits[j++] = combined & _digitMask;
+ // Note that this works with 53 bits, as the division will not lose
+ // bits.
+ c = combined ~/ _digitBase;
+ }
+ while (c != 0) {
+ int l = accumulatorDigits[j] + c;
+ accumulatorDigits[j++] = l & _digitMask;
+ c = l ~/ _digitBase;
+ }
+ }
+
+ /// Multiplication operator.
+ _BigIntImpl operator *(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ var used = _used;
+ var otherUsed = other._used;
+ if (used == 0 || otherUsed == 0) {
+ return zero;
+ }
+ var resultUsed = used + otherUsed;
+ var digits = _digits;
+ var otherDigits = other._digits;
+ var resultDigits = new Uint16List(resultUsed);
+ var i = 0;
+ while (i < otherUsed) {
+ _mulAdd(otherDigits[i], digits, 0, resultDigits, i, used);
+ i++;
+ }
+ return new _BigIntImpl._(
+ _isNegative != other._isNegative, resultUsed, resultDigits);
+ }
+
+ // r_digits[0..rUsed-1] = xDigits[0..xUsed-1]*otherDigits[0..otherUsed-1].
+ // Return resultUsed = xUsed + otherUsed.
+ static int _mulDigits(Uint16List xDigits, int xUsed, Uint16List otherDigits,
+ int otherUsed, Uint16List resultDigits) {
+ var resultUsed = xUsed + otherUsed;
+ var i = resultUsed;
+ assert(resultDigits.length >= i);
+ while (--i >= 0) {
+ resultDigits[i] = 0;
+ }
+ i = 0;
+ while (i < otherUsed) {
+ _mulAdd(otherDigits[i], xDigits, 0, resultDigits, i, xUsed);
+ i++;
+ }
+ return resultUsed;
+ }
+
+ /// Returns an estimate of `digits[i-1..i] ~/ topDigitDivisor`.
+ static int _estimateQuotientDigit(
+ int topDigitDivisor, Uint16List digits, int i) {
+ if (digits[i] == topDigitDivisor) return _digitMask;
+ var quotientDigit =
+ (digits[i] << _digitBits | digits[i - 1]) ~/ topDigitDivisor;
+ if (quotientDigit > _digitMask) return _digitMask;
+ return quotientDigit;
+ }
+
+ /// Returns `trunc(this / other)`, with `other != 0`.
+ _BigIntImpl _div(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ assert(other._used > 0);
+ if (_used < other._used) {
+ return zero;
+ }
+ _divRem(other);
+ // Return quotient, i.e.
+ // _lastQuoRem_digits[_lastRem_used.._lastQuoRem_used-1] with proper sign.
+ var lastQuo_used = _lastQuoRemUsed - _lastRemUsed;
+ var quo_digits = _cloneDigits(
+ _lastQuoRemDigits, _lastRemUsed, _lastQuoRemUsed, lastQuo_used);
+ var quo = new _BigIntImpl._(false, lastQuo_used, quo_digits);
+ if ((_isNegative != other._isNegative) && (quo._used > 0)) {
+ quo = -quo;
+ }
+ return quo;
+ }
+
+ /// Returns `this - other * trunc(this / other)`, with `other != 0`.
+ _BigIntImpl _rem(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ assert(other._used > 0);
+ if (_used < other._used) {
+ return this;
+ }
+ _divRem(other);
+ // Return remainder, i.e.
+ // denormalized _lastQuoRem_digits[0.._lastRem_used-1] with proper sign.
+ var remDigits =
+ _cloneDigits(_lastQuoRemDigits, 0, _lastRemUsed, _lastRemUsed);
+ var rem = new _BigIntImpl._(false, _lastRemUsed, remDigits);
+ if (_lastRem_nsh > 0) {
+ rem = rem >> _lastRem_nsh; // Denormalize remainder.
+ }
+ if (_isNegative && (rem._used > 0)) {
+ rem = -rem;
+ }
+ return rem;
+ }
+
+ /// Computes this ~/ other and this.remainder(other).
+ ///
+ /// Stores the result in [_lastQuoRemDigits], [_lastQuoRemUsed] and
+ /// [_lastRemUsed]. The [_lastQuoRemDigits] contains the digits of *both*, the
+ /// quotient and the remainder.
+ ///
+ /// Caches the input to avoid doing the work again when users write
+ /// `a ~/ b` followed by a `a % b`.
+ void _divRem(_BigIntImpl other) {
+ // Check if result is already cached.
+ if ((this._used == _lastDividendUsed) &&
+ (other._used == _lastDivisorUsed) &&
+ identical(this._digits, _lastDividendDigits) &&
+ identical(other._digits, _lastDivisorDigits)) {
+ return;
+ }
+ assert(_used >= other._used);
+
+ var nsh = _digitBits - other._digits[other._used - 1].bitLength;
+ // Concatenated positive quotient and normalized positive remainder.
+ // The resultDigits can have at most one more digit than the dividend.
+ Uint16List resultDigits;
+ int resultUsed;
+ // Normalized positive divisor.
+ // The normalized divisor has the most-significant bit of its most
+ // significant digit set.
+ // This makes estimating the quotient easier.
+ Uint16List yDigits;
+ int yUsed;
+ if (nsh > 0) {
+ yDigits = new Uint16List(other._used + 5);
+ yUsed = _lShiftDigits(other._digits, other._used, nsh, yDigits);
+ resultDigits = new Uint16List(_used + 5);
+ resultUsed = _lShiftDigits(_digits, _used, nsh, resultDigits);
+ } else {
+ yDigits = other._digits;
+ yUsed = other._used;
+ resultDigits = _cloneDigits(_digits, 0, _used, _used + 2);
+ resultUsed = _used;
+ }
+ var topDigitDivisor = yDigits[yUsed - 1];
+ var i = resultUsed;
+ var j = i - yUsed;
+ // tmpDigits is a temporary array of i (resultUsed) digits.
+ var tmpDigits = new Uint16List(i);
+ var tmpUsed = _dlShiftDigits(yDigits, yUsed, j, tmpDigits);
+ // Explicit first division step in case normalized dividend is larger or
+ // equal to shifted normalized divisor.
+ if (_compareDigits(resultDigits, resultUsed, tmpDigits, tmpUsed) >= 0) {
+ assert(i == resultUsed);
+ resultDigits[resultUsed++] = 1; // Quotient = 1.
+ // Subtract divisor from remainder.
+ _absSub(resultDigits, resultUsed, tmpDigits, tmpUsed, resultDigits);
+ } else {
+ // Account for possible carry in _mulAdd step.
+ resultDigits[resultUsed++] = 0;
+ }
+
+ // Negate y so we can later use _mulAdd instead of non-existent _mulSub.
+ var nyDigits = new Uint16List(yUsed + 2);
+ nyDigits[yUsed] = 1;
+ _absSub(nyDigits, yUsed + 1, yDigits, yUsed, nyDigits);
+ // nyDigits is read-only and has yUsed digits (possibly including several
+ // leading zeros).
+ // resultDigits is modified during iteration.
+ // resultDigits[0..yUsed-1] is the current remainder.
+ // resultDigits[yUsed..resultUsed-1] is the current quotient.
+ --i;
+
+ while (j > 0) {
+ var estimatedQuotientDigit =
+ _estimateQuotientDigit(topDigitDivisor, resultDigits, i);
+ j--;
+ _mulAdd(estimatedQuotientDigit, nyDigits, 0, resultDigits, j, yUsed);
+ if (resultDigits[i] < estimatedQuotientDigit) {
+ // Reusing the already existing tmpDigits array.
+ var tmpUsed = _dlShiftDigits(nyDigits, yUsed, j, tmpDigits);
+ _absSub(resultDigits, resultUsed, tmpDigits, tmpUsed, resultDigits);
+ while (resultDigits[i] < --estimatedQuotientDigit) {
+ _absSub(resultDigits, resultUsed, tmpDigits, tmpUsed, resultDigits);
+ }
+ }
+ i--;
+ }
+ // Cache result.
+ _lastDividendDigits = _digits;
+ _lastDividendUsed = _used;
+ _lastDivisorDigits = other._digits;
+ _lastDivisorUsed = other._used;
+ _lastQuoRemDigits = resultDigits;
+ _lastQuoRemUsed = resultUsed;
+ _lastRemUsed = yUsed;
+ _lastRem_nsh = nsh;
+ }
+
+ int get hashCode {
+ // This is the [Jenkins hash function][1] but using masking to keep
+ // values in SMI range.
+ //
+ // [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+
+ int combine(int hash, int value) {
+ hash = 0x1fffffff & (hash + value);
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+ return hash ^ (hash >> 6);
+ }
+
+ int finish(int hash) {
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+ hash = hash ^ (hash >> 11);
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+ }
+
+ if (_isZero) return 6707; // Just a random number.
+ var hash = _isNegative ? 83585 : 429689; // Also random.
+ for (int i = 0; i < _used; i++) {
+ hash = combine(hash, _digits[i]);
+ }
+ return finish(hash);
+ }
+
+ /// Test whether this value is numerically equal to `other`.
+ ///
+ /// If [other] is a [_BigIntImpl] returns whether the two operands have the
+ /// same value.
+ ///
+ /// Returns false if `other` is not a [_BigIntImpl].
+ bool operator ==(Object other) =>
+ other is _BigIntImpl && compareTo(other) == 0;
+
+ /// Returns the minimum number of bits required to store this big integer.
+ ///
+ /// The number of bits excludes the sign bit, which gives the natural length
+ /// for non-negative (unsigned) values. Negative values are complemented to
+ /// return the bit position of the first bit that differs from the sign bit.
+ ///
+ /// To find the number of bits needed to store the value as a signed value,
+ /// add one, i.e. use `x.bitLength + 1`.
+ ///
+ /// ```
+ /// x.bitLength == (-x-1).bitLength
+ ///
+ /// new BigInt.from(3).bitLength == 2; // 00000011
+ /// new BigInt.from(2).bitLength == 2; // 00000010
+ /// new BigInt.from(1).bitLength == 1; // 00000001
+ /// new BigInt.from(0).bitLength == 0; // 00000000
+ /// new BigInt.from(-1).bitLength == 0; // 11111111
+ /// new BigInt.from(-2).bitLength == 1; // 11111110
+ /// new BigInt.from(-3).bitLength == 2; // 11111101
+ /// new BigInt.from(-4).bitLength == 2; // 11111100
+ /// ```
+ int get bitLength {
+ if (_used == 0) return 0;
+ if (_isNegative) return (~this).bitLength;
+ return _digitBits * (_used - 1) + _digits[_used - 1].bitLength;
+ }
+
+ /// Truncating division operator.
+ ///
+ /// Performs a truncating integer division, where the remainder is discarded.
+ ///
+ /// The remainder can be computed using the [remainder] method.
+ ///
+ /// Examples:
+ /// ```
+ /// var seven = new BigInt.from(7);
+ /// var three = new BigInt.from(3);
+ /// seven ~/ three; // => 2
+ /// (-seven) ~/ three; // => -2
+ /// seven ~/ -three; // => -2
+ /// seven.remainder(three); // => 1
+ /// (-seven).remainder(three); // => -1
+ /// seven.remainder(-three); // => 1
+ /// ```
+ _BigIntImpl operator ~/(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (other._used == 0) {
+ throw const IntegerDivisionByZeroException();
+ }
+ return _div(other);
+ }
+
+ /// Returns the remainder of the truncating division of `this` by [other].
+ ///
+ /// The result `r` of this operation satisfies:
+ /// `this == (this ~/ other) * other + r`.
+ /// As a consequence the remainder `r` has the same sign as the divider
+ /// `this`.
+ _BigIntImpl remainder(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (other._used == 0) {
+ throw const IntegerDivisionByZeroException();
+ }
+ return _rem(other);
+ }
+
+ /// Division operator.
+ double operator /(BigInt other) => this.toDouble() / other.toDouble();
+
+ /// Relational less than operator.
+ bool operator <(BigInt other) => compareTo(other) < 0;
+
+ /// Relational less than or equal operator.
+ bool operator <=(BigInt other) => compareTo(other) <= 0;
+
+ /// Relational greater than operator.
+ bool operator >(BigInt other) => compareTo(other) > 0;
+
+ /// Relational greater than or equal operator.
+ bool operator >=(BigInt other) => compareTo(other) >= 0;
+
+ /// Euclidean modulo operator.
+ ///
+ /// Returns the remainder of the Euclidean division. The Euclidean division of
+ /// two integers `a` and `b` yields two integers `q` and `r` such that
+ /// `a == b * q + r` and `0 <= r < b.abs()`.
+ ///
+ /// The sign of the returned value `r` is always positive.
+ ///
+ /// See [remainder] for the remainder of the truncating division.
+ _BigIntImpl operator %(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (other._used == 0) {
+ throw const IntegerDivisionByZeroException();
+ }
+ var result = _rem(other);
+ if (result._isNegative) {
+ if (other._isNegative) {
+ result = result - other;
+ } else {
+ result = result + other;
+ }
+ }
+ return result;
+ }
+
+ /// Returns the sign of this big integer.
+ ///
+ /// Returns 0 for zero, -1 for values less than zero and
+ /// +1 for values greater than zero.
+ int get sign {
+ if (_used == 0) return 0;
+ return _isNegative ? -1 : 1;
+ }
+
+ /// Whether this big integer is even.
+ bool get isEven => _used == 0 || (_digits[0] & 1) == 0;
+
+ /// Whether this big integer is odd.
+ bool get isOdd => !isEven;
+
+ /// Whether this number is negative.
+ bool get isNegative => _isNegative;
+
+ _BigIntImpl pow(int exponent) {
+ if (exponent < 0) {
+ throw new ArgumentError("Exponent must not be negative: $exponent");
+ }
+ if (exponent == 0) return one;
+
+ // Exponentiation by squaring.
+ var result = one;
+ var base = this;
+ while (exponent != 0) {
+ if ((exponent & 1) == 1) {
+ result *= base;
+ }
+ exponent >>= 1;
+ // Skip unnecessary operation.
+ if (exponent != 0) {
+ base *= base;
+ }
+ }
+ return result;
+ }
+
+ /// Returns this integer to the power of [exponent] modulo [modulus].
+ ///
+ /// The [exponent] must be non-negative and [modulus] must be
+ /// positive.
+ _BigIntImpl modPow(BigInt bigExponent, BigInt bigModulus) {
+ _BigIntImpl exponent = bigExponent;
+ _BigIntImpl modulus = bigModulus;
+ if (exponent._isNegative) {
+ throw new ArgumentError("exponent must be positive: $exponent");
+ }
+ if (modulus <= zero) {
+ throw new ArgumentError("modulus must be strictly positive: $modulus");
+ }
+ if (exponent._isZero) return one;
+
+ final modulusUsed = modulus._used;
+ final modulusUsed2p4 = 2 * modulusUsed + 4;
+ final exponentBitlen = exponent.bitLength;
+ if (exponentBitlen <= 0) return one;
+ _BigIntReduction z = new _BigIntClassic(modulus);
+ var resultDigits = new Uint16List(modulusUsed2p4);
+ var result2Digits = new Uint16List(modulusUsed2p4);
+ var gDigits = new Uint16List(modulusUsed);
+ var gUsed = z.convert(this, gDigits);
+ // Initialize result with g.
+ // Copy leading zero if any.
+ for (int j = gUsed - 1; j >= 0; j--) {
+ resultDigits[j] = gDigits[j];
+ }
+ var resultUsed = gUsed;
+ var result2Used;
+ for (int i = exponentBitlen - 2; i >= 0; i--) {
+ result2Used = z.sqr(resultDigits, resultUsed, result2Digits);
+ if (!(exponent & (one << i))._isZero) {
+ resultUsed =
+ z.mul(result2Digits, result2Used, gDigits, gUsed, resultDigits);
+ } else {
+ // Swap result and result2.
+ var tmpDigits = resultDigits;
+ var tmpUsed = resultUsed;
+ resultDigits = result2Digits;
+ resultUsed = result2Used;
+ result2Digits = tmpDigits;
+ result2Used = tmpUsed;
+ }
+ }
+ return z.revert(resultDigits, resultUsed);
+ }
+
+ // If inv is false, returns gcd(x, y).
+ // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
+ // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
+ static _BigIntImpl _binaryGcd(_BigIntImpl x, _BigIntImpl y, bool inv) {
+ var xDigits = x._digits;
+ var yDigits = y._digits;
+ var xUsed = x._used;
+ var yUsed = y._used;
+ var maxUsed = xUsed > yUsed ? xUsed : yUsed;
+ var unshiftedMaxUsed = maxUsed; // Keep
+ xDigits = _cloneDigits(xDigits, 0, xUsed, maxUsed);
+ yDigits = _cloneDigits(yDigits, 0, yUsed, maxUsed);
+ int shiftAmount = 0;
+ if (inv) {
+ if ((yUsed == 1) && (yDigits[0] == 1)) return one;
+ if ((yUsed == 0) || (yDigits[0].isEven && xDigits[0].isEven)) {
+ throw new Exception("Not coprime");
+ }
+ } else {
+ if (x._isZero) {
+ throw new ArgumentError.value(0, "this", "must not be zero");
+ }
+ if (y._isZero) {
+ throw new ArgumentError.value(0, "other", "must not be zero");
+ }
+ if (((xUsed == 1) && (xDigits[0] == 1)) ||
+ ((yUsed == 1) && (yDigits[0] == 1))) return one;
+ while (((xDigits[0] & 1) == 0) && ((yDigits[0] & 1) == 0)) {
+ _rsh(xDigits, xUsed, 1, xDigits);
+ _rsh(yDigits, yUsed, 1, yDigits);
+ shiftAmount++;
+ }
+ if (shiftAmount >= _digitBits) {
+ var digitShiftAmount = shiftAmount ~/ _digitBits;
+ xUsed -= digitShiftAmount;
+ yUsed -= digitShiftAmount;
+ maxUsed -= digitShiftAmount;
+ }
+ if ((yDigits[0] & 1) == 1) {
+ // Swap x and y.
+ var tmpDigits = xDigits;
+ var tmpUsed = xUsed;
+ xDigits = yDigits;
+ xUsed = yUsed;
+ yDigits = tmpDigits;
+ yUsed = tmpUsed;
+ }
+ }
+ var uDigits = _cloneDigits(xDigits, 0, xUsed, unshiftedMaxUsed);
+ var vDigits =
+ _cloneDigits(yDigits, 0, yUsed, unshiftedMaxUsed + 2); // +2 for lsh.
+ final bool ac = (xDigits[0] & 1) == 0;
+
+ // Variables a, b, c, and d require one more digit.
+ final abcdUsed = maxUsed + 1;
+ final abcdLen = abcdUsed + 2; // +2 to satisfy _absAdd.
+ var aDigits, bDigits, cDigits, dDigits;
+ bool aIsNegative, bIsNegative, cIsNegative, dIsNegative;
+ if (ac) {
+ aDigits = new Uint16List(abcdLen);
+ aIsNegative = false;
+ aDigits[0] = 1;
+ cDigits = new Uint16List(abcdLen);
+ cIsNegative = false;
+ }
+ bDigits = new Uint16List(abcdLen);
+ bIsNegative = false;
+ dDigits = new Uint16List(abcdLen);
+ dIsNegative = false;
+ dDigits[0] = 1;
+
+ while (true) {
+ while ((uDigits[0] & 1) == 0) {
+ _rsh(uDigits, maxUsed, 1, uDigits);
+ if (ac) {
+ if (((aDigits[0] & 1) == 1) || ((bDigits[0] & 1) == 1)) {
+ // a += y
+ if (aIsNegative) {
+ if ((aDigits[maxUsed] != 0) ||
+ (_compareDigits(aDigits, maxUsed, yDigits, maxUsed)) > 0) {
+ _absSub(aDigits, abcdUsed, yDigits, maxUsed, aDigits);
+ } else {
+ _absSub(yDigits, maxUsed, aDigits, maxUsed, aDigits);
+ aIsNegative = false;
+ }
+ } else {
+ _absAdd(aDigits, abcdUsed, yDigits, maxUsed, aDigits);
+ }
+ // b -= x
+ if (bIsNegative) {
+ _absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+ } else if ((bDigits[maxUsed] != 0) ||
+ (_compareDigits(bDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ _absSub(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+ } else {
+ _absSub(xDigits, maxUsed, bDigits, maxUsed, bDigits);
+ bIsNegative = true;
+ }
+ }
+ _rsh(aDigits, abcdUsed, 1, aDigits);
+ } else if ((bDigits[0] & 1) == 1) {
+ // b -= x
+ if (bIsNegative) {
+ _absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+ } else if ((bDigits[maxUsed] != 0) ||
+ (_compareDigits(bDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ _absSub(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
+ } else {
+ _absSub(xDigits, maxUsed, bDigits, maxUsed, bDigits);
+ bIsNegative = true;
+ }
+ }
+ _rsh(bDigits, abcdUsed, 1, bDigits);
+ }
+ while ((vDigits[0] & 1) == 0) {
+ _rsh(vDigits, maxUsed, 1, vDigits);
+ if (ac) {
+ if (((cDigits[0] & 1) == 1) || ((dDigits[0] & 1) == 1)) {
+ // c += y
+ if (cIsNegative) {
+ if ((cDigits[maxUsed] != 0) ||
+ (_compareDigits(cDigits, maxUsed, yDigits, maxUsed) > 0)) {
+ _absSub(cDigits, abcdUsed, yDigits, maxUsed, cDigits);
+ } else {
+ _absSub(yDigits, maxUsed, cDigits, maxUsed, cDigits);
+ cIsNegative = false;
+ }
+ } else {
+ _absAdd(cDigits, abcdUsed, yDigits, maxUsed, cDigits);
+ }
+ // d -= x
+ if (dIsNegative) {
+ _absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+ } else if ((dDigits[maxUsed] != 0) ||
+ (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+ } else {
+ _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+ dIsNegative = true;
+ }
+ }
+ _rsh(cDigits, abcdUsed, 1, cDigits);
+ } else if ((dDigits[0] & 1) == 1) {
+ // d -= x
+ if (dIsNegative) {
+ _absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+ } else if ((dDigits[maxUsed] != 0) ||
+ (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+ } else {
+ _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+ dIsNegative = true;
+ }
+ }
+ _rsh(dDigits, abcdUsed, 1, dDigits);
+ }
+ if (_compareDigits(uDigits, maxUsed, vDigits, maxUsed) >= 0) {
+ // u -= v
+ _absSub(uDigits, maxUsed, vDigits, maxUsed, uDigits);
+ if (ac) {
+ // a -= c
+ if (aIsNegative == cIsNegative) {
+ var a_cmp_c = _compareDigits(aDigits, abcdUsed, cDigits, abcdUsed);
+ if (a_cmp_c > 0) {
+ _absSub(aDigits, abcdUsed, cDigits, abcdUsed, aDigits);
+ } else {
+ _absSub(cDigits, abcdUsed, aDigits, abcdUsed, aDigits);
+ aIsNegative = !aIsNegative && (a_cmp_c != 0);
+ }
+ } else {
+ _absAdd(aDigits, abcdUsed, cDigits, abcdUsed, aDigits);
+ }
+ }
+ // b -= d
+ if (bIsNegative == dIsNegative) {
+ var b_cmp_d = _compareDigits(bDigits, abcdUsed, dDigits, abcdUsed);
+ if (b_cmp_d > 0) {
+ _absSub(bDigits, abcdUsed, dDigits, abcdUsed, bDigits);
+ } else {
+ _absSub(dDigits, abcdUsed, bDigits, abcdUsed, bDigits);
+ bIsNegative = !bIsNegative && (b_cmp_d != 0);
+ }
+ } else {
+ _absAdd(bDigits, abcdUsed, dDigits, abcdUsed, bDigits);
+ }
+ } else {
+ // v -= u
+ _absSub(vDigits, maxUsed, uDigits, maxUsed, vDigits);
+ if (ac) {
+ // c -= a
+ if (cIsNegative == aIsNegative) {
+ var c_cmp_a = _compareDigits(cDigits, abcdUsed, aDigits, abcdUsed);
+ if (c_cmp_a > 0) {
+ _absSub(cDigits, abcdUsed, aDigits, abcdUsed, cDigits);
+ } else {
+ _absSub(aDigits, abcdUsed, cDigits, abcdUsed, cDigits);
+ cIsNegative = !cIsNegative && (c_cmp_a != 0);
+ }
+ } else {
+ _absAdd(cDigits, abcdUsed, aDigits, abcdUsed, cDigits);
+ }
+ }
+ // d -= b
+ if (dIsNegative == bIsNegative) {
+ var d_cmp_b = _compareDigits(dDigits, abcdUsed, bDigits, abcdUsed);
+ if (d_cmp_b > 0) {
+ _absSub(dDigits, abcdUsed, bDigits, abcdUsed, dDigits);
+ } else {
+ _absSub(bDigits, abcdUsed, dDigits, abcdUsed, dDigits);
+ dIsNegative = !dIsNegative && (d_cmp_b != 0);
+ }
+ } else {
+ _absAdd(dDigits, abcdUsed, bDigits, abcdUsed, dDigits);
+ }
+ }
+ // Exit loop if u == 0.
+ var i = maxUsed;
+ while ((i > 0) && (uDigits[i - 1] == 0)) --i;
+ if (i == 0) break;
+ }
+ if (!inv) {
+ if (shiftAmount > 0) {
+ maxUsed = _lShiftDigits(vDigits, maxUsed, shiftAmount, vDigits);
+ }
+ return new _BigIntImpl._(false, maxUsed, vDigits);
+ }
+ // No inverse if v != 1.
+ var i = maxUsed - 1;
+ while ((i > 0) && (vDigits[i] == 0)) --i;
+ if ((i != 0) || (vDigits[0] != 1)) {
+ throw new Exception("Not coprime");
+ }
+
+ if (dIsNegative) {
+ while ((dDigits[maxUsed] != 0) ||
+ (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ // d += x, d still negative
+ _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+ }
+ // d += x
+ _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+ dIsNegative = false;
+ } else {
+ while ((dDigits[maxUsed] != 0) ||
+ (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) >= 0)) {
+ // d -= x
+ _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
+ }
+ }
+ return new _BigIntImpl._(false, maxUsed, dDigits);
+ }
+
+ /// Returns the modular multiplicative inverse of this big integer
+ /// modulo [modulus].
+ ///
+ /// The [modulus] must be positive.
+ ///
+ /// It is an error if no modular inverse exists.
+ // Returns 1/this % modulus, with modulus > 0.
+ _BigIntImpl modInverse(BigInt bigInt) {
+ _BigIntImpl modulus = bigInt;
+ if (modulus <= zero) {
+ throw new ArgumentError("Modulus must be strictly positive: $modulus");
+ }
+ if (modulus == one) return zero;
+ var tmp = this;
+ if (tmp._isNegative || (tmp._absCompare(modulus) >= 0)) {
+ tmp %= modulus;
+ }
+ return _binaryGcd(modulus, tmp, true);
+ }
+
+ /// Returns the greatest common divisor of this big integer and [other].
+ ///
+ /// If either number is non-zero, the result is the numerically greatest
+ /// integer dividing both `this` and `other`.
+ ///
+ /// The greatest common divisor is independent of the order,
+ /// so `x.gcd(y)` is always the same as `y.gcd(x)`.
+ ///
+ /// For any integer `x`, `x.gcd(x)` is `x.abs()`.
+ ///
+ /// If both `this` and `other` is zero, the result is also zero.
+ _BigIntImpl gcd(BigInt bigInt) {
+ _BigIntImpl other = bigInt;
+ if (_isZero) return other.abs();
+ if (other._isZero) return this.abs();
+ return _binaryGcd(this, other, false);
+ }
+
+ /// Returns the least significant [width] bits of this big integer as a
+ /// non-negative number (i.e. unsigned representation). The returned value
+ /// has zeros in all bit positions higher than [width].
+ ///
+ /// ```
+ /// new BigInt.from(-1).toUnsigned(5) == 31 // 11111111 -> 00011111
+ /// ```
+ ///
+ /// This operation can be used to simulate arithmetic from low level
+ /// languages. For example, to increment an 8 bit quantity:
+ ///
+ /// ```
+ /// q = (q + 1).toUnsigned(8);
+ /// ```
+ ///
+ /// `q` will count from `0` up to `255` and then wrap around to `0`.
+ ///
+ /// If the input fits in [width] bits without truncation, the result is the
+ /// same as the input. The minimum width needed to avoid truncation of `x` is
+ /// given by `x.bitLength`, i.e.
+ ///
+ /// ```
+ /// x == x.toUnsigned(x.bitLength);
+ /// ```
+ _BigIntImpl toUnsigned(int width) {
+ return this & ((one << width) - one);
+ }
+
+ /// Returns the least significant [width] bits of this integer, extending the
+ /// highest retained bit to the sign. This is the same as truncating the
+ /// value to fit in [width] bits using an signed 2-s complement
+ /// representation. The returned value has the same bit value in all
+ /// positions higher than [width].
+ ///
+ /// ```
+ /// var big15 = new BigInt.from(15);
+ /// var big16 = new BigInt.from(16);
+ /// var big239 = new BigInt.from(239);
+ /// V--sign bit-V
+ /// big16.toSigned(5) == -big16 // 00010000 -> 11110000
+ /// big239.toSigned(5) == big15 // 11101111 -> 00001111
+ /// ^ ^
+ /// ```
+ ///
+ /// This operation can be used to simulate arithmetic from low level
+ /// languages. For example, to increment an 8 bit signed quantity:
+ ///
+ /// ```
+ /// q = (q + 1).toSigned(8);
+ /// ```
+ ///
+ /// `q` will count from `0` up to `127`, wrap to `-128` and count back up to
+ /// `127`.
+ ///
+ /// If the input value fits in [width] bits without truncation, the result is
+ /// the same as the input. The minimum width needed to avoid truncation of
+ /// `x` is `x.bitLength + 1`, i.e.
+ ///
+ /// ```
+ /// x == x.toSigned(x.bitLength + 1);
+ /// ```
+ _BigIntImpl toSigned(int width) {
+ // The value of binary number weights each bit by a power of two. The
+ // twos-complement value weights the sign bit negatively. We compute the
+ // value of the negative weighting by isolating the sign bit with the
+ // correct power of two weighting and subtracting it from the value of the
+ // lower bits.
+ var signMask = one << (width - 1);
+ return (this & (signMask - one)) - (this & signMask);
+ }
+
+ // Maximum number of digits that always fit in mantissa.
+ static const _simpleValidIntDigits = 53 ~/ _digitBits;
+
+ bool get isValidInt {
+ if (_used <= _simpleValidIntDigits) return true;
+ var asInt = toInt();
+ if (!asInt.toDouble().isFinite) return false;
+ return this == new _BigIntImpl._fromInt(asInt);
+ }
+
+ int toInt() {
+ var result = 0;
+ for (int i = _used - 1; i >= 0; i--) {
+ result = result * _digitBase + _digits[i];
+ }
+ return _isNegative ? -result : result;
+ }
+
+ /// Returns this [_BigIntImpl] as a [double].
+ ///
+ /// If the number is not representable as a [double], an
+ /// approximation is returned. For numerically large integers, the
+ /// approximation may be infinite.
+ double toDouble() {
+ const int exponentBias = 1075;
+ // There are 11 bits for the exponent.
+ // 2047 (all bits set to 1) is reserved for infinity and NaN.
+ // When storing the exponent in the 11 bits, it is biased by exponentBias
+ // to support negative exponents.
+ const int maxDoubleExponent = 2046 - exponentBias;
+ if (_isZero) return 0.0;
+
+ // We fill the 53 bits little-endian.
+ var resultBits = new Uint8List(8);
+
+ var length = _digitBits * (_used - 1) + _digits[_used - 1].bitLength;
+ if (length > maxDoubleExponent + 53) {
+ return _isNegative ? double.negativeInfinity : double.infinity;
+ }
+
+ // The most significant bit is for the sign.
+ if (_isNegative) resultBits[7] = 0x80;
+
+ // Write the exponent into bits 1..12:
+ var biasedExponent = length - 53 + exponentBias;
+ resultBits[6] = (biasedExponent & 0xF) << 4;
+ resultBits[7] |= biasedExponent >> 4;
+
+ int cachedBits = 0;
+ int cachedBitsLength = 0;
+ int digitIndex = _used - 1;
+ int readBits(int n) {
+ // Ensure that we have enough bits in [cachedBits].
+ while (cachedBitsLength < n) {
+ int nextDigit;
+ int nextDigitLength = _digitBits; // May get updated.
+ if (digitIndex < 0) {
+ nextDigit = 0;
+ digitIndex--;
+ } else {
+ nextDigit = _digits[digitIndex];
+ if (digitIndex == _used - 1) nextDigitLength = nextDigit.bitLength;
+ digitIndex--;
+ }
+ cachedBits = (cachedBits << nextDigitLength) + nextDigit;
+ cachedBitsLength += nextDigitLength;
+ }
+ // Read the top [n] bits.
+ var result = cachedBits >> (cachedBitsLength - n);
+ // Remove the bits from the cache.
+ cachedBits -= result << (cachedBitsLength - n);
+ cachedBitsLength -= n;
+ return result;
+ }
+
+ // The first leading 1 bit is implicit in the double-representation and can
+ // be discarded.
+ var leadingBits = readBits(5) & 0xF;
+ resultBits[6] |= leadingBits;
+
+ for (int i = 5; i >= 0; i--) {
+ // Get the remaining 48 bits.
+ resultBits[i] = readBits(8);
+ }
+
+ void roundUp() {
+ // Simply consists of adding 1 to the whole 64 bit "number".
+ // It will update the exponent, if necessary.
+ // It might even round up to infinity (which is what we want).
+ var carry = 1;
+ for (int i = 0; i < 8; i++) {
+ if (carry == 0) break;
+ var sum = resultBits[i] + carry;
+ resultBits[i] = sum & 0xFF;
+ carry = sum >> 8;
+ }
+ }
+
+ if (readBits(1) == 1) {
+ if (resultBits[0].isOdd) {
+ // Rounds to even all the time.
+ roundUp();
+ } else {
+ // Round up, if there is at least one other digit that is not 0.
+ if (cachedBits != 0) {
+ // There is already one in the cachedBits.
+ roundUp();
+ } else {
+ for (int i = digitIndex; digitIndex >= 0; i--) {
+ if (_digits[i] != 0) {
+ roundUp();
+ break;
+ }
+ }
+ }
+ }
+ }
+ return resultBits.buffer.asByteData().getFloat64(0, Endian.little);
+ }
+
+ /// Returns a String-representation of this integer.
+ ///
+ /// The returned string is parsable by [parse].
+ /// For any `_BigIntImpl` `i`, it is guaranteed that
+ /// `i == _BigIntImpl.parse(i.toString())`.
+ String toString() {
+ if (_used == 0) return "0";
+ if (_used == 1) {
+ if (_isNegative) return (-_digits[0]).toString();
+ return _digits[0].toString();
+ }
+
+ // Generate in chunks of 4 digits.
+ // The chunks are in reversed order.
+ var decimalDigitChunks = <String>[];
+ var rest = isNegative ? -this : this;
+ while (rest._used > 1) {
+ var digits4 = rest.remainder(_bigInt10000).toString();
+ decimalDigitChunks.add(digits4);
+ if (digits4.length == 1) decimalDigitChunks.add("000");
+ if (digits4.length == 2) decimalDigitChunks.add("00");
+ if (digits4.length == 3) decimalDigitChunks.add("0");
+ rest = rest ~/ _bigInt10000;
+ }
+ decimalDigitChunks.add(rest._digits[0].toString());
+ if (_isNegative) decimalDigitChunks.add("-");
+ return decimalDigitChunks.reversed.join();
+ }
+
+ int _toRadixCodeUnit(int digit) {
+ const int _0 = 48;
+ const int _a = 97;
+ if (digit < 10) return _0 + digit;
+ return _a + digit - 10;
+ }
+
+ /// Converts [this] to a string representation in the given [radix].
+ ///
+ /// In the string representation, lower-case letters are used for digits above
+ /// '9', with 'a' being 10 an 'z' being 35.
+ ///
+ /// The [radix] argument must be an integer in the range 2 to 36.
+ String toRadixString(int radix) {
+ if (radix > 36) throw new RangeError.range(radix, 2, 36);
+
+ if (_used == 0) return "0";
+
+ if (_used == 1) {
+ var digitString = _digits[0].toRadixString(radix);
+ if (_isNegative) return "-" + digitString;
+ return digitString;
+ }
+
+ if (radix == 16) return _toHexString();
+
+ var base = new _BigIntImpl._fromInt(radix);
+ var reversedDigitCodeUnits = <int>[];
+ var rest = this.abs();
+ while (!rest._isZero) {
+ var digit = rest.remainder(base).toInt();
+ rest = rest ~/ base;
+ reversedDigitCodeUnits.add(_toRadixCodeUnit(digit));
+ }
+ var digitString = new String.fromCharCodes(reversedDigitCodeUnits.reversed);
+ if (_isNegative) return "-" + digitString;
+ return digitString;
+ }
+
+ String _toHexString() {
+ var chars = <int>[];
+ for (int i = 0; i < _used - 1; i++) {
+ int chunk = _digits[i];
+ for (int j = 0; j < (_digitBits ~/ 4); j++) {
+ chars.add(_toRadixCodeUnit(chunk & 0xF));
+ chunk >>= 4;
+ }
+ }
+ var msbChunk = _digits[_used - 1];
+ while (msbChunk != 0) {
+ chars.add(_toRadixCodeUnit(msbChunk & 0xF));
+ msbChunk >>= 4;
+ }
+ if (_isNegative) {
+ const _dash = 45;
+ chars.add(_dash);
+ }
+ return new String.fromCharCodes(chars.reversed);
+ }
+}
+
+// Interface for modular reduction.
+abstract class _BigIntReduction {
+ // Return the number of digits used by r_digits.
+ int convert(_BigIntImpl x, Uint16List r_digits);
+ int mul(Uint16List xDigits, int xUsed, Uint16List yDigits, int yUsed,
+ Uint16List resultDigits);
+ int sqr(Uint16List xDigits, int xUsed, Uint16List resultDigits);
+
+ // Return x reverted to _BigIntImpl.
+ _BigIntImpl revert(Uint16List xDigits, int xUsed);
+}
+
+// Modular reduction using "classic" algorithm.
+class _BigIntClassic implements _BigIntReduction {
+ final _BigIntImpl _modulus; // Modulus.
+ final _BigIntImpl _normalizedModulus; // Normalized _modulus.
+
+ _BigIntClassic(this._modulus)
+ : _normalizedModulus = _modulus <<
+ (_BigIntImpl._digitBits -
+ _modulus._digits[_modulus._used - 1].bitLength);
+
+ int convert(_BigIntImpl x, Uint16List resultDigits) {
+ var digits;
+ var used;
+ if (x._isNegative || x._absCompare(_modulus) >= 0) {
+ var remainder = x._rem(_modulus);
+ if (x._isNegative && remainder._used > 0) {
+ assert(remainder._isNegative);
+ remainder += _modulus;
+ }
+ assert(!remainder._isNegative);
+ used = remainder._used;
+ digits = remainder._digits;
+ } else {
+ used = x._used;
+ digits = x._digits;
+ }
+ var i = used; // Copy leading zero if any.
+ while (--i >= 0) {
+ resultDigits[i] = digits[i];
+ }
+ return used;
+ }
+
+ _BigIntImpl revert(Uint16List xDigits, int xUsed) {
+ return new _BigIntImpl._(false, xUsed, xDigits);
+ }
+
+ int _reduce(Uint16List xDigits, int xUsed) {
+ if (xUsed < _modulus._used) {
+ return xUsed;
+ }
+ var reverted = revert(xDigits, xUsed);
+ var rem = reverted._rem(_normalizedModulus);
+ return convert(rem, xDigits);
+ }
+
+ int sqr(Uint16List xDigits, int xUsed, Uint16List resultDigits) {
+ var b = new _BigIntImpl._(false, xUsed, xDigits);
+ var b2 = b * b;
+ for (int i = 0; i < b2._used; i++) {
+ resultDigits[i] = b2._digits[i];
+ }
+ for (int i = b2._used; i < 2 * xUsed; i++) {
+ resultDigits[i] = 0;
+ }
+ return _reduce(resultDigits, 2 * xUsed);
+ }
+
+ int mul(Uint16List xDigits, int xUsed, Uint16List yDigits, int yUsed,
+ Uint16List resultDigits) {
+ var resultUsed =
+ _BigIntImpl._mulDigits(xDigits, xUsed, yDigits, yUsed, resultDigits);
+ return _reduce(resultDigits, resultUsed);
+ }
+}
+
+/// Creates an invocation object used in noSuchMethod forwarding stubs.
+///
+/// The signature is hardwired to the kernel nodes generated in the
+/// `Dart2jsTarget` and read in the `KernelSsaGraphBuilder`.
+external Invocation _createInvocationMirror(
+ String memberName,
+ List typeArguments,
+ List positionalArguments,
+ Map<String, dynamic> namedArguments,
+ int kind);
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/developer_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/developer_patch.dart
new file mode 100644
index 0000000..0ff0f66
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/developer_patch.dart
@@ -0,0 +1,172 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:developer library.
+
+import 'dart:_js_helper' show patch, ForceInline;
+import 'dart:_foreign_helper' show JS;
+import 'dart:async' show Zone;
+import 'dart:isolate';
+
+@patch
+@pragma('dart2js:tryInline')
+bool debugger({bool when: true, String message}) {
+ if (when) {
+ JS('', 'debugger');
+ }
+ return when;
+}
+
+@patch
+Object inspect(Object object) {
+ return object;
+}
+
+@patch
+void log(String message,
+ {DateTime time,
+ int sequenceNumber,
+ int level: 0,
+ String name: '',
+ Zone zone,
+ Object error,
+ StackTrace stackTrace}) {
+ // TODO.
+}
+
+final _extensions = new Map<String, ServiceExtensionHandler>();
+
+@patch
+ServiceExtensionHandler _lookupExtension(String method) {
+ return _extensions[method];
+}
+
+@patch
+_registerExtension(String method, ServiceExtensionHandler handler) {
+ _extensions[method] = handler;
+}
+
+@patch
+void _postEvent(String eventKind, String eventData) {
+ // TODO.
+}
+
+@patch
+bool _isDartStreamEnabled() {
+ return false;
+}
+
+@patch
+int _getTraceClock() {
+ // TODO.
+ return _clockValue++;
+}
+
+int _clockValue = 0;
+
+@patch
+int _getThreadCpuClock() {
+ return -1;
+}
+
+@patch
+void _reportCompleteEvent(int start, int startCpu, String category, String name,
+ String argumentsAsJson) {
+ // TODO.
+}
+
+@patch
+void _reportFlowEvent(int start, int startCpu, String category, String name,
+ int type, int id, String argumentsAsJson) {
+ // TODO.
+}
+
+@patch
+void _reportInstantEvent(
+ int start, String category, String name, String argumentsAsJson) {
+ // TODO.
+}
+
+@patch
+int _getNextAsyncId() {
+ return 0;
+}
+
+@patch
+void _reportTaskEvent(int start, int taskId, String phase, String category,
+ String name, String argumentsAsJson) {
+ // TODO.
+}
+
+@patch
+int _getServiceMajorVersion() {
+ return 0;
+}
+
+@patch
+int _getServiceMinorVersion() {
+ return 0;
+}
+
+@patch
+void _getServerInfo(SendPort sendPort) {
+ sendPort.send(null);
+}
+
+@patch
+void _webServerControl(SendPort sendPort, bool enable) {
+ sendPort.send(null);
+}
+
+@patch
+String _getIsolateIDFromSendPort(SendPort sendPort) {
+ return null;
+}
+
+@patch
+class UserTag {
+ @patch
+ factory UserTag(String label) = _FakeUserTag;
+
+ @patch
+ static UserTag get defaultTag => _FakeUserTag._defaultTag;
+}
+
+class _FakeUserTag implements UserTag {
+ static Map _instances = {};
+
+ _FakeUserTag.real(this.label);
+
+ factory _FakeUserTag(String label) {
+ // Canonicalize by name.
+ var existingTag = _instances[label];
+ if (existingTag != null) {
+ return existingTag;
+ }
+ // Throw an exception if we've reached the maximum number of user tags.
+ if (_instances.length == UserTag.MAX_USER_TAGS) {
+ throw new UnsupportedError(
+ 'UserTag instance limit (${UserTag.MAX_USER_TAGS}) reached.');
+ }
+ // Create a new instance and add it to the instance map.
+ var instance = new _FakeUserTag.real(label);
+ _instances[label] = instance;
+ return instance;
+ }
+
+ final String label;
+
+ UserTag makeCurrent() {
+ var old = _currentTag;
+ _currentTag = this;
+ return old;
+ }
+
+ static final UserTag _defaultTag = new _FakeUserTag('Default');
+}
+
+var _currentTag = _FakeUserTag._defaultTag;
+
+@patch
+UserTag getCurrentTag() => _currentTag;
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/foreign_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/foreign_helper.dart
new file mode 100644
index 0000000..0cecf96
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/foreign_helper.dart
@@ -0,0 +1,272 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library _foreign_helper;
+
+import 'dart:_js_embedded_names' show JsGetName, JsBuiltin;
+
+/// Emits a JavaScript code fragment parametrized by arguments.
+///
+/// Hash characters `#` in the [codeTemplate] are replaced in left-to-right
+/// order with expressions that contain the values of, or evaluate to, the
+/// arguments. The number of hash marks must match the number or arguments.
+/// Although declared with arguments [arg0] through [arg2], the form actually
+/// has no limit on the number of arguments.
+///
+/// The [typeDescription] argument is interpreted as a description of the
+/// behavior of the JavaScript code. Currently it describes the side effects
+/// types that may be returned by the expression, with the additional behavior
+/// that the returned values may be fresh instances of the types. The type
+/// information must be correct as it is trusted by the compiler in
+/// optimizations, and it must be precise as possible since it is used for
+/// native live type analysis to tree-shake large parts of the DOM libraries.
+/// If poorly written, the [typeDescription] will cause unnecessarily bloated
+/// programs. (You can check for this by compiling with `--verbose`; there is
+/// an info message describing the number of native (DOM) types that can be
+/// removed, which usually should be greater than zero.)
+///
+/// The [typeDescription] must be a [String]. Two forms of it are supported:
+///
+/// 1) a union of types separated by vertical bar `|` symbols, e.g.
+/// `"num|String"` describes the union of numbers and Strings. There is no
+/// type in Dart that is this precise. The Dart alternative would be
+/// `Object` or `dynamic`, but these types imply that the JS-code might also
+/// be creating instances of all the DOM types.
+///
+/// If `null` is possible, it must be specified explicitly, e.g.
+/// `"String|Null"`. [typeDescription] has several extensions to help
+/// describe the behavior more accurately. In addition to the union type
+/// already described:
+///
+/// + `=Object` is a plain JavaScript object. Some DOM methods return
+/// instances that have no corresponding Dart type (e.g. cross-frame
+/// documents), `=Object` can be used to describe these untyped' values.
+///
+/// + `var` or empty string. If the entire [typeDescription] is `var` (or
+/// empty string) then the type is `dynamic` but the code is known to not
+/// create any instances.
+///
+/// Examples:
+///
+/// // Parent window might be an opaque cross-frame window.
+/// var thing = JS('=Object|Window', '#.parent', myWindow);
+///
+/// 2) a sequence of the form `<tag>:<value>;` where `<tag>` is one of
+/// `creates`, `returns`, `effects` or `depends`.
+///
+/// The first two tags are used to specify the created and returned types of
+/// the expression. The value of `creates` and `returns` is a type string as
+/// defined in 1).
+///
+/// The tags `effects` and `depends` encode the side effects of this call.
+/// They can be omitted, in which case the expression is parsed and a safe
+/// conservative side-effect estimation is computed.
+///
+/// The values of `effects` and `depends` may be 'all', 'none' or a
+/// comma-separated list of 'no-index', 'no-instance' and 'no-static'.
+///
+/// The value 'all' indicates that the call affects/depends on every
+/// side-effect. The flag 'none' signals that the call does not affect
+/// (resp. depends on) anything.
+///
+/// The value 'no-index' indicates that the call does *not* do (resp. depends
+/// on) any array index-store. The flag 'no-instance' indicates that the call
+/// does not modify (resp. depends on) any instance variable. Similarly,
+/// the 'no-static' value indicates that the call does not modify (resp.
+/// depends on) any static variable.
+///
+/// The `effects` and `depends` flag must be used in tandem. Either both are
+/// specified or none is.
+///
+/// Each tag (including the type tags) may only occur once in the sequence.
+///
+/// Guidelines:
+///
+/// + Do not use any parameter, local, method or field names in the
+/// [codeTemplate]. These names are all subject to arbitrary renaming by the
+/// compiler. Pass the values in via `#` substition, and test with the
+/// `--minify` dart2js command-line option.
+///
+/// + The substituted expressions are values, not locations.
+///
+/// JS('void', '# += "x"', this.field);
+///
+/// `this.field` might not be a substituted as a reference to the field. The
+/// generated code might accidentally work as intended, but it also might be
+///
+/// var t1 = this.field;
+/// t1 += "x";
+///
+/// or
+///
+/// this.get$field() += "x";
+///
+/// The remedy in this case is to expand the `+=` operator, leaving all
+/// references to the Dart field as Dart code:
+///
+/// this.field = JS('String', '# + "x"', this.field);
+///
+/// + Never use `#` in function bodies.
+///
+/// This is a variation on the previous guideline. Since `#` is replaced
+/// with an *expression* and the expression is only valid in the immediate
+/// context, `#` should never appear in a function body. Doing so might
+/// defer the evaluation of the expression, and its side effects, until the
+/// function is called.
+///
+/// For example,
+///
+/// var value = foo();
+/// var f = JS('', 'function(){return #}', value)
+///
+/// might result in no immediate call to `foo` and a call to `foo` on every
+/// call to the JavaScript function bound to `f`. This is better:
+///
+/// var f = JS('',
+/// '(function(val) { return function(){return val}; })(#)', value);
+///
+/// Since `#` occurs in the immediately evaluated expression, the expression
+/// is immediately evaluated and bound to `val` in the immediate call.
+///
+///
+/// Type argument.
+///
+/// In Dart 2.0, the type argument additionally constrains the returned type.
+/// So, with type inference filling in the type argumemnt,
+///
+/// String s = JS('', 'JSON.stringify(#)', x);
+///
+/// will be the same as the current meaning of
+///
+/// var s = JS('String|Null', 'JSON.stringify(#)', x);
+///
+///
+/// Additional notes.
+///
+/// In the future we may extend [typeDescription] to include other aspects of
+/// the behavior, for example, separating the returned types from the
+/// instantiated types to allow the compiler to perform more optimizations
+/// around the code.
+///
+/// This might be an extension of [JS] or a new function similar to [JS] with
+/// additional arguments for the new information.
+// Add additional optional arguments if needed. The method is treated internally
+// as a variable argument method.
+external T JS<T>(String typeDescription, String codeTemplate,
+ [arg0,
+ arg1,
+ arg2,
+ arg3,
+ arg4,
+ arg5,
+ arg6,
+ arg7,
+ arg8,
+ arg9,
+ arg10,
+ arg11,
+ arg12,
+ arg13,
+ arg14,
+ arg51,
+ arg16,
+ arg17,
+ arg18,
+ arg19]);
+
+/// Converts the Dart closure [function] into a JavaScript closure.
+///
+/// Warning: This is no different from [RAW_DART_FUNCTION_REF] which means care
+/// must be taken to store the current isolate.
+external DART_CLOSURE_TO_JS(Function function);
+
+/// Returns a raw reference to the JavaScript function which implements
+/// [function].
+///
+/// Warning: this is dangerous, you should probably use
+/// [DART_CLOSURE_TO_JS] instead. The returned object is not a valid
+/// Dart closure, does not store the isolate context or arity.
+///
+/// A valid example of where this can be used is as the second argument
+/// to V8's Error.captureStackTrace. See
+/// https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi.
+external RAW_DART_FUNCTION_REF(Function function);
+
+/// Sets the current static state to [staticState].
+external void JS_SET_STATIC_STATE(staticState);
+
+/// Returns the interceptor for class [type]. The interceptor is the type's
+/// constructor's `prototype` property. [type] will typically be the class, not
+/// an interface, e.g. `JS_INTERCEPTOR_CONSTANT(JSInt)`, not
+/// `JS_INTERCEPTOR_CONSTANT(int)`.
+external JS_INTERCEPTOR_CONSTANT(Type type);
+
+/// Returns the interceptor for [object].
+///
+/// Calls are replaced with the [HInterceptor] SSA instruction.
+external getInterceptor(object);
+
+/// Returns the Rti object for the type for JavaScript arrays via JS-interop.
+///
+/// Calls are replaced with a [HLoadType] SSA instruction.
+external Object getJSArrayInteropRti();
+
+/// Returns the object corresponding to Namer.staticStateHolder.
+external JS_GET_STATIC_STATE();
+
+/// Returns the JS name for [name] from the Namer.
+external String JS_GET_NAME(JsGetName name);
+
+/// Reads an embedded global.
+///
+/// The [name] should be a constant defined in the `_embedded_names` library.
+external JS_EMBEDDED_GLOBAL(String typeDescription, String name);
+
+/// Instructs the compiler to execute the [builtinName] action at the call-site.
+///
+/// The [builtin] should be a constant defined in the `_embedded_names`
+/// library.
+// Add additional optional arguments if needed. The method is treated internally
+// as a variable argument method.
+external JS_BUILTIN(String typeDescription, JsBuiltin builtin,
+ [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11]);
+
+/// Returns the state of a flag that is determined by the state of the compiler
+/// when the program has been analyzed.
+external bool JS_GET_FLAG(String name);
+
+/// Pretend [code] is executed. Generates no executable code. This is used to
+/// model effects at some other point in external code. For example, the
+/// following models an assignment to foo with an unknown value.
+///
+/// var foo;
+///
+/// main() {
+/// JS_EFFECT((_){ foo = _; })
+/// }
+///
+/// TODO(sra): Replace this hack with something to mark the volatile or
+/// externally initialized elements.
+void JS_EFFECT(Function code) {
+ code(null);
+}
+
+/// Use this class for creating constants that hold JavaScript code.
+/// For example:
+///
+/// const constant = JS_CONST('typeof window != "undefined");
+///
+/// This code will generate:
+/// $.JS_CONST_1 = typeof window != "undefined";
+class JS_CONST {
+ final String code;
+ const JS_CONST(this.code);
+}
+
+/// JavaScript string concatenation. Inputs must be Strings. Corresponds to the
+/// HStringConcat SSA instruction and may be constant-folded.
+String JS_STRING_CONCAT(String a, String b) {
+ // This body is unused, only here for type analysis.
+ return JS('String', '# + #', a, b);
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/instantiation.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/instantiation.dart
new file mode 100644
index 0000000..bb003e6
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/instantiation.dart
@@ -0,0 +1,334 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _js_helper;
+
+/// Support class for generic function type instantiation (binding of types).
+///
+abstract class Instantiation extends Closure {
+ final Closure _genericClosure;
+ Instantiation(this._genericClosure) {
+ // TODO(sra): Copy some metadata used by Function.apply.
+
+ // Mark support code as used. The JS condition is inscrutable to dart2js,
+ // so the 'if (false)' is in the final program.
+ // TODO(sra): Find a better way to do this. Generating the signature methods
+ // earlier as SSA on the instantiation closures should achieve this.
+ if (JS('bool', 'false')) {
+ // [instantiatedGenericFunctionType] is called from injected $signature
+ // methods with runtime type representations.
+ if (JS_GET_FLAG('USE_NEW_RTI')) {
+ newRti.instantiatedGenericFunctionType(JS('', '0'), JS('', '0'));
+ } else {
+ instantiatedGenericFunctionType(JS('', '0'), JS('', '0'));
+ }
+ }
+ }
+
+ /// Returns a list of the bound types.
+ List get _types;
+
+ String toString() {
+ var types = "<${_types.join(', ')}>";
+ // TODO(sra): Refactor Closure formatting to place type arguments inside,
+ // e.g. "Closure 'map<String>' of Instance of 'JSArray<int>'".
+ return '$_genericClosure with $types';
+ }
+}
+
+/// Instantiation classes are subclasses of [Instantiation]. For now we have a
+/// fixed number of subclasses. Later we might generate the classes on demand.
+class Instantiation1<T1> extends Instantiation {
+ Instantiation1(Closure f) : super(f);
+ List get _types => [T1];
+}
+
+class Instantiation2<T1, T2> extends Instantiation {
+ Instantiation2(Closure f) : super(f);
+ List get _types => [T1, T2];
+}
+
+class Instantiation3<T1, T2, T3> extends Instantiation {
+ Instantiation3(Closure f) : super(f);
+ List get _types => [T1, T2, T3];
+}
+
+class Instantiation4<T1, T2, T3, T4> extends Instantiation {
+ Instantiation4(Closure f) : super(f);
+ List get _types => [T1, T2, T3, T4];
+}
+
+class Instantiation5<T1, T2, T3, T4, T5> extends Instantiation {
+ Instantiation5(Closure f) : super(f);
+ List get _types => [T1, T2, T3, T4, T5];
+}
+
+class Instantiation6<T1, T2, T3, T4, T5, T6> extends Instantiation {
+ Instantiation6(Closure f) : super(f);
+ List get _types => [T1, T2, T3, T4, T5, T6];
+}
+
+class Instantiation7<T1, T2, T3, T4, T5, T6, T7> extends Instantiation {
+ Instantiation7(Closure f) : super(f);
+ List get _types => [T1, T2, T3, T4, T5, T6, T7];
+}
+
+class Instantiation8<T1, T2, T3, T4, T5, T6, T7, T8> extends Instantiation {
+ Instantiation8(Closure f) : super(f);
+ List get _types => [T1, T2, T3, T4, T5, T6, T7, T8];
+}
+
+class Instantiation9<T1, T2, T3, T4, T5, T6, T7, T8, T9> extends Instantiation {
+ Instantiation9(Closure f) : super(f);
+ List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9];
+}
+
+class Instantiation10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
+ extends Instantiation {
+ Instantiation10(Closure f) : super(f);
+ List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10];
+}
+
+class Instantiation11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>
+ extends Instantiation {
+ Instantiation11(Closure f) : super(f);
+ List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11];
+}
+
+class Instantiation12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>
+ extends Instantiation {
+ Instantiation12(Closure f) : super(f);
+ List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12];
+}
+
+class Instantiation13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>
+ extends Instantiation {
+ Instantiation13(Closure f) : super(f);
+ List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13];
+}
+
+class Instantiation14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> extends Instantiation {
+ Instantiation14(Closure f) : super(f);
+ List get _types =>
+ [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14];
+}
+
+class Instantiation15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15> extends Instantiation {
+ Instantiation15(Closure f) : super(f);
+ List get _types =>
+ [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15];
+}
+
+class Instantiation16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16> extends Instantiation {
+ Instantiation16(Closure f) : super(f);
+ List get _types =>
+ [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16];
+}
+
+class Instantiation17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17> extends Instantiation {
+ Instantiation17(Closure f) : super(f);
+ List get _types => [
+ T1,
+ T2,
+ T3,
+ T4,
+ T5,
+ T6,
+ T7,
+ T8,
+ T9,
+ T10,
+ T11,
+ T12,
+ T13,
+ T14,
+ T15,
+ T16,
+ T17
+ ];
+}
+
+class Instantiation18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18> extends Instantiation {
+ Instantiation18(Closure f) : super(f);
+ List get _types => [
+ T1,
+ T2,
+ T3,
+ T4,
+ T5,
+ T6,
+ T7,
+ T8,
+ T9,
+ T10,
+ T11,
+ T12,
+ T13,
+ T14,
+ T15,
+ T16,
+ T17,
+ T18
+ ];
+}
+
+class Instantiation19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19> extends Instantiation {
+ Instantiation19(Closure f) : super(f);
+ List get _types => [
+ T1,
+ T2,
+ T3,
+ T4,
+ T5,
+ T6,
+ T7,
+ T8,
+ T9,
+ T10,
+ T11,
+ T12,
+ T13,
+ T14,
+ T15,
+ T16,
+ T17,
+ T18,
+ T19
+ ];
+}
+
+class Instantiation20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20> extends Instantiation {
+ Instantiation20(Closure f) : super(f);
+ List get _types => [
+ T1,
+ T2,
+ T3,
+ T4,
+ T5,
+ T6,
+ T7,
+ T8,
+ T9,
+ T10,
+ T11,
+ T12,
+ T13,
+ T14,
+ T15,
+ T16,
+ T17,
+ T18,
+ T19,
+ T20
+ ];
+}
+
+Instantiation instantiate1<T1>(Closure f) {
+ return new Instantiation1<T1>(f);
+}
+
+Instantiation instantiate2<T1, T2>(Closure f) {
+ return new Instantiation2<T1, T2>(f);
+}
+
+Instantiation instantiate3<T1, T2, T3>(Closure f) {
+ return new Instantiation3<T1, T2, T3>(f);
+}
+
+Instantiation instantiate4<T1, T2, T3, T4>(Closure f) {
+ return new Instantiation4<T1, T2, T3, T4>(f);
+}
+
+Instantiation instantiate5<T1, T2, T3, T4, T5>(Closure f) {
+ return new Instantiation5<T1, T2, T3, T4, T5>(f);
+}
+
+Instantiation instantiate6<T1, T2, T3, T4, T5, T6>(Closure f) {
+ return new Instantiation6<T1, T2, T3, T4, T5, T6>(f);
+}
+
+Instantiation instantiate7<T1, T2, T3, T4, T5, T6, T7>(Closure f) {
+ return new Instantiation7<T1, T2, T3, T4, T5, T6, T7>(f);
+}
+
+Instantiation instantiate8<T1, T2, T3, T4, T5, T6, T7, T8>(Closure f) {
+ return new Instantiation8<T1, T2, T3, T4, T5, T6, T7, T8>(f);
+}
+
+Instantiation instantiate9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(Closure f) {
+ return new Instantiation9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(f);
+}
+
+Instantiation instantiate10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(
+ Closure f) {
+ return new Instantiation10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(f);
+}
+
+Instantiation instantiate11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(
+ Closure f) {
+ return new Instantiation11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(f);
+}
+
+Instantiation instantiate12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(
+ Closure f) {
+ return new Instantiation12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(
+ f);
+}
+
+Instantiation
+ instantiate13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(
+ Closure f) {
+ return new Instantiation13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13>(f);
+}
+
+Instantiation
+ instantiate14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(
+ Closure f) {
+ return new Instantiation14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14>(f);
+}
+
+Instantiation instantiate15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15>(Closure f) {
+ return new Instantiation15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15>(f);
+}
+
+Instantiation instantiate16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16>(Closure f) {
+ return new Instantiation16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16>(f);
+}
+
+Instantiation instantiate17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17>(Closure f) {
+ return new Instantiation17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17>(f);
+}
+
+Instantiation instantiate18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18>(Closure f) {
+ return new Instantiation18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18>(f);
+}
+
+Instantiation instantiate19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19>(Closure f) {
+ return new Instantiation19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19>(f);
+}
+
+Instantiation instantiate20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20>(Closure f) {
+ return new Instantiation20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20>(f);
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/interceptors.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/interceptors.dart
new file mode 100644
index 0000000..b676c1b
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/interceptors.dart
@@ -0,0 +1,455 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library _interceptors;
+
+import 'dart:_js_embedded_names'
+ show DISPATCH_PROPERTY_NAME, TYPE_TO_INTERCEPTOR_MAP;
+
+import 'dart:collection' hide LinkedList, LinkedListEntry;
+import 'dart:_internal' hide Symbol;
+import "dart:_internal" as _symbol_dev show Symbol;
+import 'dart:_js_helper'
+ show
+ allMatchesInStringUnchecked,
+ JSSyntaxRegExp,
+ Primitives,
+ argumentErrorValue,
+ checkBool,
+ checkInt,
+ checkNull,
+ checkNum,
+ checkString,
+ defineProperty,
+ diagnoseIndexError,
+ getIsolateAffinityTag,
+ getRuntimeType,
+ initNativeDispatch,
+ initNativeDispatchFlag,
+ regExpGetNative,
+ regExpCaptureCount,
+ stringContainsUnchecked,
+ stringIndexOfStringUnchecked,
+ stringLastIndexOfUnchecked,
+ stringReplaceAllFuncUnchecked,
+ stringReplaceAllUnchecked,
+ stringReplaceFirstUnchecked,
+ stringReplaceFirstMappedUnchecked,
+ stringReplaceRangeUnchecked,
+ stringSplitUnchecked,
+ throwConcurrentModificationError,
+ lookupAndCacheInterceptor,
+ StringMatch,
+ firstMatchAfter,
+ NoInline;
+
+import 'dart:_foreign_helper'
+ show
+ getInterceptor,
+ JS,
+ JS_EFFECT,
+ JS_EMBEDDED_GLOBAL,
+ JS_INTERCEPTOR_CONSTANT,
+ JS_STRING_CONCAT;
+import 'dart:math' show Random, ln2;
+
+part 'js_array.dart';
+part 'js_number.dart';
+part 'js_string.dart';
+
+final String DART_CLOSURE_PROPERTY_NAME =
+ getIsolateAffinityTag(r'_$dart_dartClosure');
+
+String _symbolToString(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
+
+_symbolMapToStringMap(Map<Symbol, dynamic> map) {
+ if (map == null) return null;
+ var result = new Map<String, dynamic>();
+ map.forEach((Symbol key, value) {
+ result[_symbolToString(key)] = value;
+ });
+ return result;
+}
+
+getDispatchProperty(object) {
+ return JS(
+ '', '#[#]', object, JS_EMBEDDED_GLOBAL('String', DISPATCH_PROPERTY_NAME));
+}
+
+setDispatchProperty(object, value) {
+ defineProperty(
+ object, JS_EMBEDDED_GLOBAL('String', DISPATCH_PROPERTY_NAME), value);
+}
+
+// Avoid inlining this method because inlining gives us multiple allocation
+// points for records which is bad because it leads to polymorphic access.
+@pragma('dart2js:noInline')
+makeDispatchRecord(interceptor, proto, extension, indexability) {
+ // Dispatch records are stored in the prototype chain, and in some cases, on
+ // instances.
+ //
+ // The record layout and field usage is designed to minimize the number of
+ // operations on the common paths.
+ //
+ // [interceptor] is the interceptor - a holder of methods for the object,
+ // i.e. the prototype of the interceptor class.
+ //
+ // [proto] is usually the prototype, used to check that the dispatch record
+ // matches the object and is not the dispatch record of a superclass. Other
+ // values:
+ // - `false` for leaf classes that need no check.
+ // - `true` for Dart classes where the object is its own interceptor (unused)
+ // - a function used to continue matching.
+ //
+ // [extension] is used for irregular cases.
+ //
+ // [indexability] is used to cache whether or not the object
+ // implements JavaScriptIndexingBehavior.
+ //
+ // proto interceptor extension action
+ // ----- ----------- --------- ------
+ // false I use interceptor I
+ // true - use object
+ // P I if object's prototype is P, use I
+ // F - P if object's prototype is P, call F
+
+ return JS('', '{i: #, p: #, e: #, x: #}', interceptor, proto, extension,
+ indexability);
+}
+
+dispatchRecordInterceptor(record) => JS('', '#.i', record);
+dispatchRecordProto(record) => JS('', '#.p', record);
+dispatchRecordExtension(record) => JS('', '#.e', record);
+dispatchRecordIndexability(record) => JS('bool|Null', '#.x', record);
+
+/// Returns the interceptor for a native class instance. Used by
+/// [getInterceptor].
+getNativeInterceptor(object) {
+ var record = getDispatchProperty(object);
+
+ if (record == null) {
+ if (initNativeDispatchFlag == null) {
+ initNativeDispatch();
+ record = getDispatchProperty(object);
+ }
+ }
+
+ if (record != null) {
+ var proto = dispatchRecordProto(record);
+ if (false == proto) return dispatchRecordInterceptor(record);
+ if (true == proto) return object;
+ var objectProto = JS('', 'Object.getPrototypeOf(#)', object);
+ if (JS('bool', '# === #', proto, objectProto)) {
+ return dispatchRecordInterceptor(record);
+ }
+
+ var extension = dispatchRecordExtension(record);
+ if (JS('bool', '# === #', extension, objectProto)) {
+ // TODO(sra): The discriminator returns a tag. The tag is an uncached or
+ // instance-cached tag, defaulting to instance-cached if caching
+ // unspecified.
+ var discriminatedTag = JS('', '(#)(#, #)', proto, object, record);
+ throw new UnimplementedError('Return interceptor for $discriminatedTag');
+ }
+ }
+
+ // Check for cached UnknownJavaScriptObject. This avoids doing the slow
+ // dispatch-record based lookup for repeated js-interop classes.
+ var constructor = JS('', '#.constructor', object);
+ var interceptor = lookupInterceptorByConstructor(constructor);
+ if (interceptor != null) return interceptor;
+
+ // This takes care of dispatch-record based caching, but not constructor based
+ // caching of [UnknownJavaScriptObject]s.
+ interceptor = lookupAndCacheInterceptor(object);
+ if (interceptor != null) return interceptor;
+
+ // JavaScript Objects created via object literals and `Object.create(null)`
+ // are 'plain' Objects. This test could be simplified and the dispatch path
+ // be faster if Object.prototype was pre-patched with a non-leaf dispatch
+ // record.
+ if (JS('bool', 'typeof # == "function"', object)) {
+ interceptor = JS_INTERCEPTOR_CONSTANT(JavaScriptFunction);
+ // TODO(sra): Investigate caching on `Function`. It might be impossible if
+ // some HTML embedded objects on some browsers are (still) JS functions.
+ return interceptor;
+ }
+ var proto = JS('', 'Object.getPrototypeOf(#)', object);
+ if (JS('bool', '# == null', proto)) {
+ // Nowhere to cache output.
+ return JS_INTERCEPTOR_CONSTANT(PlainJavaScriptObject);
+ }
+ interceptor = JS_INTERCEPTOR_CONSTANT(UnknownJavaScriptObject);
+ if (JS('bool', '# === Object.prototype', proto)) {
+ interceptor = JS_INTERCEPTOR_CONSTANT(PlainJavaScriptObject);
+ // TODO(sra): Investigate caching on 'Object'. It might be impossible if
+ // some native class is plain Object (e.g. like Firefox's ImageData).
+ return interceptor;
+ }
+ if (JS('bool', 'typeof # == "function"', constructor)) {
+ cacheInterceptorOnConstructor(constructor, interceptor);
+ return interceptor;
+ }
+ return JS_INTERCEPTOR_CONSTANT(UnknownJavaScriptObject);
+}
+
+// A JS String or Symbol.
+final JS_INTEROP_INTERCEPTOR_TAG = getIsolateAffinityTag(r'_$dart_js');
+
+lookupInterceptorByConstructor(constructor) {
+ return constructor == null
+ ? null
+ : JS('', '#[#]', constructor, JS_INTEROP_INTERCEPTOR_TAG);
+}
+
+void cacheInterceptorOnConstructor(constructor, interceptor) {
+ defineProperty(constructor, JS_INTEROP_INTERCEPTOR_TAG, interceptor);
+}
+
+var constructorToInterceptor =
+ JS('', 'typeof(self.WeakMap) == "undefined" ? new Map() : new WeakMap()');
+
+XlookupInterceptorByConstructor(constructor) {
+ return JS('', '#.get(#)', constructorToInterceptor, constructor);
+}
+
+void XcacheInterceptorOnConstructor(constructor, interceptor) {
+ JS('', '#.set(#, #)', constructorToInterceptor, constructor, interceptor);
+}
+
+/// Data structure used to map a [Type] to the [Interceptor] and constructors
+/// for that type. It is JavaScript array of 3N entries of adjacent slots
+/// containing a [Type], followed by an [Interceptor] class for the type,
+/// followed by a JavaScript object map for the constructors.
+///
+/// The value of this variable is set by the compiler and contains only types
+/// that are user extensions of native classes where the type occurs as a
+/// constant in the program.
+///
+/// The compiler, in CustomElementsAnalysis, assumes that [typeToInterceptorMap]
+/// is accessed only by code that also calls [findIndexForWebComponentType]. If
+/// this assumption is invalidated, the compiler will have to be updated.
+get typeToInterceptorMap {
+ return JS_EMBEDDED_GLOBAL('', TYPE_TO_INTERCEPTOR_MAP);
+}
+
+int findIndexForNativeSubclassType(Type type) {
+ if (JS('bool', '# == null', typeToInterceptorMap)) return null;
+ List map = JS('JSFixedArray', '#', typeToInterceptorMap);
+ for (int i = 0; i + 1 < map.length; i += 3) {
+ if (type == map[i]) {
+ return i;
+ }
+ }
+ return null;
+}
+
+findInterceptorConstructorForType(Type type) {
+ var index = findIndexForNativeSubclassType(type);
+ if (index == null) return null;
+ List map = JS('JSFixedArray', '#', typeToInterceptorMap);
+ return map[index + 1];
+}
+
+/// Returns a JavaScript function that runs the constructor on its argument, or
+/// `null` if there is no such constructor.
+///
+/// The returned function takes one argument, the web component object.
+findConstructorForNativeSubclassType(Type type, String name) {
+ var index = findIndexForNativeSubclassType(type);
+ if (index == null) return null;
+ List map = JS('JSFixedArray', '#', typeToInterceptorMap);
+ var constructorMap = map[index + 2];
+ var constructorFn = JS('', '#[#]', constructorMap, name);
+ return constructorFn;
+}
+
+findInterceptorForType(Type type) {
+ var constructor = findInterceptorConstructorForType(type);
+ if (constructor == null) return null;
+ return JS('', '#.prototype', constructor);
+}
+
+/// The base interceptor class.
+///
+/// The code `r.foo(a)` is compiled to `getInterceptor(r).foo$1(r, a)`. The
+/// value returned by [getInterceptor] holds the methods separately from the
+/// state of the instance. The compiler converts the methods on an interceptor
+/// to take the Dart `this` argument as an explicit `receiver` argument. The
+/// JavaScript `this` parameter is bound to the interceptor.
+///
+/// In order to have uniform call sites, if a method is defined on an
+/// interceptor, methods of that name on plain unintercepted classes also use
+/// the interceptor calling convention. The plain classes are
+/// _self-interceptors_, and for them, `getInterceptor(r)` returns `r`. Methods
+/// on plain unintercepted classes have a redundant `receiver` argument and, to
+/// enable some optimizations, must ignore `receiver` in favour of `this`.
+///
+/// In the case of mixins, a method may be placed on both an intercepted class
+/// and an unintercepted class. In this case, the method must use the
+/// `receiver` parameter.
+///
+///
+/// There are various optimizations of the general call pattern.
+///
+/// When the interceptor can be statically determined, it can be used directly:
+///
+/// CONSTANT_INTERCEPTOR.foo$1(r, a)
+///
+/// If there are only a few classes, [getInterceptor] can be specialized with a
+/// more efficient dispatch:
+///
+/// getInterceptor$specialized(r).foo$1(r, a)
+///
+/// If it can be determined that the receiver is an unintercepted class, it can
+/// be called directly:
+///
+/// r.foo$1(r, a)
+///
+/// If, further, it is known that the call site cannot call a foo that is
+/// mixed-in to a native class, then it is known that the explicit receiver is
+/// ignored, and space-saving dummy value can be passed instead:
+///
+/// r.foo$1(0, a)
+///
+/// This class defines implementations of *all* methods on [Object] so no
+/// interceptor inherits an implementation from [Object]. This enables the
+/// implementations on Object to ignore the explicit receiver argument, which
+/// allows dummy receiver optimization.
+abstract class Interceptor {
+ const Interceptor();
+
+ bool operator ==(other) => identical(this, other);
+
+ int get hashCode => Primitives.objectHashCode(this);
+
+ String toString() => Primitives.objectToHumanReadableString(this);
+
+ // [Interceptor.noSuchMethod] is identical to [Object.noSuchMethod]. However,
+ // each copy is compiled differently. The presence of the method on an
+ // Interceptor class forces [noSuchMethod] to use interceptor calling
+ // convention. In the [Interceptor] version, `this` is the explicit receiver
+ // argument. In the [Object] version, as Object is not an intercepted class,
+ // `this` is the JavaScript receiver, and the explicit receiver is ignored.
+ // The noSuchMethod stubs for selectors that use the interceptor calling
+ // convention do not know the calling convention and forward `this` and
+ // `receiver` to one of these noSuchMethod implementations which selects the
+ // correct Dart receiver.
+ //
+ // We don't allow [noSuchMethod] on intercepted classes (that would force all
+ // calls to use interceptor calling convention). If we did allow it, the
+ // interceptor context would select the correct `this`.
+ dynamic noSuchMethod(Invocation invocation) {
+ throw new NoSuchMethodError(this, invocation.memberName,
+ invocation.positionalArguments, invocation.namedArguments);
+ }
+
+ Type get runtimeType => getRuntimeType(this);
+}
+
+/// The interceptor class for [bool].
+class JSBool extends Interceptor implements bool {
+ const JSBool();
+
+ // Note: if you change this, also change the function [S].
+ String toString() => JS('String', r'String(#)', this);
+
+ bool operator &(bool other) => JS('bool', "# && #", checkBool(other), this);
+
+ bool operator |(bool other) => JS('bool', "# || #", checkBool(other), this);
+
+ bool operator ^(bool other) => !identical(this, checkBool(other));
+
+ // The values here are SMIs, co-prime and differ about half of the bit
+ // positions, including the low bit, so they are different mod 2^k.
+ int get hashCode => this ? (2 * 3 * 23 * 3761) : (269 * 811);
+
+ Type get runtimeType => bool;
+}
+
+/// The interceptor class for [Null].
+///
+/// This class defines implementations for *all* methods on [Object] since
+/// the methods on Object assume the receiver is non-null. This means that
+/// JSNull will always be in the interceptor set for methods defined on Object.
+class JSNull extends Interceptor implements Null {
+ const JSNull();
+
+ bool operator ==(other) => identical(null, other);
+
+ // Note: if you change this, also change the function [S].
+ String toString() => 'null';
+
+ int get hashCode => 0;
+
+ // The spec guarantees that `null` is the singleton instance of the `Null`
+ // class. In the mirrors library we also have to patch the `type` getter to
+ // special case `null`.
+ Type get runtimeType => Null;
+
+ dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/// The supertype for JSString and JSArray. Used by the backend as to
+/// have a type mask that contains the objects that we can use the
+/// native JS [] operator and length on.
+abstract class JSIndexable<E> {
+ int get length;
+ E operator [](int index);
+}
+
+/// The supertype for JSMutableArray and
+/// JavaScriptIndexingBehavior. Used by the backend to have a type mask
+/// that contains the objects we can use the JS []= operator on.
+abstract class JSMutableIndexable<E> extends JSIndexable<E> {
+ operator []=(int index, E value);
+}
+
+/// The interface implemented by JavaScript objects. These are methods in
+/// addition to the regular Dart Object methods like [Object.hashCode].
+///
+/// This is the type that should be exported by a JavaScript interop library.
+abstract class JSObject {}
+
+/// Interceptor base class for JavaScript objects not recognized as some more
+/// specific native type.
+class JavaScriptObject extends Interceptor implements JSObject {
+ const JavaScriptObject();
+
+ // It would be impolite to stash a property on the object.
+ int get hashCode => 0;
+
+ Type get runtimeType => JSObject;
+
+ /// Returns the result of the JavaScript objects `toString` method.
+ String toString() => JS('String', 'String(#)', this);
+}
+
+/// Interceptor for plain JavaScript objects created as JavaScript object
+/// literals or `new Object()`.
+class PlainJavaScriptObject extends JavaScriptObject {
+ const PlainJavaScriptObject();
+}
+
+/// Interceptor for unclassified JavaScript objects, typically objects with a
+/// non-trivial prototype chain.
+///
+/// This class also serves as a fallback for unknown JavaScript exceptions.
+class UnknownJavaScriptObject extends JavaScriptObject {
+ const UnknownJavaScriptObject();
+}
+
+/// Interceptor for JavaScript function objects and Dart functions that have
+/// been converted to JavaScript functions.
+/// These interceptor methods are not always used as the JavaScript function
+/// object has also been mangled to support Dart function calling conventions.
+class JavaScriptFunction extends JavaScriptObject implements Function {
+ const JavaScriptFunction();
+
+ String toString() {
+ var dartClosure = JS('', '#.#', this, DART_CLOSURE_PROPERTY_NAME);
+ if (dartClosure == null) return super.toString();
+ return 'JavaScript function for ${dartClosure.toString()}';
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/internal_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/internal_patch.dart
new file mode 100644
index 0000000..77884e2
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/internal_patch.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:core' hide Symbol;
+import 'dart:core' as core;
+import 'dart:_js_primitives' show printString;
+import 'dart:_js_helper' show patch, NoInline;
+import 'dart:_interceptors' show JSArray;
+import 'dart:_foreign_helper' show JS, JS_GET_FLAG;
+
+@patch
+class Symbol implements core.Symbol {
+ @patch
+ const Symbol(String name) : this._name = name;
+
+ @patch
+ int get hashCode {
+ int hash = JS('int|Null', '#._hashCode', this);
+ if (hash != null) return hash;
+ const arbitraryPrime = 664597;
+ hash = 0x1fffffff & (arbitraryPrime * _name.hashCode);
+ JS('', '#._hashCode = #', this, hash);
+ return hash;
+ }
+
+ @patch
+ toString() => 'Symbol("$_name")';
+
+ @patch
+ static String computeUnmangledName(Symbol symbol) {
+ throw "unsupported operation";
+ }
+}
+
+@patch
+void printToConsole(String line) {
+ printString('$line');
+}
+
+@patch
+List<T> makeListFixedLength<T>(List<T> growableList) {
+ return JSArray.markFixedList(growableList);
+}
+
+@patch
+List<T> makeFixedListUnmodifiable<T>(List<T> fixedLengthList) {
+ return JSArray.markUnmodifiableList(fixedLengthList);
+}
+
+@patch
+@pragma('dart2js:noInline')
+Object extractTypeArguments<T>(T instance, Function extract) {
+ // This function is recognized and replaced with calls to js_runtime.
+
+ // This call to [extract] is required to model that the function is called and
+ // the returned value flows to the result of extractTypeArguments.
+ return extract();
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/io_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/io_patch.dart
new file mode 100644
index 0000000..4f3894d
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/io_patch.dart
@@ -0,0 +1,690 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:_js_helper' show patch;
+import 'dart:_internal' hide Symbol;
+import 'dart:async';
+import 'dart:convert';
+import 'dart:isolate';
+import 'dart:typed_data';
+
+@patch
+class _Directory {
+ @patch
+ static _current(_Namespace namespace) {
+ throw new UnsupportedError("Directory._current");
+ }
+
+ @patch
+ static _setCurrent(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("Directory_SetCurrent");
+ }
+
+ @patch
+ static _createTemp(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("Directory._createTemp");
+ }
+
+ @patch
+ static String _systemTemp(_Namespace namespace) {
+ throw new UnsupportedError("Directory._systemTemp");
+ }
+
+ @patch
+ static _exists(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("Directory._exists");
+ }
+
+ @patch
+ static _create(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("Directory._create");
+ }
+
+ @patch
+ static _deleteNative(_Namespace namespace, Uint8List path, bool recursive) {
+ throw new UnsupportedError("Directory._deleteNative");
+ }
+
+ @patch
+ static _rename(_Namespace namespace, Uint8List path, String newPath) {
+ throw new UnsupportedError("Directory._rename");
+ }
+
+ @patch
+ static void _fillWithDirectoryListing(
+ _Namespace namespace,
+ List<FileSystemEntity> list,
+ Uint8List path,
+ bool recursive,
+ bool followLinks) {
+ throw new UnsupportedError("Directory._fillWithDirectoryListing");
+ }
+}
+
+@patch
+class _AsyncDirectoryListerOps {
+ @patch
+ factory _AsyncDirectoryListerOps(int pointer) {
+ throw new UnsupportedError("Directory._list");
+ }
+}
+
+@patch
+class _EventHandler {
+ @patch
+ static void _sendData(Object sender, SendPort sendPort, int data) {
+ throw new UnsupportedError("EventHandler._sendData");
+ }
+}
+
+@patch
+class FileStat {
+ @patch
+ static _statSync(_Namespace namespace, String path) {
+ throw new UnsupportedError("FileStat.stat");
+ }
+}
+
+@patch
+class FileSystemEntity {
+ @patch
+ static _getTypeNative(
+ _Namespace namespace, Uint8List path, bool followLinks) {
+ throw new UnsupportedError("FileSystemEntity._getType");
+ }
+
+ @patch
+ static _identicalNative(_Namespace namespace, String path1, String path2) {
+ throw new UnsupportedError("FileSystemEntity._identical");
+ }
+
+ @patch
+ static _resolveSymbolicLinks(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("FileSystemEntity._resolveSymbolicLinks");
+ }
+}
+
+@patch
+class _File {
+ @patch
+ static _exists(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("File._exists");
+ }
+
+ @patch
+ static _create(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("File._create");
+ }
+
+ @patch
+ static _createLink(_Namespace namespace, Uint8List path, String target) {
+ throw new UnsupportedError("File._createLink");
+ }
+
+ @patch
+ static _linkTarget(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("File._linkTarget");
+ }
+
+ @patch
+ static _deleteNative(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("File._deleteNative");
+ }
+
+ @patch
+ static _deleteLinkNative(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("File._deleteLinkNative");
+ }
+
+ @patch
+ static _rename(_Namespace namespace, Uint8List oldPath, String newPath) {
+ throw new UnsupportedError("File._rename");
+ }
+
+ @patch
+ static _renameLink(_Namespace namespace, Uint8List oldPath, String newPath) {
+ throw new UnsupportedError("File._renameLink");
+ }
+
+ @patch
+ static _copy(_Namespace namespace, Uint8List oldPath, String newPath) {
+ throw new UnsupportedError("File._copy");
+ }
+
+ @patch
+ static _lengthFromPath(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("File._lengthFromPath");
+ }
+
+ @patch
+ static _lastModified(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("File._lastModified");
+ }
+
+ @patch
+ static _lastAccessed(_Namespace namespace, Uint8List path) {
+ throw new UnsupportedError("File._lastAccessed");
+ }
+
+ @patch
+ static _setLastModified(_Namespace namespace, Uint8List path, int millis) {
+ throw new UnsupportedError("File._setLastModified");
+ }
+
+ @patch
+ static _setLastAccessed(_Namespace namespace, Uint8List path, int millis) {
+ throw new UnsupportedError("File._setLastAccessed");
+ }
+
+ @patch
+ static _open(_Namespace namespace, Uint8List path, int mode) {
+ throw new UnsupportedError("File._open");
+ }
+
+ @patch
+ static int _openStdio(int fd) {
+ throw new UnsupportedError("File._openStdio");
+ }
+}
+
+@patch
+class _Namespace {
+ @patch
+ static void _setupNamespace(var namespace) {
+ throw new UnsupportedError("_Namespace");
+ }
+
+ @patch
+ static _Namespace get _namespace {
+ throw new UnsupportedError("_Namespace");
+ }
+
+ @patch
+ static int get _namespacePointer {
+ throw new UnsupportedError("_Namespace");
+ }
+}
+
+@patch
+class _RandomAccessFileOps {
+ @patch
+ factory _RandomAccessFileOps(int pointer) {
+ throw new UnsupportedError("RandomAccessFile");
+ }
+}
+
+@patch
+class _IOCrypto {
+ @patch
+ static Uint8List getRandomBytes(int count) {
+ throw new UnsupportedError("_IOCrypto.getRandomBytes");
+ }
+}
+
+@patch
+class _Platform {
+ @patch
+ static int _numberOfProcessors() {
+ throw new UnsupportedError("Platform._numberOfProcessors");
+ }
+
+ @patch
+ static String _pathSeparator() {
+ throw new UnsupportedError("Platform._pathSeparator");
+ }
+
+ @patch
+ static String _operatingSystem() {
+ throw new UnsupportedError("Platform._operatingSystem");
+ }
+
+ @patch
+ static _operatingSystemVersion() {
+ throw new UnsupportedError("Platform._operatingSystemVersion");
+ }
+
+ @patch
+ static _localHostname() {
+ throw new UnsupportedError("Platform._localHostname");
+ }
+
+ @patch
+ static _executable() {
+ throw new UnsupportedError("Platform._executable");
+ }
+
+ @patch
+ static _resolvedExecutable() {
+ throw new UnsupportedError("Platform._resolvedExecutable");
+ }
+
+ @patch
+ static List<String> _executableArguments() {
+ throw new UnsupportedError("Platform._executableArguments");
+ }
+
+ @patch
+ static String _packageRoot() {
+ throw new UnsupportedError("Platform._packageRoot");
+ }
+
+ @patch
+ static String _packageConfig() {
+ throw new UnsupportedError("Platform._packageConfig");
+ }
+
+ @patch
+ static _environment() {
+ throw new UnsupportedError("Platform._environment");
+ }
+
+ @patch
+ static String _version() {
+ throw new UnsupportedError("Platform._version");
+ }
+
+ @patch
+ static String _localeName() {
+ throw new UnsupportedError("Platform._localeName");
+ }
+
+ @patch
+ static Uri _script() {
+ throw new UnsupportedError("Platform._script");
+ }
+}
+
+@patch
+class _ProcessUtils {
+ @patch
+ static void _exit(int status) {
+ throw new UnsupportedError("ProcessUtils._exit");
+ }
+
+ @patch
+ static void _setExitCode(int status) {
+ throw new UnsupportedError("ProcessUtils._setExitCode");
+ }
+
+ @patch
+ static int _getExitCode() {
+ throw new UnsupportedError("ProcessUtils._getExitCode");
+ }
+
+ @patch
+ static void _sleep(int millis) {
+ throw new UnsupportedError("ProcessUtils._sleep");
+ }
+
+ @patch
+ static int _pid(Process process) {
+ throw new UnsupportedError("ProcessUtils._pid");
+ }
+
+ @patch
+ static Stream<ProcessSignal> _watchSignal(ProcessSignal signal) {
+ throw new UnsupportedError("ProcessUtils._watchSignal");
+ }
+}
+
+@patch
+class ProcessInfo {
+ @patch
+ static int get currentRss {
+ throw new UnsupportedError("ProcessInfo.currentRss");
+ }
+
+ @patch
+ static int get maxRss {
+ throw new UnsupportedError("ProcessInfo.maxRss");
+ }
+}
+
+@patch
+class Process {
+ @patch
+ static Future<Process> start(String executable, List<String> arguments,
+ {String workingDirectory,
+ Map<String, String> environment,
+ bool includeParentEnvironment: true,
+ bool runInShell: false,
+ ProcessStartMode mode: ProcessStartMode.normal}) {
+ throw new UnsupportedError("Process.start");
+ }
+
+ @patch
+ static Future<ProcessResult> run(String executable, List<String> arguments,
+ {String workingDirectory,
+ Map<String, String> environment,
+ bool includeParentEnvironment: true,
+ bool runInShell: false,
+ Encoding stdoutEncoding: systemEncoding,
+ Encoding stderrEncoding: systemEncoding}) {
+ throw new UnsupportedError("Process.run");
+ }
+
+ @patch
+ static ProcessResult runSync(String executable, List<String> arguments,
+ {String workingDirectory,
+ Map<String, String> environment,
+ bool includeParentEnvironment: true,
+ bool runInShell: false,
+ Encoding stdoutEncoding: systemEncoding,
+ Encoding stderrEncoding: systemEncoding}) {
+ throw new UnsupportedError("Process.runSync");
+ }
+
+ @patch
+ static bool killPid(int pid, [ProcessSignal signal = ProcessSignal.sigterm]) {
+ throw new UnsupportedError("Process.killPid");
+ }
+}
+
+@patch
+class InternetAddress {
+ @patch
+ static InternetAddress get LOOPBACK_IP_V4 {
+ throw new UnsupportedError("InternetAddress.LOOPBACK_IP_V4");
+ }
+
+ @patch
+ static InternetAddress get LOOPBACK_IP_V6 {
+ throw new UnsupportedError("InternetAddress.LOOPBACK_IP_V6");
+ }
+
+ @patch
+ static InternetAddress get ANY_IP_V4 {
+ throw new UnsupportedError("InternetAddress.ANY_IP_V4");
+ }
+
+ @patch
+ static InternetAddress get ANY_IP_V6 {
+ throw new UnsupportedError("InternetAddress.ANY_IP_V6");
+ }
+
+ @patch
+ factory InternetAddress(String address) {
+ throw new UnsupportedError("InternetAddress");
+ }
+ @patch
+ static Future<List<InternetAddress>> lookup(String host,
+ {InternetAddressType type: InternetAddressType.any}) {
+ throw new UnsupportedError("InternetAddress.lookup");
+ }
+
+ @patch
+ static InternetAddress _cloneWithNewHost(
+ InternetAddress address, String host) {
+ throw new UnsupportedError("InternetAddress._cloneWithNewHost");
+ }
+}
+
+@patch
+class NetworkInterface {
+ @patch
+ static bool get listSupported {
+ throw new UnsupportedError("NetworkInterface.listSupported");
+ }
+
+ @patch
+ static Future<List<NetworkInterface>> list(
+ {bool includeLoopback: false,
+ bool includeLinkLocal: false,
+ InternetAddressType type: InternetAddressType.any}) {
+ throw new UnsupportedError("NetworkInterface.list");
+ }
+}
+
+@patch
+class RawServerSocket {
+ @patch
+ static Future<RawServerSocket> bind(address, int port,
+ {int backlog: 0, bool v6Only: false, bool shared: false}) {
+ throw new UnsupportedError("RawServerSocket.bind");
+ }
+}
+
+@patch
+class ServerSocket {
+ @patch
+ static Future<ServerSocket> bind(address, int port,
+ {int backlog: 0, bool v6Only: false, bool shared: false}) {
+ throw new UnsupportedError("ServerSocket.bind");
+ }
+}
+
+@patch
+class RawSocket {
+ @patch
+ static Future<RawSocket> connect(host, int port,
+ {sourceAddress, Duration timeout}) {
+ throw new UnsupportedError("RawSocket constructor");
+ }
+
+ @patch
+ static Future<ConnectionTask<RawSocket>> startConnect(host, int port,
+ {sourceAddress}) {
+ throw new UnsupportedError("RawSocket constructor");
+ }
+}
+
+@patch
+class Socket {
+ @patch
+ static Future<Socket> _connect(host, int port,
+ {sourceAddress, Duration timeout}) {
+ throw new UnsupportedError("Socket constructor");
+ }
+
+ @patch
+ static Future<ConnectionTask<Socket>> _startConnect(host, int port,
+ {sourceAddress}) {
+ throw new UnsupportedError("Socket constructor");
+ }
+}
+
+@patch
+class SecureSocket {
+ @patch
+ factory SecureSocket._(RawSecureSocket rawSocket) {
+ throw new UnsupportedError("SecureSocket constructor");
+ }
+}
+
+@patch
+class RawSynchronousSocket {
+ @patch
+ static RawSynchronousSocket connectSync(host, int port) {
+ throw new UnsupportedError("RawSynchronousSocket.connectSync");
+ }
+}
+
+@patch
+class RawSocketOption {
+ @patch
+ static int _getOptionValue(int key) {
+ throw UnsupportedError("RawSocketOption._getOptionValue");
+ }
+}
+
+@patch
+class SecurityContext {
+ @patch
+ factory SecurityContext({bool withTrustedRoots: false}) {
+ throw new UnsupportedError("SecurityContext constructor");
+ }
+
+ @patch
+ static SecurityContext get defaultContext {
+ throw new UnsupportedError("default SecurityContext getter");
+ }
+
+ @patch
+ static bool get alpnSupported {
+ throw new UnsupportedError("SecurityContext alpnSupported getter");
+ }
+}
+
+@patch
+class X509Certificate {
+ @patch
+ factory X509Certificate._() {
+ throw new UnsupportedError("X509Certificate constructor");
+ }
+}
+
+@patch
+class RawDatagramSocket {
+ @patch
+ static Future<RawDatagramSocket> bind(host, int port,
+ {bool reuseAddress: true, bool reusePort: false, int ttl: 1}) {
+ throw new UnsupportedError("RawDatagramSocket.bind");
+ }
+}
+
+@patch
+class _SecureFilter {
+ @patch
+ factory _SecureFilter._() {
+ throw new UnsupportedError("_SecureFilter._SecureFilter");
+ }
+}
+
+@patch
+class _StdIOUtils {
+ @patch
+ static Stdin _getStdioInputStream(int fd) {
+ throw new UnsupportedError("StdIOUtils._getStdioInputStream");
+ }
+
+ @patch
+ static _getStdioOutputStream(int fd) {
+ throw new UnsupportedError("StdIOUtils._getStdioOutputStream");
+ }
+
+ @patch
+ static int _socketType(Socket socket) {
+ throw new UnsupportedError("StdIOUtils._socketType");
+ }
+
+ @patch
+ static _getStdioHandleType(int fd) {
+ throw new UnsupportedError("StdIOUtils._getStdioHandleType");
+ }
+}
+
+@patch
+class _WindowsCodePageDecoder {
+ @patch
+ static String _decodeBytes(List<int> bytes) {
+ throw new UnsupportedError("_WindowsCodePageDecoder._decodeBytes");
+ }
+}
+
+@patch
+class _WindowsCodePageEncoder {
+ @patch
+ static List<int> _encodeString(String string) {
+ throw new UnsupportedError("_WindowsCodePageEncoder._encodeString");
+ }
+}
+
+@patch
+class RawZLibFilter {
+ @patch
+ static RawZLibFilter _makeZLibDeflateFilter(
+ bool gzip,
+ int level,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ List<int> dictionary,
+ bool raw) {
+ throw new UnsupportedError("_newZLibDeflateFilter");
+ }
+
+ @patch
+ static RawZLibFilter _makeZLibInflateFilter(
+ int windowBits, List<int> dictionary, bool raw) {
+ throw new UnsupportedError("_newZLibInflateFilter");
+ }
+}
+
+@patch
+class Stdin {
+ @patch
+ int readByteSync() {
+ throw new UnsupportedError("Stdin.readByteSync");
+ }
+
+ @patch
+ bool get echoMode {
+ throw new UnsupportedError("Stdin.echoMode");
+ }
+
+ @patch
+ void set echoMode(bool enabled) {
+ throw new UnsupportedError("Stdin.echoMode");
+ }
+
+ @patch
+ bool get lineMode {
+ throw new UnsupportedError("Stdin.lineMode");
+ }
+
+ @patch
+ void set lineMode(bool enabled) {
+ throw new UnsupportedError("Stdin.lineMode");
+ }
+
+ @patch
+ bool get supportsAnsiEscapes {
+ throw new UnsupportedError("Stdin.supportsAnsiEscapes");
+ }
+}
+
+@patch
+class Stdout {
+ @patch
+ bool _hasTerminal(int fd) {
+ throw new UnsupportedError("Stdout.hasTerminal");
+ }
+
+ @patch
+ int _terminalColumns(int fd) {
+ throw new UnsupportedError("Stdout.terminalColumns");
+ }
+
+ @patch
+ int _terminalLines(int fd) {
+ throw new UnsupportedError("Stdout.terminalLines");
+ }
+
+ @patch
+ static bool _supportsAnsiEscapes(int fd) {
+ throw new UnsupportedError("Stdout.supportsAnsiEscapes");
+ }
+}
+
+@patch
+class _FileSystemWatcher {
+ @patch
+ static Stream<FileSystemEvent> _watch(
+ String path, int events, bool recursive) {
+ throw new UnsupportedError("_FileSystemWatcher.watch");
+ }
+
+ @patch
+ static bool get isSupported {
+ throw new UnsupportedError("_FileSystemWatcher.isSupported");
+ }
+}
+
+@patch
+class _IOService {
+ @patch
+ static Future _dispatch(int request, List data) {
+ throw new UnsupportedError("_IOService._dispatch");
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/isolate_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/isolate_patch.dart
new file mode 100644
index 0000000..d781e7a
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/isolate_patch.dart
@@ -0,0 +1,152 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for the dart:isolate library.
+
+import "dart:async";
+import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper' show patch;
+import "dart:typed_data" show ByteData, TypedData, Uint8List;
+
+@patch
+class Isolate {
+ @patch
+ static Isolate get current {
+ throw new UnsupportedError("Isolate.current");
+ }
+
+ @patch
+ String get debugName {
+ throw new UnsupportedError("Isolate.debugName");
+ }
+
+ @patch
+ static Future<Uri> get packageRoot {
+ throw new UnsupportedError("Isolate.packageRoot");
+ }
+
+ @patch
+ static Future<Uri> get packageConfig {
+ throw new UnsupportedError("Isolate.packageConfig");
+ }
+
+ @patch
+ static Future<Uri> resolvePackageUri(Uri packageUri) {
+ throw new UnsupportedError("Isolate.resolvePackageUri");
+ }
+
+ @patch
+ static Future<Isolate> spawn<T>(void entryPoint(T message), T message,
+ {bool paused: false,
+ bool errorsAreFatal,
+ SendPort onExit,
+ SendPort onError}) {
+ throw new UnsupportedError("Isolate.spawn");
+ }
+
+ @patch
+ static Future<Isolate> spawnUri(Uri uri, List<String> args, var message,
+ {bool paused: false,
+ SendPort onExit,
+ SendPort onError,
+ bool errorsAreFatal,
+ bool checked,
+ Map<String, String> environment,
+ Uri packageRoot,
+ Uri packageConfig,
+ bool automaticPackageResolution: false}) {
+ throw new UnsupportedError("Isolate.spawnUri");
+ }
+
+ @patch
+ void _pause(Capability resumeCapability) {
+ throw new UnsupportedError("Isolate._pause");
+ }
+
+ @patch
+ void resume(Capability resumeCapability) {
+ throw new UnsupportedError("Isolate.resume");
+ }
+
+ @patch
+ void addOnExitListener(SendPort responsePort, {Object response}) {
+ throw new UnsupportedError("Isolate.addOnExitListener");
+ }
+
+ @patch
+ void removeOnExitListener(SendPort responsePort) {
+ throw new UnsupportedError("Isolate.removeOnExitListener");
+ }
+
+ @patch
+ void setErrorsFatal(bool errorsAreFatal) {
+ throw new UnsupportedError("Isolate.setErrorsFatal");
+ }
+
+ @patch
+ void kill({int priority: beforeNextEvent}) {
+ throw new UnsupportedError("Isolate.kill");
+ }
+
+ @patch
+ void ping(SendPort responsePort, {Object response, int priority: immediate}) {
+ throw new UnsupportedError("Isolate.ping");
+ }
+
+ @patch
+ void addErrorListener(SendPort port) {
+ throw new UnsupportedError("Isolate.addErrorListener");
+ }
+
+ @patch
+ void removeErrorListener(SendPort port) {
+ throw new UnsupportedError("Isolate.removeErrorListener");
+ }
+}
+
+@patch
+class ReceivePort {
+ @patch
+ factory ReceivePort() = _ReceivePortImpl;
+
+ @patch
+ factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) {
+ throw new UnsupportedError('new ReceivePort.fromRawReceivePort');
+ }
+}
+
+class _ReceivePortImpl extends Stream implements ReceivePort {
+ StreamSubscription listen(void onData(var event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ throw new UnsupportedError("ReceivePort.listen");
+ }
+
+ void close() {}
+
+ SendPort get sendPort => throw new UnsupportedError("ReceivePort.sendPort");
+}
+
+@patch
+class RawReceivePort {
+ @patch
+ factory RawReceivePort([Function handler]) {
+ throw new UnsupportedError('new RawReceivePort');
+ }
+}
+
+@patch
+class Capability {
+ @patch
+ factory Capability() {
+ throw new UnsupportedError('new Capability');
+ }
+}
+
+@patch
+abstract class TransferableTypedData {
+ @patch
+ factory TransferableTypedData.fromList(List<TypedData> list) {
+ throw new UnsupportedError('TransferableTypedData.fromList');
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_array.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_array.dart
new file mode 100644
index 0000000..ff820d4
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_array.dart
@@ -0,0 +1,734 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _interceptors;
+
+class _Growable {
+ const _Growable();
+}
+
+const _ListConstructorSentinel = const _Growable();
+
+/// The interceptor class for [List]. The compiler recognizes this
+/// class as an interceptor, and changes references to [:this:] to
+/// actually use the receiver of the method, which is generated as an extra
+/// argument added to each member.
+class JSArray<E> extends Interceptor implements List<E>, JSIndexable {
+ const JSArray();
+
+ // This factory constructor is the redirection target of the List() factory
+ // constructor. [length] has no type to permit the sentinel value.
+ factory JSArray.list([length = _ListConstructorSentinel]) {
+ if (_ListConstructorSentinel == length) {
+ return new JSArray<E>.emptyGrowable();
+ }
+ return new JSArray<E>.fixed(length);
+ }
+
+ /// Returns a fresh JavaScript Array, marked as fixed-length.
+ ///
+ /// [length] must be a non-negative integer.
+ factory JSArray.fixed(int length) {
+ // Explicit type test is necessary to guard against JavaScript conversions
+ // in unchecked mode, and against `new Array(null)` which creates a single
+ // element Array containing `null`.
+ if (length is! int) {
+ throw new ArgumentError.value(length, 'length', 'is not an integer');
+ }
+ // The JavaScript Array constructor with one argument throws if
+ // the value is not a UInt32. Give a better error message.
+ int maxJSArrayLength = 0xFFFFFFFF;
+ if (length < 0 || length > maxJSArrayLength) {
+ throw new RangeError.range(length, 0, maxJSArrayLength, 'length');
+ }
+ return new JSArray<E>.markFixed(JS('', 'new Array(#)', length));
+ }
+
+ /// Returns a fresh growable JavaScript Array of zero length length.
+ factory JSArray.emptyGrowable() => new JSArray<E>.markGrowable(JS('', '[]'));
+
+ /// Returns a fresh growable JavaScript Array with initial length.
+ ///
+ /// [validatedLength] must be a non-negative integer.
+ factory JSArray.growable(int length) {
+ // Explicit type test is necessary to guard against JavaScript conversions
+ // in unchecked mode.
+ if ((length is! int) || (length < 0)) {
+ throw new ArgumentError('Length must be a non-negative integer: $length');
+ }
+ return new JSArray<E>.markGrowable(JS('', 'new Array(#)', length));
+ }
+
+ /// Constructor for adding type parameters to an existing JavaScript Array.
+ /// The compiler specially recognizes this constructor.
+ ///
+ /// var a = new JSArray<int>.typed(JS('JSExtendableArray', '[]'));
+ /// a is List<int> --> true
+ /// a is List<String> --> false
+ ///
+ /// Usually either the [JSArray.markFixed] or [JSArray.markGrowable]
+ /// constructors is used instead.
+ ///
+ /// The input must be a JavaScript Array. The JS form is just a re-assertion
+ /// to help type analysis when the input type is sloppy.
+ factory JSArray.typed(allocation) => JS('JSArray', '#', allocation);
+
+ factory JSArray.markFixed(allocation) =>
+ JS('JSFixedArray', '#', markFixedList(new JSArray<E>.typed(allocation)));
+
+ factory JSArray.markGrowable(allocation) =>
+ JS('JSExtendableArray', '#', new JSArray<E>.typed(allocation));
+
+ static List markFixedList(List list) {
+ // Functions are stored in the hidden class and not as properties in
+ // the object. We never actually look at the value, but only want
+ // to know if the property exists.
+ JS('void', r'#.fixed$length = Array', list);
+ return JS('JSFixedArray', '#', list);
+ }
+
+ static List markUnmodifiableList(List list) {
+ // Functions are stored in the hidden class and not as properties in
+ // the object. We never actually look at the value, but only want
+ // to know if the property exists.
+ JS('void', r'#.fixed$length = Array', list);
+ JS('void', r'#.immutable$list = Array', list);
+ return JS('JSUnmodifiableArray', '#', list);
+ }
+
+ static bool isFixedLength(JSArray a) {
+ return !JS('bool', r'!#.fixed$length', a);
+ }
+
+ static bool isUnmodifiable(JSArray a) {
+ return !JS('bool', r'!#.immutable$list', a);
+ }
+
+ static bool isGrowable(JSArray a) {
+ return !isFixedLength(a);
+ }
+
+ static bool isMutable(JSArray a) {
+ return !isUnmodifiable(a);
+ }
+
+ checkMutable(String reason) {
+ if (!isMutable(this)) {
+ throw UnsupportedError(reason);
+ }
+ }
+
+ checkGrowable(String reason) {
+ if (!isGrowable(this)) {
+ throw UnsupportedError(reason);
+ }
+ }
+
+ List<R> cast<R>() => List.castFrom<E, R>(this);
+ void add(E value) {
+ checkGrowable('add');
+ JS('void', r'#.push(#)', this, value);
+ }
+
+ E removeAt(int index) {
+ checkGrowable('removeAt');
+ if (index is! int) throw argumentErrorValue(index);
+ if (index < 0 || index >= length) {
+ throw new RangeError.value(index);
+ }
+ return JS('', r'#.splice(#, 1)[0]', this, index);
+ }
+
+ void insert(int index, E value) {
+ checkGrowable('insert');
+ if (index is! int) throw argumentErrorValue(index);
+ if (index < 0 || index > length) {
+ throw new RangeError.value(index);
+ }
+ JS('void', r'#.splice(#, 0, #)', this, index, value);
+ }
+
+ void insertAll(int index, Iterable<E> iterable) {
+ checkGrowable('insertAll');
+ RangeError.checkValueInInterval(index, 0, this.length, 'index');
+ if (iterable is! EfficientLengthIterable) {
+ iterable = iterable.toList();
+ }
+ int insertionLength = iterable.length;
+ this.length += insertionLength;
+ int end = index + insertionLength;
+ this.setRange(end, this.length, this, index);
+ this.setRange(index, end, iterable);
+ }
+
+ void setAll(int index, Iterable<E> iterable) {
+ checkMutable('setAll');
+ RangeError.checkValueInInterval(index, 0, this.length, 'index');
+ for (var element in iterable) {
+ this[index++] = element;
+ }
+ }
+
+ E removeLast() {
+ checkGrowable('removeLast');
+ if (length == 0) throw diagnoseIndexError(this, -1);
+ return JS('', r'#.pop()', this);
+ }
+
+ bool remove(Object element) {
+ checkGrowable('remove');
+ for (int i = 0; i < this.length; i++) {
+ if (this[i] == element) {
+ JS('', r'#.splice(#, 1)', this, i);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// Removes elements matching [test] from [this] List.
+ void removeWhere(bool test(E element)) {
+ checkGrowable('removeWhere');
+ _removeWhere(test, true);
+ }
+
+ void retainWhere(bool test(E element)) {
+ checkGrowable('retainWhere');
+ _removeWhere(test, false);
+ }
+
+ void _removeWhere(bool test(E element), bool removeMatching) {
+ // Performed in two steps, to avoid exposing an inconsistent state
+ // to the [test] function. First the elements to retain are found, and then
+ // the original list is updated to contain those elements.
+
+ // TODO(sra): Replace this algorithm with one that retains a list of ranges
+ // to be removed. Most real uses remove 0, 1 or a few clustered elements.
+
+ List retained = [];
+ int end = this.length;
+ for (int i = 0; i < end; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var element = JS<E>('', '#[#]', this, i);
+ // !test() ensures bool conversion in checked mode.
+ if (!test(element) == removeMatching) {
+ retained.add(element);
+ }
+ if (this.length != end) throw new ConcurrentModificationError(this);
+ }
+ if (retained.length == end) return;
+ this.length = retained.length;
+ for (int i = 0; i < retained.length; i++) {
+ // We don't need a bounds check or an element type check.
+ JS('', '#[#] = #', this, i, retained[i]);
+ }
+ }
+
+ Iterable<E> where(bool f(E element)) {
+ return new WhereIterable<E>(this, f);
+ }
+
+ Iterable<T> expand<T>(Iterable<T> f(E element)) {
+ return new ExpandIterable<E, T>(this, f);
+ }
+
+ void addAll(Iterable<E> collection) {
+ int i = this.length;
+ checkGrowable('addAll');
+ for (E e in collection) {
+ assert(
+ i++ == this.length || (throw new ConcurrentModificationError(this)));
+ JS('void', r'#.push(#)', this, e);
+ }
+ }
+
+ void clear() {
+ length = 0;
+ }
+
+ void forEach(void f(E element)) {
+ int end = this.length;
+ for (int i = 0; i < end; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var element = JS<E>('', '#[#]', this, i);
+ f(element);
+ if (this.length != end) throw new ConcurrentModificationError(this);
+ }
+ }
+
+ Iterable<T> map<T>(T f(E element)) {
+ return new MappedListIterable<E, T>(this, f);
+ }
+
+ String join([String separator = '']) {
+ var list = new List(this.length);
+ for (int i = 0; i < this.length; i++) {
+ list[i] = '${this[i]}';
+ }
+ return JS('String', '#.join(#)', list, separator);
+ }
+
+ Iterable<E> take(int n) {
+ return new SubListIterable<E>(this, 0, n);
+ }
+
+ Iterable<E> takeWhile(bool test(E value)) {
+ return new TakeWhileIterable<E>(this, test);
+ }
+
+ Iterable<E> skip(int n) {
+ return new SubListIterable<E>(this, n, null);
+ }
+
+ Iterable<E> skipWhile(bool test(E value)) {
+ return new SkipWhileIterable<E>(this, test);
+ }
+
+ E reduce(E combine(E previousValue, E element)) {
+ int length = this.length;
+ if (length == 0) throw IterableElementError.noElement();
+ E value = this[0];
+ for (int i = 1; i < length; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var element = JS<E>('', '#[#]', this, i);
+ value = combine(value, element);
+ if (length != this.length) throw new ConcurrentModificationError(this);
+ }
+ return value;
+ }
+
+ T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+ var value = initialValue;
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var element = JS<E>('', '#[#]', this, i);
+ value = combine(value, element);
+ if (this.length != length) throw new ConcurrentModificationError(this);
+ }
+ return value;
+ }
+
+ E firstWhere(bool test(E value), {E orElse()}) {
+ var end = this.length;
+ for (int i = 0; i < end; ++i) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var element = JS<E>('', '#[#]', this, i);
+ if (test(element)) return element;
+ if (this.length != end) throw new ConcurrentModificationError(this);
+ }
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E lastWhere(bool test(E element), {E orElse()}) {
+ int length = this.length;
+ for (int i = length - 1; i >= 0; i--) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var element = JS<E>('', '#[#]', this, i);
+ if (test(element)) return element;
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E singleWhere(bool test(E element), {E orElse()}) {
+ int length = this.length;
+ E match = null;
+ bool matchFound = false;
+ for (int i = 0; i < length; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var element = JS<E>('', '#[#]', this, i);
+ if (test(element)) {
+ if (matchFound) {
+ throw IterableElementError.tooMany();
+ }
+ matchFound = true;
+ match = element;
+ }
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ if (matchFound) return match;
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E elementAt(int index) {
+ return this[index];
+ }
+
+ List<E> sublist(int start, [int end]) {
+ checkNull(start); // TODO(ahe): This is not specified but co19 tests it.
+ if (start is! int) throw argumentErrorValue(start);
+ if (start < 0 || start > length) {
+ throw new RangeError.range(start, 0, length, 'start');
+ }
+ if (end == null) {
+ end = length;
+ } else {
+ if (end is! int) throw argumentErrorValue(end);
+ if (end < start || end > length) {
+ throw new RangeError.range(end, start, length, 'end');
+ }
+ }
+ if (start == end) return <E>[];
+ return new JSArray<E>.markGrowable(
+ JS('', r'#.slice(#, #)', this, start, end));
+ }
+
+ Iterable<E> getRange(int start, int end) {
+ RangeError.checkValidRange(start, end, this.length);
+ return new SubListIterable<E>(this, start, end);
+ }
+
+ E get first {
+ if (length > 0) return this[0];
+ throw IterableElementError.noElement();
+ }
+
+ E get last {
+ if (length > 0) return this[length - 1];
+ throw IterableElementError.noElement();
+ }
+
+ E get single {
+ if (length == 1) return this[0];
+ if (length == 0) throw IterableElementError.noElement();
+ throw IterableElementError.tooMany();
+ }
+
+ void removeRange(int start, int end) {
+ checkGrowable('removeRange');
+ RangeError.checkValidRange(start, end, this.length);
+ int deleteCount = end - start;
+ JS('', '#.splice(#, #)', this, start, deleteCount);
+ }
+
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+ checkMutable('setRange');
+
+ RangeError.checkValidRange(start, end, this.length);
+ int length = end - start;
+ if (length == 0) return;
+ RangeError.checkNotNegative(skipCount, 'skipCount');
+
+ List<E> otherList;
+ int otherStart;
+ // TODO(floitsch): Make this accept more.
+ if (iterable is List) {
+ otherList = iterable;
+ otherStart = skipCount;
+ } else {
+ otherList = iterable.skip(skipCount).toList(growable: false);
+ otherStart = 0;
+ }
+ if (otherStart + length > otherList.length) {
+ throw IterableElementError.tooFew();
+ }
+ if (otherStart < start) {
+ // Copy backwards to ensure correct copy if [from] is this.
+ // TODO(sra): If [from] is the same Array as [this], we can copy without
+ // type annotation checks on the stores.
+ for (int i = length - 1; i >= 0; i--) {
+ // Use JS to avoid bounds check (the bounds check elimination
+ // optimzation is too weak). The 'E' type annotation is a store type
+ // check - we can't rely on iterable, it could be List<dynamic>.
+ E element = otherList[otherStart + i];
+ JS('', '#[#] = #', this, start + i, element);
+ }
+ } else {
+ for (int i = 0; i < length; i++) {
+ E element = otherList[otherStart + i];
+ JS('', '#[#] = #', this, start + i, element);
+ }
+ }
+ }
+
+ void fillRange(int start, int end, [E fillValue]) {
+ checkMutable('fill range');
+ RangeError.checkValidRange(start, end, this.length);
+ for (int i = start; i < end; i++) {
+ // Store is safe since [fillValue] type has been checked as parameter.
+ JS('', '#[#] = #', this, i, fillValue);
+ }
+ }
+
+ void replaceRange(int start, int end, Iterable<E> replacement) {
+ checkGrowable('replaceRange');
+ RangeError.checkValidRange(start, end, this.length);
+ if (replacement is! EfficientLengthIterable) {
+ replacement = replacement.toList();
+ }
+ int removeLength = end - start;
+ int insertLength = replacement.length;
+ if (removeLength >= insertLength) {
+ int delta = removeLength - insertLength;
+ int insertEnd = start + insertLength;
+ int newLength = this.length - delta;
+ this.setRange(start, insertEnd, replacement);
+ if (delta != 0) {
+ this.setRange(insertEnd, newLength, this, end);
+ this.length = newLength;
+ }
+ } else {
+ int delta = insertLength - removeLength;
+ int newLength = this.length + delta;
+ int insertEnd = start + insertLength; // aka. end + delta.
+ this.length = newLength;
+ this.setRange(insertEnd, newLength, this, end);
+ this.setRange(start, insertEnd, replacement);
+ }
+ }
+
+ bool any(bool test(E element)) {
+ int end = this.length;
+ for (int i = 0; i < end; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var element = JS<E>('', '#[#]', this, i);
+ if (test(element)) return true;
+ if (this.length != end) throw new ConcurrentModificationError(this);
+ }
+ return false;
+ }
+
+ bool every(bool test(E element)) {
+ int end = this.length;
+ for (int i = 0; i < end; i++) {
+ // TODO(22407): Improve bounds check elimination to allow this JS code to
+ // be replaced by indexing.
+ var element = JS<E>('', '#[#]', this, i);
+ if (!test(element)) return false;
+ if (this.length != end) throw new ConcurrentModificationError(this);
+ }
+ return true;
+ }
+
+ Iterable<E> get reversed => new ReversedListIterable<E>(this);
+
+ void sort([int compare(E a, E b)]) {
+ checkMutable('sort');
+ Sort.sort(this, compare ?? _compareAny);
+ }
+
+ static int _compareAny(a, b) {
+ // In strong mode Comparable.compare requires an implicit cast to ensure
+ // `a` and `b` are Comparable.
+ return Comparable.compare(a, b);
+ }
+
+ void shuffle([Random random]) {
+ checkMutable('shuffle');
+ if (random == null) random = new Random();
+ int length = this.length;
+ while (length > 1) {
+ int pos = random.nextInt(length);
+ length -= 1;
+ var tmp = this[length];
+ this[length] = this[pos];
+ this[pos] = tmp;
+ }
+ }
+
+ int indexOf(Object element, [int start = 0]) {
+ if (start >= this.length) {
+ return -1;
+ }
+ if (start < 0) {
+ start = 0;
+ }
+ for (int i = start; i < this.length; i++) {
+ if (this[i] == element) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ int lastIndexOf(Object element, [int startIndex]) {
+ if (startIndex == null) {
+ startIndex = this.length - 1;
+ } else {
+ if (startIndex < 0) {
+ return -1;
+ }
+ if (startIndex >= this.length) {
+ startIndex = this.length - 1;
+ }
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (this[i] == element) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ bool contains(Object other) {
+ for (int i = 0; i < length; i++) {
+ if (this[i] == other) return true;
+ }
+ return false;
+ }
+
+ bool get isEmpty => length == 0;
+
+ bool get isNotEmpty => !isEmpty;
+
+ String toString() => ListBase.listToString(this);
+
+ List<E> toList({bool growable: true}) =>
+ growable ? _toListGrowable() : _toListFixed();
+
+ List<E> _toListGrowable() =>
+ // slice(0) is slightly faster than slice()
+ new JSArray<E>.markGrowable(JS('', '#.slice(0)', this));
+
+ List<E> _toListFixed() =>
+ new JSArray<E>.markFixed(JS('', '#.slice(0)', this));
+
+ Set<E> toSet() => new Set<E>.from(this);
+
+ Iterator<E> get iterator => new ArrayIterator<E>(this);
+
+ int get hashCode => Primitives.objectHashCode(this);
+
+ int get length => JS('JSUInt32', r'#.length', this);
+
+ set length(int newLength) {
+ checkGrowable('set length');
+ if (newLength is! int) {
+ throw new ArgumentError.value(newLength, 'newLength');
+ }
+ // TODO(sra): Remove this test and let JavaScript throw an error.
+ if (newLength < 0) {
+ throw new RangeError.range(newLength, 0, null, 'newLength');
+ }
+ // JavaScript with throw a RangeError for numbers that are too big. The
+ // message does not contain the value.
+ JS('void', r'#.length = #', this, newLength);
+ }
+
+ E operator [](int index) {
+ if (index is! int) throw diagnoseIndexError(this, index);
+ if (index >= length || index < 0) throw diagnoseIndexError(this, index);
+ return JS('', '#[#]', this, index);
+ }
+
+ void operator []=(int index, E value) {
+ checkMutable('indexed set');
+ if (index is! int) throw diagnoseIndexError(this, index);
+ if (index >= length || index < 0) throw diagnoseIndexError(this, index);
+ JS('void', r'#[#] = #', this, index, value);
+ }
+
+ Map<int, E> asMap() {
+ return new ListMapView<E>(this);
+ }
+
+ Iterable<E> followedBy(Iterable<E> other) =>
+ new FollowedByIterable<E>.firstEfficient(this, other);
+
+ Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
+
+ List<E> operator +(List<E> other) {
+ int totalLength = this.length + other.length;
+ return <E>[]
+ ..length = totalLength
+ ..setRange(0, this.length, this)
+ ..setRange(this.length, totalLength, other);
+ }
+
+ int indexWhere(bool test(E element), [int start = 0]) {
+ if (start >= this.length) return -1;
+ if (start < 0) start = 0;
+ for (int i = start; i < this.length; i++) {
+ if (test(this[i])) return i;
+ }
+ return -1;
+ }
+
+ int lastIndexWhere(bool test(E element), [int start]) {
+ if (start == null) start = this.length - 1;
+ if (start < 0) return -1;
+ for (int i = start; i >= 0; i--) {
+ if (test(this[i])) return i;
+ }
+ return -1;
+ }
+
+ void set first(E element) {
+ if (this.isEmpty) throw IterableElementError.noElement();
+ this[0] = element;
+ }
+
+ void set last(E element) {
+ if (this.isEmpty) throw IterableElementError.noElement();
+ this[this.length - 1] = element;
+ }
+}
+
+/// Dummy subclasses that allow the backend to track more precise
+/// information about arrays through their type. The CPA type inference
+/// relies on the fact that these classes do not override [] nor []=.
+///
+/// These classes are really a fiction, and can have no methods, since
+/// getInterceptor always returns JSArray. We should consider pushing the
+/// 'isGrowable' and 'isMutable' checks into the getInterceptor implementation
+/// so these classes can have specialized implementations. Doing so will
+/// challenge many assumptions in the JS backend.
+class JSMutableArray<E> extends JSArray<E> implements JSMutableIndexable {}
+
+class JSFixedArray<E> extends JSMutableArray<E> {}
+
+class JSExtendableArray<E> extends JSMutableArray<E> {}
+
+class JSUnmodifiableArray<E> extends JSArray<E> {} // Already is JSIndexable.
+
+/// An [Iterator] that iterates a JSArray.
+///
+class ArrayIterator<E> implements Iterator<E> {
+ final JSArray<E> _iterable;
+ final int _length;
+ int _index;
+ E _current;
+
+ ArrayIterator(JSArray<E> iterable)
+ : _iterable = iterable,
+ _length = iterable.length,
+ _index = 0;
+
+ E get current => _current;
+
+ bool moveNext() {
+ int length = _iterable.length;
+
+ // We have to do the length check even on fixed length Arrays. If we can
+ // inline moveNext() we might be able to GVN the length and eliminate this
+ // check on known fixed length JSArray.
+ if (_length != length) {
+ throw throwConcurrentModificationError(_iterable);
+ }
+
+ if (_index >= length) {
+ _current = null;
+ return false;
+ }
+ _current = _iterable[_index];
+ _index++;
+ return true;
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
new file mode 100644
index 0000000..8c167115
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
@@ -0,0 +1,3551 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library _js_helper;
+
+import 'dart:_js_embedded_names'
+ show
+ CURRENT_SCRIPT,
+ DEFERRED_LIBRARY_PARTS,
+ DEFERRED_PART_URIS,
+ DEFERRED_PART_HASHES,
+ GET_TYPE_FROM_NAME,
+ GET_ISOLATE_TAG,
+ INITIALIZE_LOADED_HUNK,
+ INTERCEPTED_NAMES,
+ INTERCEPTORS_BY_TAG,
+ IS_HUNK_LOADED,
+ IS_HUNK_INITIALIZED,
+ JsBuiltin,
+ JsGetName,
+ LEAF_TAGS,
+ NATIVE_SUPERCLASS_TAG_NAME,
+ STATIC_FUNCTION_NAME_PROPERTY_NAME;
+
+import 'dart:collection';
+
+import 'dart:async' show Completer, DeferredLoadException, Future;
+
+import 'dart:_foreign_helper'
+ show
+ DART_CLOSURE_TO_JS,
+ getInterceptor,
+ JS,
+ JS_BUILTIN,
+ JS_CONST,
+ JS_EFFECT,
+ JS_EMBEDDED_GLOBAL,
+ JS_GET_FLAG,
+ JS_GET_NAME,
+ JS_INTERCEPTOR_CONSTANT,
+ JS_STRING_CONCAT,
+ RAW_DART_FUNCTION_REF;
+
+import 'dart:_interceptors';
+import 'dart:_internal' as _symbol_dev;
+import 'dart:_internal'
+ show
+ EfficientLengthIterable,
+ MappedIterable,
+ IterableElementError,
+ SubListIterable;
+
+import 'dart:_native_typed_data';
+
+import 'dart:_js_names'
+ show
+ extractKeys,
+ unmangleGlobalNameIfPreservedAnyways,
+ unmangleAllIdentifiersIfPreservedAnyways;
+
+import 'dart:_rti' as newRti
+ show
+ createRuntimeType,
+ evalInInstance,
+ getRuntimeType,
+ getTypeFromTypesTable,
+ instanceTypeName,
+ instantiatedGenericFunctionType;
+
+part 'annotations.dart';
+part 'constant_map.dart';
+part 'instantiation.dart';
+part 'native_helper.dart';
+part 'regexp_helper.dart';
+part 'string_helper.dart';
+part 'js_rti.dart';
+part 'linked_hash_map.dart';
+
+/// Marks the internal map in dart2js, so that internal libraries can is-check
+/// them.
+abstract class InternalMap {}
+
+/// Extracts the JavaScript-constructor name from the given isCheckProperty.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+String isCheckPropertyToJsConstructorName(String isCheckProperty) {
+ return JS_BUILTIN('returns:String;depends:none;effects:none',
+ JsBuiltin.isCheckPropertyToJsConstructorName, isCheckProperty);
+}
+
+/// Returns true if the given [type] is a function type object.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+bool isDartFunctionType(Object type) {
+ // Function type test is using the `in` operator which doesn't work on
+ // primitive types.
+ assert(!(type == null || type is num || type is String));
+ return JS_BUILTIN(
+ 'returns:bool;effects:none;depends:none', JsBuiltin.isFunctionType, type);
+}
+
+/// Returns true if the given [type] is a FutureOr type object.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+bool isDartFutureOrType(Object type) {
+ // FutureOr test is using the `in` operator which doesn't work on primitive
+ // types.
+ assert(!(type == null || type is num || type is String));
+ return JS_BUILTIN(
+ 'returns:bool;effects:none;depends:none', JsBuiltin.isFutureOrType, type);
+}
+
+@pragma('dart2js:tryInline')
+bool isDartVoidTypeRti(Object type) {
+ return JS_BUILTIN(
+ 'returns:bool;effects:none;depends:none', JsBuiltin.isVoidType, type);
+}
+
+/// Retrieves the class name from type information stored on the constructor of
+/// [type].
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+String rawRtiToJsConstructorName(Object rti) {
+ return JS_BUILTIN('String', JsBuiltin.rawRtiToJsConstructorName, rti);
+}
+
+/// Given a raw constructor name, return the unminified name, if available,
+/// otherwise tag the name with `minified:`.
+String unminifyOrTag(String rawClassName) {
+ String preserved = unmangleGlobalNameIfPreservedAnyways(rawClassName);
+ if (preserved is String) return preserved;
+ if (JS_GET_FLAG('MINIFIED')) return 'minified:${rawClassName}';
+ return rawClassName;
+}
+
+/// Returns the rti from the given [constructorName].
+// TODO(floitsch): make this a builtin.
+jsConstructorNameToRti(String constructorName) {
+ var getTypeFromName = JS_EMBEDDED_GLOBAL('', GET_TYPE_FROM_NAME);
+ return JS('', '#(#)', getTypeFromName, constructorName);
+}
+
+/// Returns the raw runtime type of the given object [o].
+///
+/// The argument [o] must be the interceptor for primitive types. If
+/// necessary run it through [getInterceptor] first.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+// TODO(floitsch): we should call getInterceptor ourselves, but currently
+// getInterceptor is not GVNed.
+@pragma('dart2js:tryInline')
+Object getRawRuntimeType(Object o) {
+ return JS_BUILTIN('', JsBuiltin.rawRuntimeType, o);
+}
+
+/// Returns whether the given [type] is a subtype of [other].
+///
+/// The argument [other] is the name of the other type, as computed by
+/// [runtimeTypeToString].
+@pragma('dart2js:tryInline')
+bool builtinIsSubtype(type, String other) {
+ return JS_BUILTIN('returns:bool;effects:none;depends:none',
+ JsBuiltin.isSubtype, other, type);
+}
+
+/// Returns true if the given [type] is _the_ `Function` type.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+bool isDartFunctionTypeRti(Object type) {
+ return JS_BUILTIN(
+ 'returns:bool;effects:none;depends:none',
+ JsBuiltin.isGivenTypeRti,
+ type,
+ JS_GET_NAME(JsGetName.FUNCTION_CLASS_TYPE_NAME));
+}
+
+/// Returns true if the given [type] is _the_ `Null` type.
+@pragma('dart2js:tryInline')
+bool isNullType(Object type) {
+ return JS_BUILTIN(
+ 'returns:bool;effects:none;depends:none',
+ JsBuiltin.isGivenTypeRti,
+ type,
+ JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME));
+}
+
+/// Returns whether the given type is the dynamic type.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+bool isDartDynamicTypeRti(type) {
+ return JS_BUILTIN(
+ 'returns:bool;effects:none;depends:none', JsBuiltin.isDynamicType, type);
+}
+
+@pragma('dart2js:tryInline')
+bool isDartJsInteropTypeArgumentRti(type) {
+ return JS_BUILTIN('returns:bool;effects:none;depends:none',
+ JsBuiltin.isJsInteropTypeArgument, type);
+}
+
+/// Returns whether the given type is _the_ Dart Object type.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+bool isDartObjectTypeRti(type) {
+ return JS_BUILTIN(
+ 'returns:bool;effects:none;depends:none',
+ JsBuiltin.isGivenTypeRti,
+ type,
+ JS_GET_NAME(JsGetName.OBJECT_CLASS_TYPE_NAME));
+}
+
+/// Returns whether the given type is _the_ null type.
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+bool isNullTypeRti(type) {
+ return JS_BUILTIN(
+ 'returns:bool;effects:none;depends:none',
+ JsBuiltin.isGivenTypeRti,
+ type,
+ JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME));
+}
+
+/// Returns the metadata of the given [index].
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+getMetadata(int index) {
+ return JS_BUILTIN(
+ 'returns:var;effects:none;depends:none', JsBuiltin.getMetadata, index);
+}
+
+/// Returns the type of the given [index].
+// TODO(floitsch): move this to foreign_helper.dart or similar.
+@pragma('dart2js:tryInline')
+getType(int index) {
+ return JS_BUILTIN(
+ 'returns:var;effects:none;depends:none', JsBuiltin.getType, index);
+}
+
+/// No-op method that is called to inform the compiler that preambles might
+/// be needed when executing the resulting JS file in a command-line
+/// JS engine.
+requiresPreamble() {}
+
+bool isJsIndexable(var object, var record) {
+ if (record != null) {
+ var result = dispatchRecordIndexability(record);
+ if (result != null) return result;
+ }
+ return object is JavaScriptIndexingBehavior;
+}
+
+String S(value) {
+ if (value is String) return value;
+ if (value is num) {
+ if (value != 0) {
+ // ""+x is faster than String(x) for integers on most browsers.
+ return JS('String', r'"" + (#)', value);
+ }
+ } else if (true == value) {
+ return 'true';
+ } else if (false == value) {
+ return 'false';
+ } else if (value == null) {
+ return 'null';
+ }
+ var res = value.toString();
+ if (res is! String) throw argumentErrorValue(value);
+ return res;
+}
+
+// Called from generated code.
+createInvocationMirror(
+ String name, internalName, kind, arguments, argumentNames, types) {
+ // TODO(sra): [types] (the number of type arguments) could be omitted in the
+ // generated stub code to save an argument. Then we would use `types ?? 0`.
+ return new JSInvocationMirror(
+ name, internalName, kind, arguments, argumentNames, types);
+}
+
+createUnmangledInvocationMirror(
+ Symbol symbol, internalName, kind, arguments, argumentNames, types) {
+ return new JSInvocationMirror(
+ symbol, internalName, kind, arguments, argumentNames, types);
+}
+
+void throwInvalidReflectionError(String memberName) {
+ throw new UnsupportedError("Can't use '$memberName' in reflection "
+ "because it is not included in a @MirrorsUsed annotation.");
+}
+
+/// Helper used to instrument calls when the compiler is invoked with
+/// `--experiment-call-instrumentation`.
+///
+/// By default, whenever a method is invoked for the first time, it prints an id
+/// and the method name to the console. This can be overriden by adding a top
+/// level `dartCallInstrumentation` hook in JavaScript.
+@pragma('dart2js:noInline')
+void traceHelper(dynamic /*int*/ id, dynamic /*String*/ qualifiedName) {
+ // Note: this method is written mostly in JavaScript to prevent a stack
+ // overflow. In particular, we use dynamic argument types because with with
+ // types, traceHelper would include type checks for the parameter types, those
+ // checks (intTypeCheck, stringTypeCheck) are themselves calls that end up
+ // invoking this traceHelper and produce a stack overflow. Similarly if we
+ // had Dart code below using, for example, string interpolation, we would
+ // include extra calls to the Dart runtime that could also trigger a stack
+ // overflow. This approach here is simpler than making the compiler smart
+ // about how to generate traceHelper calls more carefully.
+ JS(
+ '',
+ r'''
+ (function (id, name) {
+ var hook = self.dartCallInstrumentation;
+ if (typeof hook === "function") {
+ hook(id, name);
+ return;
+ }
+ if (!this.callInstrumentationCache) {
+ this.callInstrumentationCache = Object.create(null);
+ }
+ if (!this.callInstrumentationCache[id]) {
+ console.log(id, name);
+ this.callInstrumentationCache[id] = true;
+ }
+ })(#, #)''',
+ id,
+ qualifiedName);
+}
+
+class JSInvocationMirror implements Invocation {
+ static const METHOD = 0;
+ static const GETTER = 1;
+ static const SETTER = 2;
+
+ /// When [_memberName] is a String, it holds the mangled name of this
+ /// invocation. When it is a Symbol, it holds the unmangled name.
+ var /* String or Symbol */ _memberName;
+ final String _internalName;
+ final int _kind;
+ final List _arguments;
+ final List _namedArgumentNames;
+ final int _typeArgumentCount;
+
+ JSInvocationMirror(this._memberName, this._internalName, this._kind,
+ this._arguments, this._namedArgumentNames, this._typeArgumentCount);
+
+ Symbol get memberName {
+ if (_memberName is Symbol) return _memberName;
+ return _memberName = new _symbol_dev.Symbol.unvalidated(_memberName);
+ }
+
+ bool get isMethod => _kind == METHOD;
+ bool get isGetter => _kind == GETTER;
+ bool get isSetter => _kind == SETTER;
+ bool get isAccessor => _kind != METHOD;
+
+ List<Type> get typeArguments {
+ if (_typeArgumentCount == 0) return const <Type>[];
+ int start = _arguments.length - _typeArgumentCount;
+ var list = <Type>[];
+ if (JS_GET_FLAG('USE_NEW_RTI')) {
+ for (int index = 0; index < _typeArgumentCount; index++) {
+ list.add(newRti.createRuntimeType(_arguments[start + index]));
+ }
+ } else {
+ for (int index = 0; index < _typeArgumentCount; index++) {
+ list.add(createRuntimeType(_arguments[start + index]));
+ }
+ }
+ return list;
+ }
+
+ List get positionalArguments {
+ if (isGetter) return const [];
+ var argumentCount =
+ _arguments.length - _namedArgumentNames.length - _typeArgumentCount;
+ if (argumentCount == 0) return const [];
+ var list = [];
+ for (var index = 0; index < argumentCount; index++) {
+ list.add(_arguments[index]);
+ }
+ return JSArray.markUnmodifiableList(list);
+ }
+
+ Map<Symbol, dynamic> get namedArguments {
+ if (isAccessor) return const <Symbol, dynamic>{};
+ int namedArgumentCount = _namedArgumentNames.length;
+ int namedArgumentsStartIndex =
+ _arguments.length - namedArgumentCount - _typeArgumentCount;
+ if (namedArgumentCount == 0) return const <Symbol, dynamic>{};
+ var map = new Map<Symbol, dynamic>();
+ for (int i = 0; i < namedArgumentCount; i++) {
+ map[new _symbol_dev.Symbol.unvalidated(_namedArgumentNames[i])] =
+ _arguments[namedArgumentsStartIndex + i];
+ }
+ return new ConstantMapView<Symbol, dynamic>(map);
+ }
+}
+
+class Primitives {
+ static int objectHashCode(object) {
+ int hash = JS('int|Null', r'#.$identityHash', object);
+ if (hash == null) {
+ hash = JS('int', '(Math.random() * 0x3fffffff) | 0');
+ JS('void', r'#.$identityHash = #', object, hash);
+ }
+ return JS('int', '#', hash);
+ }
+
+ static int parseInt(String source, int radix) {
+ checkString(source);
+ var re = JS('', r'/^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i');
+ var match = JS('JSExtendableArray|Null', '#.exec(#)', re, source);
+ int digitsIndex = 1;
+ int hexIndex = 2;
+ int decimalIndex = 3;
+ int nonDecimalHexIndex = 4;
+ if (match == null) {
+ // TODO(sra): It might be that the match failed due to unrecognized U+0085
+ // spaces. We could replace them with U+0020 spaces and try matching
+ // again.
+ return null;
+ }
+ String decimalMatch = match[decimalIndex];
+ if (radix == null) {
+ if (decimalMatch != null) {
+ // Cannot fail because we know that the digits are all decimal.
+ return JS('int', r'parseInt(#, 10)', source);
+ }
+ if (match[hexIndex] != null) {
+ // Cannot fail because we know that the digits are all hex.
+ return JS('int', r'parseInt(#, 16)', source);
+ }
+ return null;
+ }
+
+ if (radix is! int) {
+ throw new ArgumentError.value(radix, 'radix', 'is not an integer');
+ }
+ if (radix < 2 || radix > 36) {
+ throw new RangeError.range(radix, 2, 36, 'radix');
+ }
+ if (radix == 10 && decimalMatch != null) {
+ // Cannot fail because we know that the digits are all decimal.
+ return JS('int', r'parseInt(#, 10)', source);
+ }
+ // If radix >= 10 and we have only decimal digits the string is safe.
+ // Otherwise we need to check the digits.
+ if (radix < 10 || decimalMatch == null) {
+ // We know that the characters must be ASCII as otherwise the
+ // regexp wouldn't have matched. Lowercasing by doing `| 0x20` is thus
+ // guaranteed to be a safe operation, since it preserves digits
+ // and lower-cases ASCII letters.
+ int maxCharCode;
+ if (radix <= 10) {
+ // Allow all digits less than the radix. For example 0, 1, 2 for
+ // radix 3.
+ // "0".codeUnitAt(0) + radix - 1;
+ maxCharCode = (0x30 - 1) + radix;
+ } else {
+ // Letters are located after the digits in ASCII. Therefore we
+ // only check for the character code. The regexp above made already
+ // sure that the string does not contain anything but digits or
+ // letters.
+ // "a".codeUnitAt(0) + (radix - 10) - 1;
+ maxCharCode = (0x61 - 10 - 1) + radix;
+ }
+ assert(match[digitsIndex] is String);
+ String digitsPart = JS('String', '#[#]', match, digitsIndex);
+ for (int i = 0; i < digitsPart.length; i++) {
+ int characterCode = digitsPart.codeUnitAt(i) | 0x20;
+ if (characterCode > maxCharCode) {
+ return null;
+ }
+ }
+ }
+ // The above matching and checks ensures the source has at least one digits
+ // and all digits are suitable for the radix, so parseInt cannot return NaN.
+ return JS('int', r'parseInt(#, #)', source, radix);
+ }
+
+ static double parseDouble(String source) {
+ checkString(source);
+ // Notice that JS parseFloat accepts garbage at the end of the string.
+ // Accept only:
+ // - [+/-]NaN
+ // - [+/-]Infinity
+ // - a Dart double literal
+ // We do allow leading or trailing whitespace.
+ if (!JS(
+ 'bool',
+ r'/^\s*[+-]?(?:Infinity|NaN|'
+ r'(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$/.test(#)',
+ source)) {
+ return null;
+ }
+ var result = JS('num', r'parseFloat(#)', source);
+ if (result.isNaN) {
+ var trimmed = source.trim();
+ if (trimmed == 'NaN' || trimmed == '+NaN' || trimmed == '-NaN') {
+ return result;
+ }
+ return null;
+ }
+ return result;
+ }
+
+ /// [: r"$".codeUnitAt(0) :]
+ static const int DOLLAR_CHAR_VALUE = 36;
+
+ /// Creates a string containing the complete type for the class [className]
+ /// with the given type arguments.
+ ///
+ /// In minified mode, uses the unminified names if available.
+ ///
+ /// The given [className] string generally contains the name of the JavaScript
+ /// constructor of the given class.
+ static String formatType(String className, List typeArguments) {
+ return unmangleAllIdentifiersIfPreservedAnyways(
+ '$className${joinArguments(typeArguments, 0)}');
+ }
+
+ /// Returns the type of [object] as a string (including type arguments).
+ /// Tries to return a sensible name for non-Dart objects.
+ ///
+ /// In minified mode, uses the unminified names if available, otherwise tags
+ /// them with 'minified:'.
+ @pragma('dart2js:noInline')
+ static String objectTypeName(Object object) {
+ if (JS_GET_FLAG('USE_NEW_RTI')) {
+ return _objectTypeNameNewRti(object);
+ }
+ String className = _objectClassName(object);
+ String arguments = joinArguments(getRuntimeTypeInfo(object), 0);
+ return '${className}${arguments}';
+ }
+
+ static String _objectClassName(Object object) {
+ var interceptor = getInterceptor(object);
+ // The interceptor is either an object (self-intercepting plain Dart class),
+ // the prototype of the constructor for an Interceptor class (like
+ // `JSString.prototype`, `JSNull.prototype`), or an Interceptor object
+ // instance (`const JSString()`, should use `JSString.prototype`).
+ //
+ // These all should have a `constructor` property with a `name` property.
+ String name;
+ var interceptorConstructor = JS('', '#.constructor', interceptor);
+ if (JS('bool', 'typeof # == "function"', interceptorConstructor)) {
+ var interceptorConstructorName = JS('', '#.name', interceptorConstructor);
+ if (interceptorConstructorName is String) {
+ name = interceptorConstructorName;
+ }
+ }
+
+ if (name == null ||
+ identical(interceptor, JS_INTERCEPTOR_CONSTANT(Interceptor)) ||
+ object is UnknownJavaScriptObject) {
+ // Try to do better. If we do not find something better, leave the name
+ // as 'UnknownJavaScriptObject' or 'Interceptor' (or the minified name).
+ //
+ // When we get here via the UnknownJavaScriptObject test (for JavaScript
+ // objects from outside the program), the object's constructor has a
+ // better name that 'UnknownJavaScriptObject'.
+ //
+ // When we get here the Interceptor test (for Native classes that are
+ // declared in the Dart program but have been 'folded' into Interceptor),
+ // the native class's constructor name is better than the generic
+ // 'Interceptor' (an abstract class).
+
+ // Try the [constructorNameFallback]. This gets the constructor name for
+ // any browser (used by [getNativeInterceptor]).
+ String dispatchName = constructorNameFallback(object);
+ name ??= dispatchName;
+ if (dispatchName == 'Object') {
+ // Try to decompile the constructor by turning it into a string and get
+ // the name out of that. If the decompiled name is a string containing
+ // an identifier, we use that instead of the very generic 'Object'.
+ var objectConstructor = JS('', '#.constructor', object);
+ if (JS('bool', 'typeof # == "function"', objectConstructor)) {
+ var match = JS('var', r'#.match(/^\s*function\s*([\w$]*)\s*\(/)',
+ JS('var', r'String(#)', objectConstructor));
+ var decompiledName = match == null ? null : JS('var', r'#[1]', match);
+ if (decompiledName is String &&
+ JS('bool', r'/^\w+$/.test(#)', decompiledName)) {
+ name = decompiledName;
+ }
+ }
+ }
+ return JS('String', '#', name);
+ }
+
+ // Type inference does not understand that [name] is now always a non-null
+ // String. (There is some imprecision in the negation of the disjunction.)
+ name = JS('String', '#', name);
+
+ // TODO(kasperl): If the namer gave us a fresh global name, we may
+ // want to remove the numeric suffix that makes it unique too.
+ if (name.length > 1 && identical(name.codeUnitAt(0), DOLLAR_CHAR_VALUE)) {
+ name = name.substring(1);
+ }
+ return unminifyOrTag(name);
+ }
+
+ /// Returns the type of [object] as a string (including type arguments).
+ /// Tries to return a sensible name for non-Dart objects.
+ ///
+ /// In minified mode, uses the unminified names if available, otherwise tags
+ /// them with 'minified:'.
+ static String _objectTypeNameNewRti(Object object) {
+ var dartObjectConstructor = JS_BUILTIN(
+ 'depends:none;effects:none;', JsBuiltin.dartObjectConstructor);
+ if (JS('bool', '# instanceof #', object, dartObjectConstructor)) {
+ return newRti.instanceTypeName(object);
+ }
+
+ var interceptor = getInterceptor(object);
+ if (identical(interceptor, JS_INTERCEPTOR_CONSTANT(Interceptor)) ||
+ object is UnknownJavaScriptObject) {
+ // Try to do better. If we do not find something better, fallthrough to
+ // Dart-type based name that leave the name as 'UnknownJavaScriptObject'
+ // or 'Interceptor' (or the minified versions thereof).
+ //
+ // When we get here via the UnknownJavaScriptObject test (for JavaScript
+ // objects from outside the program), the object's constructor has a
+ // better name that 'UnknownJavaScriptObject'.
+ //
+ // When we get here the Interceptor test (for Native classes that are
+ // declared in the Dart program but have been 'folded' into Interceptor),
+ // the native class's constructor name is better than the generic
+ // 'Interceptor' (an abstract class).
+
+ // Try the [constructorNameFallback]. This gets the constructor name for
+ // any browser (used by [getNativeInterceptor]).
+ String dispatchName = constructorNameFallback(object);
+ if (_saneNativeClassName(dispatchName)) return dispatchName;
+ var constructor = JS('', '#.constructor', object);
+ if (JS('bool', 'typeof # == "function"', constructor)) {
+ var constructorName = JS('', '#.name', constructor);
+ if (constructorName is String &&
+ _saneNativeClassName(constructorName)) {
+ return constructorName;
+ }
+ }
+ }
+
+ return newRti.instanceTypeName(object);
+ }
+
+ static bool _saneNativeClassName(name) =>
+ name != null && name != 'Object' && name != '';
+
+ /// In minified mode, uses the unminified names if available.
+ static String objectToHumanReadableString(Object object) {
+ String name = objectTypeName(object);
+ return "Instance of '$name'";
+ }
+
+ static int dateNow() => JS('int', r'Date.now()');
+
+ static void initTicker() {
+ if (timerFrequency != null) return;
+ // Start with low-resolution. We overwrite the fields if we find better.
+ timerFrequency = 1000;
+ timerTicks = dateNow;
+ if (JS('bool', 'typeof window == "undefined"')) return;
+ var window = JS('var', 'window');
+ if (window == null) return;
+ var performance = JS('var', '#.performance', window);
+ if (performance == null) return;
+ if (JS('bool', 'typeof #.now != "function"', performance)) return;
+ timerFrequency = 1000000;
+ timerTicks = () => (1000 * JS('num', '#.now()', performance)).floor();
+ }
+
+ static int timerFrequency;
+ static Function timerTicks;
+
+ static String currentUri() {
+ requiresPreamble();
+ // In a browser return self.location.href.
+ if (JS('bool', '!!self.location')) {
+ return JS('String', 'self.location.href');
+ }
+
+ return null;
+ }
+
+ /// Version of `String.fromCharCode.apply` that chunks the conversion to avoid
+ /// stack overflows due to very large argument arrays.
+ ///
+ /// [array] is pre-validated as a JSArray of int values but is not typed as
+ /// <int> so it can be called with any JSArray.
+ static String _fromCharCodeApply(List array) {
+ const kMaxApply = 500;
+ int end = array.length;
+ if (end <= kMaxApply) {
+ return JS('String', r'String.fromCharCode.apply(null, #)', array);
+ }
+ String result = '';
+ for (int i = 0; i < end; i += kMaxApply) {
+ int chunkEnd = (i + kMaxApply < end) ? i + kMaxApply : end;
+ result = JS(
+ 'String',
+ r'# + String.fromCharCode.apply(null, #.slice(#, #))',
+ result,
+ array,
+ i,
+ chunkEnd);
+ }
+ return result;
+ }
+
+ static String stringFromCodePoints(codePoints) {
+ List<int> a = <int>[];
+ for (var i in codePoints) {
+ if (i is! int) throw argumentErrorValue(i);
+ if (i <= 0xffff) {
+ a.add(i);
+ } else if (i <= 0x10ffff) {
+ a.add(0xd800 + ((((i - 0x10000) >> 10) & 0x3ff)));
+ a.add(0xdc00 + (i & 0x3ff));
+ } else {
+ throw argumentErrorValue(i);
+ }
+ }
+ return _fromCharCodeApply(a);
+ }
+
+ static String stringFromCharCodes(charCodes) {
+ for (var i in charCodes) {
+ if (i is! int) throw argumentErrorValue(i);
+ if (i < 0) throw argumentErrorValue(i);
+ if (i > 0xffff) return stringFromCodePoints(charCodes);
+ }
+ return _fromCharCodeApply(charCodes);
+ }
+
+ // [start] and [end] are validated.
+ static String stringFromNativeUint8List(
+ NativeUint8List charCodes, int start, int end) {
+ const kMaxApply = 500;
+ if (end <= kMaxApply && start == 0 && end == charCodes.length) {
+ return JS('String', r'String.fromCharCode.apply(null, #)', charCodes);
+ }
+ String result = '';
+ for (int i = start; i < end; i += kMaxApply) {
+ int chunkEnd = (i + kMaxApply < end) ? i + kMaxApply : end;
+ result = JS(
+ 'String',
+ r'# + String.fromCharCode.apply(null, #.subarray(#, #))',
+ result,
+ charCodes,
+ i,
+ chunkEnd);
+ }
+ return result;
+ }
+
+ static String stringFromCharCode(charCode) {
+ if (0 <= charCode) {
+ if (charCode <= 0xffff) {
+ return JS('returns:String;effects:none;depends:none',
+ 'String.fromCharCode(#)', charCode);
+ }
+ if (charCode <= 0x10ffff) {
+ var bits = charCode - 0x10000;
+ var low = 0xDC00 | (bits & 0x3ff);
+ var high = 0xD800 | (bits >> 10);
+ return JS('returns:String;effects:none;depends:none',
+ 'String.fromCharCode(#, #)', high, low);
+ }
+ }
+ throw new RangeError.range(charCode, 0, 0x10ffff);
+ }
+
+ static String stringConcatUnchecked(String string1, String string2) {
+ return JS_STRING_CONCAT(string1, string2);
+ }
+
+ static String flattenString(String str) {
+ return JS('returns:String;depends:none;effects:none;throws:never;gvn:true',
+ '#.charCodeAt(0) == 0 ? # : #', str, str, str);
+ }
+
+ static String getTimeZoneName(DateTime receiver) {
+ // Firefox and Chrome emit the timezone in parenthesis.
+ // Example: "Wed May 16 2012 21:13:00 GMT+0200 (CEST)".
+ // We extract this name using a regexp.
+ var d = lazyAsJsDate(receiver);
+ List match = JS('JSArray|Null', r'/\((.*)\)/.exec(#.toString())', d);
+ if (match != null) return match[1];
+
+ // Internet Explorer 10+ emits the zone name without parenthesis:
+ // Example: Thu Oct 31 14:07:44 PDT 2013
+ match = JS(
+ 'JSArray|Null',
+ // Thu followed by a space.
+ r'/^[A-Z,a-z]{3}\s'
+ // Oct 31 followed by space.
+ r'[A-Z,a-z]{3}\s\d+\s'
+ // Time followed by a space.
+ r'\d{2}:\d{2}:\d{2}\s'
+ // The time zone name followed by a space.
+ r'([A-Z]{3,5})\s'
+ // The year.
+ r'\d{4}$/'
+ '.exec(#.toString())',
+ d);
+ if (match != null) return match[1];
+
+ // IE 9 and Opera don't provide the zone name. We fall back to emitting the
+ // UTC/GMT offset.
+ // Example (IE9): Wed Nov 20 09:51:00 UTC+0100 2013
+ // (Opera): Wed Nov 20 2013 11:03:38 GMT+0100
+ match = JS('JSArray|Null', r'/(?:GMT|UTC)[+-]\d{4}/.exec(#.toString())', d);
+ if (match != null) return match[0];
+ return '';
+ }
+
+ static int getTimeZoneOffsetInMinutes(DateTime receiver) {
+ // Note that JS and Dart disagree on the sign of the offset.
+ // Subtract to avoid -0.0
+ return 0 - JS('int', r'#.getTimezoneOffset()', lazyAsJsDate(receiver));
+ }
+
+ static int valueFromDecomposedDate(
+ years, month, day, hours, minutes, seconds, milliseconds, isUtc) {
+ final int MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000;
+ checkInt(years);
+ checkInt(month);
+ checkInt(day);
+ checkInt(hours);
+ checkInt(minutes);
+ checkInt(seconds);
+ checkInt(milliseconds);
+ checkBool(isUtc);
+ var jsMonth = month - 1;
+ // The JavaScript Date constructor 'corrects' year NN to 19NN. Sidestep that
+ // correction by adjusting years out of that range and compensating with an
+ // adjustment of months. This hack should not be sensitive to leap years but
+ // use 400 just in case.
+ if (0 <= years && years < 100) {
+ years += 400;
+ jsMonth -= 400 * 12;
+ }
+ var value;
+ if (isUtc) {
+ value = JS('num', r'Date.UTC(#, #, #, #, #, #, #)', years, jsMonth, day,
+ hours, minutes, seconds, milliseconds);
+ } else {
+ value = JS('num', r'new Date(#, #, #, #, #, #, #).valueOf()', years,
+ jsMonth, day, hours, minutes, seconds, milliseconds);
+ }
+ if (value.isNaN ||
+ value < -MAX_MILLISECONDS_SINCE_EPOCH ||
+ value > MAX_MILLISECONDS_SINCE_EPOCH) {
+ return null;
+ }
+ return JS('int', '#', value);
+ }
+
+ // Lazily keep a JS Date stored in the JS object.
+ static lazyAsJsDate(DateTime receiver) {
+ if (JS('bool', r'#.date === (void 0)', receiver)) {
+ JS('void', r'#.date = new Date(#)', receiver,
+ receiver.millisecondsSinceEpoch);
+ }
+ return JS('var', r'#.date', receiver);
+ }
+
+ // The getters for date and time parts below add a positive integer to ensure
+ // that the result is really an integer, because the JavaScript implementation
+ // may return -0.0 instead of 0.
+ //
+ // They are marked as @pragma('dart2js:noThrows') because `receiver` comes from a receiver of
+ // a method on DateTime (i.e. is not `null`).
+
+ // TODO(sra): These methods are GVN-able. dart2js should implement an
+ // annotation for that.
+
+ // TODO(sra): These methods often occur in groups (e.g. day, month and
+ // year). Is it possible to factor them so that the `Date` is visible and can
+ // be GVN-ed without a lot of code bloat?
+
+ @pragma('dart2js:noSideEffects')
+ @pragma('dart2js:noThrows')
+ @pragma('dart2js:noInline')
+ static getYear(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS('int', r'(#.getUTCFullYear() + 0)', lazyAsJsDate(receiver))
+ : JS('int', r'(#.getFullYear() + 0)', lazyAsJsDate(receiver));
+ }
+
+ @pragma('dart2js:noSideEffects')
+ @pragma('dart2js:noThrows')
+ @pragma('dart2js:noInline')
+ static getMonth(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS('JSUInt31', r'#.getUTCMonth() + 1', lazyAsJsDate(receiver))
+ : JS('JSUInt31', r'#.getMonth() + 1', lazyAsJsDate(receiver));
+ }
+
+ @pragma('dart2js:noSideEffects')
+ @pragma('dart2js:noThrows')
+ @pragma('dart2js:noInline')
+ static getDay(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS('JSUInt31', r'(#.getUTCDate() + 0)', lazyAsJsDate(receiver))
+ : JS('JSUInt31', r'(#.getDate() + 0)', lazyAsJsDate(receiver));
+ }
+
+ @pragma('dart2js:noSideEffects')
+ @pragma('dart2js:noThrows')
+ @pragma('dart2js:noInline')
+ static getHours(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS('JSUInt31', r'(#.getUTCHours() + 0)', lazyAsJsDate(receiver))
+ : JS('JSUInt31', r'(#.getHours() + 0)', lazyAsJsDate(receiver));
+ }
+
+ @pragma('dart2js:noSideEffects')
+ @pragma('dart2js:noThrows')
+ @pragma('dart2js:noInline')
+ static getMinutes(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS('JSUInt31', r'(#.getUTCMinutes() + 0)', lazyAsJsDate(receiver))
+ : JS('JSUInt31', r'(#.getMinutes() + 0)', lazyAsJsDate(receiver));
+ }
+
+ @pragma('dart2js:noSideEffects')
+ @pragma('dart2js:noThrows')
+ @pragma('dart2js:noInline')
+ static getSeconds(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS('JSUInt31', r'(#.getUTCSeconds() + 0)', lazyAsJsDate(receiver))
+ : JS('JSUInt31', r'(#.getSeconds() + 0)', lazyAsJsDate(receiver));
+ }
+
+ @pragma('dart2js:noSideEffects')
+ @pragma('dart2js:noThrows')
+ @pragma('dart2js:noInline')
+ static getMilliseconds(DateTime receiver) {
+ return (receiver.isUtc)
+ ? JS(
+ 'JSUInt31', r'(#.getUTCMilliseconds() + 0)', lazyAsJsDate(receiver))
+ : JS('JSUInt31', r'(#.getMilliseconds() + 0)', lazyAsJsDate(receiver));
+ }
+
+ @pragma('dart2js:noSideEffects')
+ @pragma('dart2js:noThrows')
+ @pragma('dart2js:noInline')
+ static getWeekday(DateTime receiver) {
+ int weekday = (receiver.isUtc)
+ ? JS('int', r'#.getUTCDay() + 0', lazyAsJsDate(receiver))
+ : JS('int', r'#.getDay() + 0', lazyAsJsDate(receiver));
+ // Adjust by one because JS weeks start on Sunday.
+ return (weekday + 6) % 7 + 1;
+ }
+
+ static valueFromDateString(str) {
+ if (str is! String) throw argumentErrorValue(str);
+ var value = JS('num', r'Date.parse(#)', str);
+ if (value.isNaN) throw argumentErrorValue(str);
+ return value;
+ }
+
+ static getProperty(object, key) {
+ if (object == null || object is bool || object is num || object is String) {
+ throw argumentErrorValue(object);
+ }
+ return JS('var', '#[#]', object, key);
+ }
+
+ static void setProperty(object, key, value) {
+ if (object == null || object is bool || object is num || object is String) {
+ throw argumentErrorValue(object);
+ }
+ JS('void', '#[#] = #', object, key, value);
+ }
+
+ static functionNoSuchMethod(
+ function, List positionalArguments, Map<String, dynamic> namedArguments) {
+ int argumentCount = 0;
+ List arguments = [];
+ List namedArgumentList = [];
+
+ if (positionalArguments != null) {
+ argumentCount += positionalArguments.length;
+ arguments.addAll(positionalArguments);
+ }
+
+ String names = '';
+ if (namedArguments != null && !namedArguments.isEmpty) {
+ namedArguments.forEach((String name, argument) {
+ names = '$names\$$name';
+ namedArgumentList.add(name);
+ arguments.add(argument);
+ argumentCount++;
+ });
+ }
+
+ String selectorName =
+ '${JS_GET_NAME(JsGetName.CALL_PREFIX)}\$$argumentCount$names';
+
+ return function.noSuchMethod(createUnmangledInvocationMirror(
+ #call,
+ selectorName,
+ JSInvocationMirror.METHOD,
+ arguments,
+ namedArgumentList,
+ 0));
+ }
+
+ /// Implements [Function.apply] for the lazy and startup emitters.
+ ///
+ /// There are two types of closures that can reach this function:
+ ///
+ /// 1. tear-offs (including tear-offs of static functions).
+ /// 2. anonymous closures.
+ ///
+ /// They are treated differently (although there are lots of similarities).
+ /// Both have in common that they have
+ /// a [JsGetName.CALL_CATCH_ALL] and
+ /// a [JsGetName.REQUIRED_PARAMETER_PROPERTY] property.
+ ///
+ /// If the closure supports optional parameters, then they also feature
+ /// a [JsGetName.DEFAULT_VALUES_PROPERTY] property.
+ ///
+ /// The catch-all property is a method that takes all arguments (including
+ /// all optional positional or named arguments). If the function accepts
+ /// optional arguments, then the default-values property stores (potentially
+ /// wrapped in a function) the default values for the optional arguments. If
+ /// the function accepts optional positional arguments, then the value is a
+ /// JavaScript array with the default values. Otherwise, when the function
+ /// accepts optional named arguments, it is a JavaScript object.
+ ///
+ /// The default-values property may either contain the value directly, or
+ /// it can be a function that returns the default-values when invoked.
+ ///
+ /// If the function is an anonymous closure, then the catch-all property
+ /// only contains a string pointing to the property that should be used
+ /// instead. For example, if the catch-all property contains the string
+ /// "call$4", then the object's "call$4" property should be used as if it was
+ /// the value of the catch-all property.
+ static applyFunction(Function function, List positionalArguments,
+ Map<String, dynamic> namedArguments) {
+ // Fast shortcut for the common case.
+ if (JS('bool', '# instanceof Array', positionalArguments) &&
+ (namedArguments == null || namedArguments.isEmpty)) {
+ // Let the compiler know that we did a type-test.
+ List arguments = (JS('JSArray', '#', positionalArguments));
+ int argumentCount = arguments.length;
+ if (argumentCount == 0) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX0);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#]()', function, selectorName);
+ }
+ } else if (argumentCount == 1) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX1);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#](#[0])', function, selectorName, arguments);
+ }
+ } else if (argumentCount == 2) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX2);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#](#[0],#[1])', function, selectorName, arguments,
+ arguments);
+ }
+ } else if (argumentCount == 3) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX3);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#](#[0],#[1],#[2])', function, selectorName,
+ arguments, arguments, arguments);
+ }
+ } else if (argumentCount == 4) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX4);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#](#[0],#[1],#[2],#[3])', function, selectorName,
+ arguments, arguments, arguments, arguments);
+ }
+ } else if (argumentCount == 5) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX5);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS(
+ '',
+ '#[#](#[0],#[1],#[2],#[3],#[4])',
+ function,
+ selectorName,
+ arguments,
+ arguments,
+ arguments,
+ arguments,
+ arguments);
+ }
+ }
+ String selectorName =
+ '${JS_GET_NAME(JsGetName.CALL_PREFIX)}\$$argumentCount';
+ var jsStub = JS('var', r'#[#]', function, selectorName);
+ if (jsStub != null) {
+ return JS('var', '#.apply(#, #)', jsStub, function, arguments);
+ }
+ }
+
+ return _genericApplyFunction2(
+ function, positionalArguments, namedArguments);
+ }
+
+ static _genericApplyFunction2(Function function, List positionalArguments,
+ Map<String, dynamic> namedArguments) {
+ List arguments;
+ if (positionalArguments != null) {
+ if (JS('bool', '# instanceof Array', positionalArguments)) {
+ arguments = JS('JSArray', '#', positionalArguments);
+ } else {
+ arguments = new List.from(positionalArguments);
+ }
+ } else {
+ arguments = [];
+ }
+
+ int argumentCount = arguments.length;
+
+ int requiredParameterCount = JS('int', r'#[#]', function,
+ JS_GET_NAME(JsGetName.REQUIRED_PARAMETER_PROPERTY));
+
+ if (argumentCount < requiredParameterCount) {
+ return functionNoSuchMethod(function, arguments, namedArguments);
+ }
+
+ var defaultValuesClosure = JS('var', r'#[#]', function,
+ JS_GET_NAME(JsGetName.DEFAULT_VALUES_PROPERTY));
+
+ bool acceptsOptionalArguments = defaultValuesClosure != null;
+
+ // Default values are stored inside a JavaScript closure to avoid
+ // accessing them too early.
+ var defaultValues =
+ acceptsOptionalArguments ? JS('', '#()', defaultValuesClosure) : null;
+
+ var interceptor = getInterceptor(function);
+ var jsFunction =
+ JS('', '#[#]', interceptor, JS_GET_NAME(JsGetName.CALL_CATCH_ALL));
+ if (jsFunction is String) {
+ // Anonymous closures redirect to the catch-all property instead of
+ // storing the catch-all method directly in the catch-all property.
+ jsFunction = JS('', '#[#]', interceptor, jsFunction);
+ }
+
+ if (!acceptsOptionalArguments) {
+ if (namedArguments != null && namedArguments.isNotEmpty) {
+ // Tried to invoke a function that takes a fixed number of arguments
+ // with named (optional) arguments.
+ return functionNoSuchMethod(function, arguments, namedArguments);
+ }
+ if (argumentCount == requiredParameterCount) {
+ return JS('var', r'#.apply(#, #)', jsFunction, function, arguments);
+ }
+ return functionNoSuchMethod(function, arguments, namedArguments);
+ }
+
+ bool acceptsPositionalArguments =
+ JS('bool', '# instanceof Array', defaultValues);
+
+ if (acceptsPositionalArguments) {
+ if (namedArguments != null && namedArguments.isNotEmpty) {
+ // Tried to invoke a function that takes optional positional arguments
+ // with named arguments.
+ return functionNoSuchMethod(function, arguments, namedArguments);
+ }
+
+ int defaultsLength = JS('int', '#.length', defaultValues);
+ int maxArguments = requiredParameterCount + defaultsLength;
+ if (argumentCount > maxArguments) {
+ // The function expects fewer arguments.
+ return functionNoSuchMethod(function, arguments, null);
+ }
+ List missingDefaults = JS('JSArray', '#.slice(#)', defaultValues,
+ argumentCount - requiredParameterCount);
+ arguments.addAll(missingDefaults);
+ return JS('var', '#.apply(#, #)', jsFunction, function, arguments);
+ } else {
+ // Handle named arguments.
+
+ if (argumentCount > requiredParameterCount) {
+ // Tried to invoke a function that takes named parameters with
+ // too many positional arguments.
+ return functionNoSuchMethod(function, arguments, namedArguments);
+ }
+
+ List keys = JS('JSArray', r'Object.keys(#)', defaultValues);
+ if (namedArguments == null) {
+ for (String key in keys) {
+ arguments.add(JS('var', '#[#]', defaultValues, key));
+ }
+ } else {
+ int used = 0;
+ for (String key in keys) {
+ if (namedArguments.containsKey(key)) {
+ used++;
+ arguments.add(namedArguments[key]);
+ } else {
+ arguments.add(JS('var', r'#[#]', defaultValues, key));
+ }
+ }
+ if (used != namedArguments.length) {
+ return functionNoSuchMethod(function, arguments, namedArguments);
+ }
+ }
+ return JS('var', r'#.apply(#, #)', jsFunction, function, arguments);
+ }
+ }
+
+ static StackTrace extractStackTrace(Error error) {
+ return getTraceFromException(JS('', r'#.$thrownJsError', error));
+ }
+}
+
+/// Helper class for allocating and using JS object literals as caches.
+class JsCache {
+ /// Returns a JavaScript object suitable for use as a cache.
+ static allocate() {
+ var result = JS('=Object', 'Object.create(null)');
+ // Deleting a property makes V8 assume that it shouldn't create a hidden
+ // class for [result] and map transitions. Although these map transitions
+ // pay off if there are many cache hits for the same keys, it becomes
+ // really slow when there aren't many repeated hits.
+ JS('void', '#.x=0', result);
+ JS('void', 'delete #.x', result);
+ return result;
+ }
+
+ static fetch(cache, String key) {
+ return JS('', '#[#]', cache, key);
+ }
+
+ static void update(cache, String key, value) {
+ JS('void', '#[#] = #', cache, key, value);
+ }
+}
+
+/// Called by generated code to throw an illegal-argument exception,
+/// for example, if a non-integer index is given to an optimized
+/// indexed access.
+@pragma('dart2js:noInline')
+iae(argument) {
+ throw argumentErrorValue(argument);
+}
+
+/// Called by generated code to throw an index-out-of-range exception, for
+/// example, if a bounds check fails in an optimized indexed access. This may
+/// also be called when the index is not an integer, in which case it throws an
+/// illegal-argument exception instead, like [iae], or when the receiver is
+/// null.
+@pragma('dart2js:noInline')
+ioore(receiver, index) {
+ if (receiver == null) receiver.length; // Force a NoSuchMethodError.
+ throw diagnoseIndexError(receiver, index);
+}
+
+/// Diagnoses an indexing error. Returns the ArgumentError or RangeError that
+/// describes the problem.
+@pragma('dart2js:noInline')
+Error diagnoseIndexError(indexable, index) {
+ if (index is! int) return new ArgumentError.value(index, 'index');
+ int length = indexable.length;
+ // The following returns the same error that would be thrown by calling
+ // [RangeError.checkValidIndex] with no optional parameters provided.
+ if (index < 0 || index >= length) {
+ return new RangeError.index(index, indexable, 'index', null, length);
+ }
+ // The above should always match, but if it does not, use the following.
+ return new RangeError.value(index, 'index');
+}
+
+/// Diagnoses a range error. Returns the ArgumentError or RangeError that
+/// describes the problem.
+@pragma('dart2js:noInline')
+Error diagnoseRangeError(start, end, length) {
+ if (start is! int) {
+ return new ArgumentError.value(start, 'start');
+ }
+ if (start < 0 || start > length) {
+ return new RangeError.range(start, 0, length, 'start');
+ }
+ if (end != null) {
+ if (end is! int) {
+ return new ArgumentError.value(end, 'end');
+ }
+ if (end < start || end > length) {
+ return new RangeError.range(end, start, length, 'end');
+ }
+ }
+ // The above should always match, but if it does not, use the following.
+ return new ArgumentError.value(end, 'end');
+}
+
+stringLastIndexOfUnchecked(receiver, element, start) =>
+ JS('int', r'#.lastIndexOf(#, #)', receiver, element, start);
+
+/// 'factory' for constructing ArgumentError.value to keep the call sites small.
+@pragma('dart2js:noInline')
+ArgumentError argumentErrorValue(object) {
+ return new ArgumentError.value(object);
+}
+
+checkNull(object) {
+ if (object == null) throw argumentErrorValue(object);
+ return object;
+}
+
+@pragma('dart2js:noInline')
+num checkNum(value) {
+ if (value is! num) throw argumentErrorValue(value);
+ return value;
+}
+
+int checkInt(value) {
+ if (value is! int) throw argumentErrorValue(value);
+ return value;
+}
+
+bool checkBool(value) {
+ if (value is! bool) throw argumentErrorValue(value);
+ return value;
+}
+
+String checkString(value) {
+ if (value is! String) throw argumentErrorValue(value);
+ return value;
+}
+
+/// Wrap the given Dart object and record a stack trace.
+///
+/// The code in [unwrapException] deals with getting the original Dart
+/// object out of the wrapper again.
+@pragma('dart2js:noInline')
+wrapException(ex) {
+ if (ex == null) ex = new NullThrownError();
+ var wrapper = JS('', 'new Error()');
+ // [unwrapException] looks for the property 'dartException'.
+ JS('void', '#.dartException = #', wrapper, ex);
+
+ if (JS('bool', '"defineProperty" in Object')) {
+ // Define a JavaScript getter for 'message'. This is to work around V8 bug
+ // (https://code.google.com/p/v8/issues/detail?id=2519). The default
+ // toString on Error returns the value of 'message' if 'name' is
+ // empty. Setting toString directly doesn't work, see the bug.
+ JS('void', 'Object.defineProperty(#, "message", { get: # })', wrapper,
+ DART_CLOSURE_TO_JS(toStringWrapper));
+ JS('void', '#.name = ""', wrapper);
+ } else {
+ // In the unlikely event the browser doesn't support Object.defineProperty,
+ // hope that it just calls toString.
+ JS('void', '#.toString = #', wrapper, DART_CLOSURE_TO_JS(toStringWrapper));
+ }
+
+ return wrapper;
+}
+
+/// Do not call directly.
+toStringWrapper() {
+ // This method gets installed as toString on a JavaScript object. Due to the
+ // weird scope rules of JavaScript, JS 'this' will refer to that object.
+ return JS('', r'this.dartException').toString();
+}
+
+/// This wraps the exception and does the throw. It is possible to call this in
+/// a JS expression context, where the throw statement is not allowed. Helpers
+/// are never inlined, so we don't risk inlining the throw statement into an
+/// expression context.
+throwExpression(ex) {
+ JS('void', 'throw #', wrapException(ex));
+}
+
+throwRuntimeError(message) {
+ throw new RuntimeError(message);
+}
+
+throwUnsupportedError(message) {
+ throw new UnsupportedError(message);
+}
+
+throwAbstractClassInstantiationError(className) {
+ throw new AbstractClassInstantiationError(className);
+}
+
+// This is used in open coded for-in loops on arrays.
+//
+// checkConcurrentModificationError(a.length == startLength, a)
+//
+// is replaced in codegen by:
+//
+// a.length == startLength || throwConcurrentModificationError(a)
+//
+// TODO(sra): We would like to annotate this as @pragma('dart2js:noSideEffects') so that loops
+// with no other effects can recognize that the array length does not
+// change. However, in the usual case where the loop does have other effects,
+// that causes the length in the loop condition to be phi(startLength,a.length),
+// which causes confusion in range analysis and the insertion of a bounds check.
+@pragma('dart2js:noInline')
+checkConcurrentModificationError(sameLength, collection) {
+ if (true != sameLength) {
+ throwConcurrentModificationError(collection);
+ }
+}
+
+@pragma('dart2js:noInline')
+throwConcurrentModificationError(collection) {
+ throw new ConcurrentModificationError(collection);
+}
+
+/// Helper class for building patterns recognizing native type errors.
+class TypeErrorDecoder {
+ // Field names are private to help tree-shaking.
+
+ /// A regular expression which matches is matched against an error message.
+ final String _pattern;
+
+ /// The group index of "arguments" in [_pattern], or -1 if _pattern has no
+ /// match for "arguments".
+ final int _arguments;
+
+ /// The group index of "argumentsExpr" in [_pattern], or -1 if _pattern has
+ /// no match for "argumentsExpr".
+ final int _argumentsExpr;
+
+ /// The group index of "expr" in [_pattern], or -1 if _pattern has no match
+ /// for "expr".
+ final int _expr;
+
+ /// The group index of "method" in [_pattern], or -1 if _pattern has no match
+ /// for "method".
+ final int _method;
+
+ /// The group index of "receiver" in [_pattern], or -1 if _pattern has no
+ /// match for "receiver".
+ final int _receiver;
+
+ /// Pattern used to recognize a NoSuchMethodError error (and
+ /// possibly extract the method name).
+ static final TypeErrorDecoder noSuchMethodPattern =
+ extractPattern(provokeCallErrorOn(buildJavaScriptObject()));
+
+ /// Pattern used to recognize an "object not a closure" error (and
+ /// possibly extract the method name).
+ static final TypeErrorDecoder notClosurePattern =
+ extractPattern(provokeCallErrorOn(buildJavaScriptObjectWithNonClosure()));
+
+ /// Pattern used to recognize a NoSuchMethodError on JavaScript null
+ /// call.
+ static final TypeErrorDecoder nullCallPattern =
+ extractPattern(provokeCallErrorOn(JS('', 'null')));
+
+ /// Pattern used to recognize a NoSuchMethodError on JavaScript literal null
+ /// call.
+ static final TypeErrorDecoder nullLiteralCallPattern =
+ extractPattern(provokeCallErrorOnNull());
+
+ /// Pattern used to recognize a NoSuchMethodError on JavaScript
+ /// undefined call.
+ static final TypeErrorDecoder undefinedCallPattern =
+ extractPattern(provokeCallErrorOn(JS('', 'void 0')));
+
+ /// Pattern used to recognize a NoSuchMethodError on JavaScript literal
+ /// undefined call.
+ static final TypeErrorDecoder undefinedLiteralCallPattern =
+ extractPattern(provokeCallErrorOnUndefined());
+
+ /// Pattern used to recognize a NoSuchMethodError on JavaScript null
+ /// property access.
+ static final TypeErrorDecoder nullPropertyPattern =
+ extractPattern(provokePropertyErrorOn(JS('', 'null')));
+
+ /// Pattern used to recognize a NoSuchMethodError on JavaScript literal null
+ /// property access.
+ static final TypeErrorDecoder nullLiteralPropertyPattern =
+ extractPattern(provokePropertyErrorOnNull());
+
+ /// Pattern used to recognize a NoSuchMethodError on JavaScript
+ /// undefined property access.
+ static final TypeErrorDecoder undefinedPropertyPattern =
+ extractPattern(provokePropertyErrorOn(JS('', 'void 0')));
+
+ /// Pattern used to recognize a NoSuchMethodError on JavaScript literal
+ /// undefined property access.
+ static final TypeErrorDecoder undefinedLiteralPropertyPattern =
+ extractPattern(provokePropertyErrorOnUndefined());
+
+ TypeErrorDecoder(this._arguments, this._argumentsExpr, this._expr,
+ this._method, this._receiver, this._pattern);
+
+ /// Returns a JavaScript object literal (map) with at most the
+ /// following keys:
+ ///
+ /// * arguments: The arguments as formatted by the JavaScript
+ /// engine. No browsers are known to provide this information.
+ ///
+ /// * argumentsExpr: The syntax of the arguments (JavaScript source
+ /// code). No browsers are known to provide this information.
+ ///
+ /// * expr: The syntax of the receiver expression (JavaScript source
+ /// code). Firefox provides this information, for example: "$expr$.$method$
+ /// is not a function".
+ ///
+ /// * method: The name of the called method (mangled name). At least Firefox
+ /// and Chrome/V8 provides this information, for example, "Object [object
+ /// Object] has no method '$method$'".
+ ///
+ /// * receiver: The string representation of the receiver. Chrome/V8
+ /// used to provide this information (by calling user-defined
+ /// JavaScript toString on receiver), but it has degenerated into
+ /// "[object Object]" in recent versions.
+ matchTypeError(message) {
+ var match = JS(
+ 'JSExtendableArray|Null', 'new RegExp(#).exec(#)', _pattern, message);
+ if (match == null) return null;
+ var result = JS('', 'Object.create(null)');
+ if (_arguments != -1) {
+ JS('', '#.arguments = #[# + 1]', result, match, _arguments);
+ }
+ if (_argumentsExpr != -1) {
+ JS('', '#.argumentsExpr = #[# + 1]', result, match, _argumentsExpr);
+ }
+ if (_expr != -1) {
+ JS('', '#.expr = #[# + 1]', result, match, _expr);
+ }
+ if (_method != -1) {
+ JS('', '#.method = #[# + 1]', result, match, _method);
+ }
+ if (_receiver != -1) {
+ JS('', '#.receiver = #[# + 1]', result, match, _receiver);
+ }
+
+ return result;
+ }
+
+ /// Builds a JavaScript Object with a toString method saying
+ /// r"$receiver$".
+ static buildJavaScriptObject() {
+ return JS('', r'{ toString: function() { return "$receiver$"; } }');
+ }
+
+ /// Builds a JavaScript Object with a toString method saying
+ /// r"$receiver$". The property "$method" is defined, but is not a function.
+ static buildJavaScriptObjectWithNonClosure() {
+ return JS(
+ '',
+ r'{ $method$: null, '
+ r'toString: function() { return "$receiver$"; } }');
+ }
+
+ /// Extract a pattern from a JavaScript TypeError message.
+ ///
+ /// The patterns are extracted by forcing TypeErrors on known
+ /// objects thus forcing known strings into the error message. The
+ /// known strings are then replaced with wildcards which in theory
+ /// makes it possible to recognize the desired information even if
+ /// the error messages are reworded or translated.
+ static extractPattern(String message) {
+ // Some JavaScript implementations (V8 at least) include a
+ // representation of the receiver in the error message, however,
+ // this representation is not always [: receiver.toString() :],
+ // sometimes it is [: Object.prototype.toString(receiver) :], and
+ // sometimes it is an implementation specific method (but that
+ // doesn't seem to happen for object literals). So sometimes we
+ // get the text "[object Object]". The shortest way to get that
+ // string is using "String({})".
+ // See: http://code.google.com/p/v8/issues/detail?id=2519.
+ message = JS('String', r"#.replace(String({}), '$receiver$')", message);
+
+ // Since we want to create a new regular expression from an unknown string,
+ // we must escape all regular expression syntax.
+ message = quoteStringForRegExp(message);
+
+ // Look for the special pattern \$camelCase\$ (all the $ symbols
+ // have been escaped already), as we will soon be inserting
+ // regular expression syntax that we want interpreted by RegExp.
+ List<String> match =
+ JS('JSExtendableArray|Null', r'#.match(/\\\$[a-zA-Z]+\\\$/g)', message);
+ if (match == null) match = [];
+
+ // Find the positions within the substring matches of the error message
+ // components. This will help us extract information later, such as the
+ // method name.
+ int arguments = JS('int', '#.indexOf(#)', match, r'\$arguments\$');
+ int argumentsExpr = JS('int', '#.indexOf(#)', match, r'\$argumentsExpr\$');
+ int expr = JS('int', '#.indexOf(#)', match, r'\$expr\$');
+ int method = JS('int', '#.indexOf(#)', match, r'\$method\$');
+ int receiver = JS('int', '#.indexOf(#)', match, r'\$receiver\$');
+
+ // Replace the patterns with a regular expression wildcard.
+ // Note: in a perfect world, one would use "(.*)", but not in
+ // JavaScript, "." does not match newlines.
+ String pattern = JS(
+ 'String',
+ r"#.replace(new RegExp('\\\\\\$arguments\\\\\\$', 'g'), "
+ r"'((?:x|[^x])*)')"
+ r".replace(new RegExp('\\\\\\$argumentsExpr\\\\\\$', 'g'), "
+ r"'((?:x|[^x])*)')"
+ r".replace(new RegExp('\\\\\\$expr\\\\\\$', 'g'), '((?:x|[^x])*)')"
+ r".replace(new RegExp('\\\\\\$method\\\\\\$', 'g'), '((?:x|[^x])*)')"
+ r".replace(new RegExp('\\\\\\$receiver\\\\\\$', 'g'), "
+ r"'((?:x|[^x])*)')",
+ message);
+
+ return new TypeErrorDecoder(
+ arguments, argumentsExpr, expr, method, receiver, pattern);
+ }
+
+ /// Provokes a TypeError and returns its message.
+ ///
+ /// The error is provoked so all known variable content can be recognized and
+ /// a pattern can be inferred.
+ static String provokeCallErrorOn(expression) {
+ // This function is carefully created to maximize the possibility
+ // of decoding the TypeError message and turning it into a general
+ // pattern.
+ //
+ // The idea is to inject something known into something unknown. The
+ // unknown entity is the error message that the browser provides with a
+ // TypeError. It is a human readable message, possibly localized in a
+ // language no dart2js engineer understand. We assume that $name$ would
+ // never naturally occur in a human readable error message, yet it is easy
+ // to decode.
+ //
+ // For example, evaluate this in V8 version 3.13.7.6:
+ //
+ // var $expr$ = null; $expr$.$method$()
+ //
+ // The VM throws an instance of TypeError whose message property contains
+ // "Cannot call method '$method$' of null". We can then reasonably assume
+ // that if the string contains $method$, that's where the method name will
+ // be in general. Call this automatically reverse engineering the error
+ // format string in V8.
+ //
+ // So the error message from V8 is turned into this regular expression:
+ //
+ // "Cannot call method '(.*)' of null"
+ //
+ // Similarly, if we evaluate:
+ //
+ // var $expr$ = {toString: function() { return '$receiver$'; }};
+ // $expr$.$method$()
+ //
+ // We get this message: "Object $receiver$ has no method '$method$'"
+ //
+ // Which is turned into this regular expression:
+ //
+ // "Object (.*) has no method '(.*)'"
+ //
+ // Firefox/jsshell is slightly different, it tries to include the source
+ // code that caused the exception, so we get this message: "$expr$.$method$
+ // is not a function" which is turned into this regular expression:
+ //
+ // "(.*)\\.(.*) is not a function"
+
+ var function = JS('', r"""function($expr$) {
+ var $argumentsExpr$ = '$arguments$';
+ try {
+ $expr$.$method$($argumentsExpr$);
+ } catch (e) {
+ return e.message;
+ }
+}""");
+ return JS('String', '(#)(#)', function, expression);
+ }
+
+ /// Similar to [provokeCallErrorOn], but provokes an error directly on
+ /// literal "null" expression.
+ static String provokeCallErrorOnNull() {
+ // See [provokeCallErrorOn] for a detailed explanation.
+ var function = JS('', r"""function() {
+ var $argumentsExpr$ = '$arguments$';
+ try {
+ null.$method$($argumentsExpr$);
+ } catch (e) {
+ return e.message;
+ }
+}""");
+ return JS('String', '(#)()', function);
+ }
+
+ /// Similar to [provokeCallErrorOnNull], but provokes an error directly on
+ /// (void 0), that is, "undefined".
+ static String provokeCallErrorOnUndefined() {
+ // See [provokeCallErrorOn] for a detailed explanation.
+ var function = JS('', r"""function() {
+ var $argumentsExpr$ = '$arguments$';
+ try {
+ (void 0).$method$($argumentsExpr$);
+ } catch (e) {
+ return e.message;
+ }
+}""");
+ return JS('String', '(#)()', function);
+ }
+
+ /// Similar to [provokeCallErrorOn], but provokes a property access
+ /// error.
+ static String provokePropertyErrorOn(expression) {
+ // See [provokeCallErrorOn] for a detailed explanation.
+ var function = JS('', r"""function($expr$) {
+ try {
+ $expr$.$method$;
+ } catch (e) {
+ return e.message;
+ }
+}""");
+ return JS('String', '(#)(#)', function, expression);
+ }
+
+ /// Similar to [provokePropertyErrorOn], but provokes an property access
+ /// error directly on literal "null" expression.
+ static String provokePropertyErrorOnNull() {
+ // See [provokeCallErrorOn] for a detailed explanation.
+ var function = JS('', r"""function() {
+ try {
+ null.$method$;
+ } catch (e) {
+ return e.message;
+ }
+}""");
+ return JS('String', '(#)()', function);
+ }
+
+ /// Similar to [provokePropertyErrorOnNull], but provokes an property access
+ /// error directly on (void 0), that is, "undefined".
+ static String provokePropertyErrorOnUndefined() {
+ // See [provokeCallErrorOn] for a detailed explanation.
+ var function = JS('', r"""function() {
+ try {
+ (void 0).$method$;
+ } catch (e) {
+ return e.message;
+ }
+}""");
+ return JS('String', '(#)()', function);
+ }
+}
+
+class NullError extends Error implements NoSuchMethodError {
+ final String _message;
+ final String _method;
+
+ NullError(this._message, match)
+ : _method = match == null ? null : JS('', '#.method', match);
+
+ String toString() {
+ if (_method == null) return 'NoSuchMethodError: $_message';
+ return "NoSuchMethodError: method not found: '$_method' on null";
+ }
+}
+
+class JsNoSuchMethodError extends Error implements NoSuchMethodError {
+ final String _message;
+ final String _method;
+ final String _receiver;
+
+ JsNoSuchMethodError(this._message, match)
+ : _method = match == null ? null : JS('String|Null', '#.method', match),
+ _receiver =
+ match == null ? null : JS('String|Null', '#.receiver', match);
+
+ String toString() {
+ if (_method == null) return 'NoSuchMethodError: $_message';
+ if (_receiver == null) {
+ return "NoSuchMethodError: method not found: '$_method' ($_message)";
+ }
+ return "NoSuchMethodError: "
+ "method not found: '$_method' on '$_receiver' ($_message)";
+ }
+}
+
+class UnknownJsTypeError extends Error {
+ final String _message;
+
+ UnknownJsTypeError(this._message);
+
+ String toString() => _message.isEmpty ? 'Error' : 'Error: $_message';
+}
+
+/// A wrapper around an exception, much like the one created by [wrapException]
+/// but with a pre-given stack-trace.
+class ExceptionAndStackTrace {
+ dynamic dartException;
+ StackTrace stackTrace;
+
+ ExceptionAndStackTrace(this.dartException, this.stackTrace);
+}
+
+/// Called from catch blocks in generated code to extract the Dart
+/// exception from the thrown value. The thrown value may have been
+/// created by [wrapException] or it may be a 'native' JS exception.
+///
+/// Some native exceptions are mapped to new Dart instances, others are
+/// returned unmodified.
+unwrapException(ex) {
+ /// If error implements Error, save [ex] in [error.$thrownJsError].
+ /// Otherwise, do nothing. Later, the stack trace can then be extracted from
+ /// [ex].
+ saveStackTrace(error) {
+ if (error is Error) {
+ var thrownStackTrace = JS('', r'#.$thrownJsError', error);
+ if (thrownStackTrace == null) {
+ JS('void', r'#.$thrownJsError = #', error, ex);
+ }
+ }
+ return error;
+ }
+
+ // Note that we are checking if the object has the property. If it
+ // has, it could be set to null if the thrown value is null.
+ if (ex == null) return null;
+ if (ex is ExceptionAndStackTrace) {
+ return saveStackTrace(ex.dartException);
+ }
+ if (JS('bool', 'typeof # !== "object"', ex)) return ex;
+
+ if (JS('bool', r'"dartException" in #', ex)) {
+ return saveStackTrace(JS('', r'#.dartException', ex));
+ } else if (!JS('bool', r'"message" in #', ex)) {
+ return ex;
+ }
+
+ // Grab hold of the exception message. This field is available on
+ // all supported browsers.
+ var message = JS('var', r'#.message', ex);
+
+ // Internet Explorer has an error number. This is the most reliable way to
+ // detect specific errors, so check for this first.
+ if (JS('bool', '"number" in #', ex) &&
+ JS('bool', 'typeof #.number == "number"', ex)) {
+ int number = JS('int', '#.number', ex);
+
+ // From http://msdn.microsoft.com/en-us/library/ie/hc53e755(v=vs.94).aspx
+ // "number" is a 32-bit word. The error code is the low 16 bits, and the
+ // facility code is the upper 16 bits.
+ var ieErrorCode = number & 0xffff;
+ var ieFacilityNumber = (number >> 16) & 0x1fff;
+
+ // http://msdn.microsoft.com/en-us/library/aa264975(v=vs.60).aspx
+ // http://msdn.microsoft.com/en-us/library/ie/1dk3k160(v=vs.94).aspx
+ if (ieFacilityNumber == 10) {
+ switch (ieErrorCode) {
+ case 438:
+ return saveStackTrace(
+ new JsNoSuchMethodError('$message (Error $ieErrorCode)', null));
+ case 445:
+ case 5007:
+ return saveStackTrace(
+ new NullError('$message (Error $ieErrorCode)', null));
+ }
+ }
+ }
+
+ if (JS('bool', r'# instanceof TypeError', ex)) {
+ var match;
+ // Using JS to give type hints to the compiler to help tree-shaking.
+ // TODO(ahe): That should be unnecessary due to type inference.
+ var nsme = TypeErrorDecoder.noSuchMethodPattern;
+ var notClosure = TypeErrorDecoder.notClosurePattern;
+ var nullCall = TypeErrorDecoder.nullCallPattern;
+ var nullLiteralCall = TypeErrorDecoder.nullLiteralCallPattern;
+ var undefCall = TypeErrorDecoder.undefinedCallPattern;
+ var undefLiteralCall = TypeErrorDecoder.undefinedLiteralCallPattern;
+ var nullProperty = TypeErrorDecoder.nullPropertyPattern;
+ var nullLiteralProperty = TypeErrorDecoder.nullLiteralPropertyPattern;
+ var undefProperty = TypeErrorDecoder.undefinedPropertyPattern;
+ var undefLiteralProperty = TypeErrorDecoder.undefinedLiteralPropertyPattern;
+ if ((match = nsme.matchTypeError(message)) != null) {
+ return saveStackTrace(new JsNoSuchMethodError(message, match));
+ } else if ((match = notClosure.matchTypeError(message)) != null) {
+ // notClosure may match "({c:null}).c()" or "({c:1}).c()", so we
+ // cannot tell if this an attempt to invoke call on null or a
+ // non-function object.
+ // But we do know the method name is "call".
+ JS('', '#.method = "call"', match);
+ return saveStackTrace(new JsNoSuchMethodError(message, match));
+ } else if ((match = nullCall.matchTypeError(message)) != null ||
+ (match = nullLiteralCall.matchTypeError(message)) != null ||
+ (match = undefCall.matchTypeError(message)) != null ||
+ (match = undefLiteralCall.matchTypeError(message)) != null ||
+ (match = nullProperty.matchTypeError(message)) != null ||
+ (match = nullLiteralCall.matchTypeError(message)) != null ||
+ (match = undefProperty.matchTypeError(message)) != null ||
+ (match = undefLiteralProperty.matchTypeError(message)) != null) {
+ return saveStackTrace(new NullError(message, match));
+ }
+
+ // If we cannot determine what kind of error this is, we fall back
+ // to reporting this as a generic error. It's probably better than
+ // nothing.
+ return saveStackTrace(
+ new UnknownJsTypeError(message is String ? message : ''));
+ }
+
+ if (JS('bool', r'# instanceof RangeError', ex)) {
+ if (message is String && contains(message, 'call stack')) {
+ return new StackOverflowError();
+ }
+
+ // In general, a RangeError is thrown when trying to pass a number as an
+ // argument to a function that does not allow a range that includes that
+ // number. Translate to a Dart ArgumentError with the same message.
+ // TODO(sra): Translate to RangeError.
+ message = tryStringifyException(ex);
+ if (message is String) {
+ message = JS('String', r'#.replace(/^RangeError:\s*/, "")', message);
+ }
+ return saveStackTrace(new ArgumentError(message));
+ }
+
+ // Check for the Firefox specific stack overflow signal.
+ if (JS(
+ 'bool',
+ r'typeof InternalError == "function" && # instanceof InternalError',
+ ex)) {
+ if (message is String && message == 'too much recursion') {
+ return new StackOverflowError();
+ }
+ }
+
+ // Just return the exception. We should not wrap it because in case
+ // the exception comes from the DOM, it is a JavaScript
+ // object backed by a native Dart class.
+ return ex;
+}
+
+String tryStringifyException(ex) {
+ // Since this function is called from [unwrapException] which is called from
+ // code injected into a catch-clause, use JavaScript try-catch to avoid a
+ // potential loop if stringifying crashes.
+ return JS(
+ 'String|Null',
+ r'''
+ (function(ex) {
+ try {
+ return String(ex);
+ } catch (e) {}
+ return null;
+ })(#)
+ ''',
+ ex);
+}
+
+/// Called by generated code to fetch the stack trace from an
+/// exception. Should never return null.
+StackTrace getTraceFromException(exception) {
+ if (exception is ExceptionAndStackTrace) {
+ return exception.stackTrace;
+ }
+ if (exception == null) return new _StackTrace(exception);
+ _StackTrace trace = JS('_StackTrace|Null', r'#.$cachedTrace', exception);
+ if (trace != null) return trace;
+ trace = new _StackTrace(exception);
+ return JS('_StackTrace', r'#.$cachedTrace = #', exception, trace);
+}
+
+class _StackTrace implements StackTrace {
+ var _exception;
+ String _trace;
+ _StackTrace(this._exception);
+
+ String toString() {
+ if (_trace != null) return JS('String', '#', _trace);
+
+ String trace;
+ if (JS('bool', '# !== null', _exception) &&
+ JS('bool', 'typeof # === "object"', _exception)) {
+ trace = JS('String|Null', r'#.stack', _exception);
+ }
+ return _trace = (trace == null) ? '' : trace;
+ }
+}
+
+int objectHashCode(var object) {
+ if (object == null || JS('bool', "typeof # != 'object'", object)) {
+ return object.hashCode;
+ } else {
+ return Primitives.objectHashCode(object);
+ }
+}
+
+/// Called by generated code to build a map literal. [keyValuePairs] is
+/// a list of key, value, key, value, ..., etc.
+fillLiteralMap(keyValuePairs, Map result) {
+ // TODO(johnniwinther): Use JSArray to optimize this code instead of calling
+ // [getLength] and [getIndex].
+ int index = 0;
+ int length = getLength(keyValuePairs);
+ while (index < length) {
+ var key = getIndex(keyValuePairs, index++);
+ var value = getIndex(keyValuePairs, index++);
+ result[key] = value;
+ }
+ return result;
+}
+
+/// Called by generated code to build a set literal.
+fillLiteralSet(values, Set result) {
+ // TODO(johnniwinther): Use JSArray to optimize this code instead of calling
+ // [getLength] and [getIndex].
+ int length = getLength(values);
+ for (int index = 0; index < length; index++) {
+ result.add(getIndex(values, index));
+ }
+ return result;
+}
+
+invokeClosure(Function closure, int numberOfArguments, var arg1, var arg2,
+ var arg3, var arg4) {
+ switch (numberOfArguments) {
+ case 0:
+ return closure();
+ case 1:
+ return closure(arg1);
+ case 2:
+ return closure(arg1, arg2);
+ case 3:
+ return closure(arg1, arg2, arg3);
+ case 4:
+ return closure(arg1, arg2, arg3, arg4);
+ }
+ throw new Exception('Unsupported number of arguments for wrapped closure');
+}
+
+/// Called by generated code to convert a Dart closure to a JS
+/// closure when the Dart closure is passed to the DOM.
+convertDartClosureToJS(closure, int arity) {
+ if (closure == null) return null;
+ var function = JS('var', r'#.$identity', closure);
+ if (JS('bool', r'!!#', function)) return function;
+
+ function = JS(
+ 'var',
+ r'''
+ (function(closure, arity, invoke) {
+ return function(a1, a2, a3, a4) {
+ return invoke(closure, arity, a1, a2, a3, a4);
+ };
+ })(#,#,#)''',
+ closure,
+ arity,
+ DART_CLOSURE_TO_JS(invokeClosure));
+
+ JS('void', r'#.$identity = #', closure, function);
+ return function;
+}
+
+/// Superclass for Dart closures.
+///
+/// All static, tear-off, function declaration and function expression closures
+/// extend this class, but classes that implement Function via a `call` method
+/// do not.
+abstract class Closure implements Function {
+ // TODO(ahe): These constants must be in sync with
+ // reflection_data_parser.dart.
+ static const FUNCTION_INDEX = 0;
+ static const NAME_INDEX = 1;
+ static const CALL_NAME_INDEX = 2;
+ static const REQUIRED_PARAMETER_INDEX = 3;
+ static const OPTIONAL_PARAMETER_INDEX = 4;
+ static const DEFAULT_ARGUMENTS_INDEX = 5;
+
+ /// Global counter to prevent reusing function code objects.
+ ///
+ /// V8 will share the underlying function code objects when the same string is
+ /// passed to "new Function". Shared function code objects can lead to
+ /// sub-optimal performance due to polymorphism, and can be prevented by
+ /// ensuring the strings are different, for example, by generating a local
+ /// variable with a name dependent on [functionCounter].
+ static int functionCounter = 0;
+
+ Closure();
+
+ /// Creates a new closure class for use by implicit getters associated with a
+ /// method.
+ ///
+ /// In other words, creates a tear-off closure.
+ ///
+ /// Called from [closureFromTearOff] as well as from reflection when tearing
+ /// of a method via `getField`.
+ ///
+ /// This method assumes that [functions] was created by the JavaScript
+ /// function `addStubs` in `reflection_data_parser.dart`. That is, a list of
+ /// JavaScript function objects with properties `$stubName` and `$callName`.
+ ///
+ /// Further assumes that [reflectionInfo] is the end of the array created by
+ /// [dart2js.js_emitter.ContainerBuilder.addMemberMethod] starting with
+ /// required parameter count or, in case of the new emitter, the runtime
+ /// representation of the function's type.
+ ///
+ /// Caution: this function may be called when building constants.
+ /// TODO(ahe): Don't call this function when building constants.
+ static fromTearOff(
+ receiver,
+ List functions,
+ int applyTrampolineIndex,
+ var reflectionInfo,
+ bool isStatic,
+ bool isIntercepted,
+ String propertyName,
+ ) {
+ JS_EFFECT(() {
+ // The functions are called here to model the calls from JS forms below.
+ // The types in the JS forms in the arguments are propagated in type
+ // inference.
+ var aBoundClosure = JS('BoundClosure', '0');
+ var aString = JS('String', '0');
+ BoundClosure.receiverOf(aBoundClosure);
+ BoundClosure.selfOf(aBoundClosure);
+ BoundClosure.evalRecipeIntercepted(aBoundClosure, aString);
+ BoundClosure.evalRecipe(aBoundClosure, aString);
+ getType(JS('int', '0'));
+ });
+ // TODO(ahe): All the place below using \$ should be rewritten to go
+ // through the namer.
+ var function = JS('', '#[#]', functions, 0);
+ String name = JS('String|Null', '#.\$stubName', function);
+ String callName = JS('String|Null', '#[#]', function,
+ JS_GET_NAME(JsGetName.CALL_NAME_PROPERTY));
+
+ // This variable holds either an index into the types-table, or a function
+ // that can compute a function-rti. (The latter is necessary if the type
+ // is dependent on generic arguments).
+ var functionType = reflectionInfo;
+
+ // function tmp() {};
+ // tmp.prototype = BC.prototype;
+ // var proto = new tmp;
+ // for each computed prototype property:
+ // proto[property] = ...;
+ // proto._init = BC;
+ // var dynClosureConstructor =
+ // new Function('self', 'target', 'receiver', 'name',
+ // 'this._init(self, target, receiver, name)');
+ // proto.constructor = dynClosureConstructor;
+ // dynClosureConstructor.prototype = proto;
+ // return dynClosureConstructor;
+
+ // We need to create a new subclass of TearOffClosure, one of StaticClosure
+ // or BoundClosure. For this, we need to create an object whose prototype
+ // is the prototype is either StaticClosure.prototype or
+ // BoundClosure.prototype, respectively in pseudo JavaScript code. The
+ // simplest way to access the JavaScript construction function of a Dart
+ // class is to create an instance and access its constructor property.
+ // Creating an instance ensures that any lazy class initialization has taken
+ // place. The newly created instance could in theory be used directly as the
+ // prototype, but it might include additional fields that we don't need. So
+ // we only use the new instance to access the constructor property and use
+ // Object.create to create the desired prototype.
+ //
+ // TODO(sra): Perhaps cache the prototype to avoid the allocation.
+ var prototype = isStatic
+ ? JS('StaticClosure', 'Object.create(#.constructor.prototype)',
+ new StaticClosure())
+ : JS('BoundClosure', 'Object.create(#.constructor.prototype)',
+ new BoundClosure(null, null, null, null));
+
+ JS('', '#.\$initialize = #', prototype, JS('', '#.constructor', prototype));
+
+ // The constructor functions have names to prevent the JavaScript
+ // implementation from inventing a name that might have special meaning
+ // (e.g. clashing with minified 'Object' or 'Interceptor').
+ var constructor = isStatic
+ ? JS('', 'function static_tear_off(){this.\$initialize()}')
+ : isCsp
+ ? JS('', 'function tear_off(a,b,c,d) {this.\$initialize(a,b,c,d)}')
+ : JS(
+ '',
+ 'new Function("a,b,c,d" + #,'
+ ' "this.\$initialize(a,b,c,d" + # + ")")',
+ functionCounter,
+ functionCounter++);
+
+ // It is necessary to set the constructor property, otherwise it will be
+ // "Object".
+ JS('', '#.constructor = #', prototype, constructor);
+
+ JS('', '#.prototype = #', constructor, prototype);
+
+ // Create a closure and "monkey" patch it with call stubs.
+ var trampoline = function;
+ if (!isStatic) {
+ trampoline = forwardCallTo(receiver, function, isIntercepted);
+ JS('', '#.\$reflectionInfo = #', trampoline, reflectionInfo);
+ } else {
+ JS('', '#[#] = #', prototype, STATIC_FUNCTION_NAME_PROPERTY_NAME,
+ propertyName);
+ }
+
+ var signatureFunction = JS_GET_FLAG('USE_NEW_RTI')
+ ? _computeSignatureFunctionNewRti(functionType, isStatic, isIntercepted)
+ : _computeSignatureFunctionLegacy(
+ functionType, isStatic, isIntercepted);
+
+ JS('', '#[#] = #', prototype, JS_GET_NAME(JsGetName.SIGNATURE_NAME),
+ signatureFunction);
+ var applyTrampoline = trampoline;
+ JS('', '#[#] = #', prototype, callName, trampoline);
+ for (int i = 1; i < functions.length; i++) {
+ var stub = functions[i];
+ var stubCallName = JS('String|Null', '#[#]', stub,
+ JS_GET_NAME(JsGetName.CALL_NAME_PROPERTY));
+ if (stubCallName != null) {
+ stub = isStatic ? stub : forwardCallTo(receiver, stub, isIntercepted);
+ JS('', '#[#] = #', prototype, stubCallName, stub);
+ }
+ if (i == applyTrampolineIndex) {
+ applyTrampoline = stub;
+ JS('', '#.\$reflectionInfo = #', applyTrampoline, reflectionInfo);
+ }
+ }
+
+ JS('', '#[#] = #', prototype, JS_GET_NAME(JsGetName.CALL_CATCH_ALL),
+ applyTrampoline);
+ String reqArgProperty = JS_GET_NAME(JsGetName.REQUIRED_PARAMETER_PROPERTY);
+ String defValProperty = JS_GET_NAME(JsGetName.DEFAULT_VALUES_PROPERTY);
+ JS('', '#.# = #.#', prototype, reqArgProperty, function, reqArgProperty);
+ JS('', '#.# = #.#', prototype, defValProperty, function, defValProperty);
+
+ return constructor;
+ }
+
+ static _computeSignatureFunctionLegacy(
+ Object functionType, bool isStatic, bool isIntercepted) {
+ if (JS('bool', 'typeof # == "number"', functionType)) {
+ // We cannot call [getType] here, since the types-metadata might not be
+ // set yet. This is, because fromTearOff might be called for constants
+ // when the program isn't completely set up yet.
+ //
+ // Note that we cannot just textually inline the call
+ // `getType(functionType)` since we cannot guarantee that the (then)
+ // captured variable `functionType` isn't reused.
+ return JS(
+ '',
+ '''(function(getType, t) {
+ return function(){ return getType(t); };
+ })(#, #)''',
+ RAW_DART_FUNCTION_REF(getType),
+ functionType);
+ }
+ if (JS('bool', 'typeof # == "function"', functionType)) {
+ if (isStatic) {
+ return functionType;
+ } else {
+ var getReceiver = isIntercepted
+ ? RAW_DART_FUNCTION_REF(BoundClosure.receiverOf)
+ : RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
+ return JS(
+ '',
+ 'function(f,r){'
+ 'return function(){'
+ 'return f.apply({\$receiver:r(this)},arguments)'
+ '}'
+ '}(#,#)',
+ functionType,
+ getReceiver);
+ }
+ }
+ throw 'Error in functionType of tearoff';
+ }
+
+ static _computeSignatureFunctionNewRti(
+ Object functionType, bool isStatic, bool isIntercepted) {
+ if (JS('bool', 'typeof # == "number"', functionType)) {
+ // Index into types table.
+ //
+ // We cannot call [getTypeFromTypesTable] here, since the types-metadata
+ // might not be set yet. This is, because fromTearOff might be called for
+ // constants when the program isn't completely set up yet. We also want to
+ // avoid creating lots of types at startup.
+ return JS(
+ '',
+ '''(function(getType, t) {
+ return function(){ return getType(t); };
+ })(#, #)''',
+ RAW_DART_FUNCTION_REF(newRti.getTypeFromTypesTable),
+ functionType);
+ }
+ if (JS('bool', 'typeof # == "string"', functionType)) {
+ // A recipe to evaluate against the instance type.
+ if (isStatic) {
+ throw 'TODO: Recipe for static tearoff.';
+ }
+ var typeEvalMethod = isIntercepted
+ ? RAW_DART_FUNCTION_REF(BoundClosure.evalRecipeIntercepted)
+ : RAW_DART_FUNCTION_REF(BoundClosure.evalRecipe);
+ return JS(
+ '',
+ ' function(recipe, evalOnReceiver) {'
+ ' return function() {'
+ ' return evalOnReceiver(this, recipe);'
+ ' };'
+ '}(#,#)',
+ functionType,
+ typeEvalMethod);
+ }
+ throw 'Error in functionType of tearoff';
+ }
+
+ static cspForwardCall(
+ int arity, bool isSuperCall, String stubName, function) {
+ var getSelf = RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
+ // Handle intercepted stub-names with the default slow case.
+ if (isSuperCall) arity = -1;
+ switch (arity) {
+ case 0:
+ return JS(
+ '',
+ 'function(n,S){'
+ 'return function(){'
+ 'return S(this)[n]()'
+ '}'
+ '}(#,#)',
+ stubName,
+ getSelf);
+ case 1:
+ return JS(
+ '',
+ 'function(n,S){'
+ 'return function(a){'
+ 'return S(this)[n](a)'
+ '}'
+ '}(#,#)',
+ stubName,
+ getSelf);
+ case 2:
+ return JS(
+ '',
+ 'function(n,S){'
+ 'return function(a,b){'
+ 'return S(this)[n](a,b)'
+ '}'
+ '}(#,#)',
+ stubName,
+ getSelf);
+ case 3:
+ return JS(
+ '',
+ 'function(n,S){'
+ 'return function(a,b,c){'
+ 'return S(this)[n](a,b,c)'
+ '}'
+ '}(#,#)',
+ stubName,
+ getSelf);
+ case 4:
+ return JS(
+ '',
+ 'function(n,S){'
+ 'return function(a,b,c,d){'
+ 'return S(this)[n](a,b,c,d)'
+ '}'
+ '}(#,#)',
+ stubName,
+ getSelf);
+ case 5:
+ return JS(
+ '',
+ 'function(n,S){'
+ 'return function(a,b,c,d,e){'
+ 'return S(this)[n](a,b,c,d,e)'
+ '}'
+ '}(#,#)',
+ stubName,
+ getSelf);
+ default:
+ return JS(
+ '',
+ 'function(f,s){'
+ 'return function(){'
+ 'return f.apply(s(this),arguments)'
+ '}'
+ '}(#,#)',
+ function,
+ getSelf);
+ }
+ }
+
+ static bool get isCsp => JS_GET_FLAG('USE_CONTENT_SECURITY_POLICY');
+
+ static forwardCallTo(receiver, function, bool isIntercepted) {
+ if (isIntercepted) return forwardInterceptedCallTo(receiver, function);
+ String stubName = JS('String|Null', '#.\$stubName', function);
+ int arity = JS('int', '#.length', function);
+ var lookedUpFunction = JS('', '#[#]', receiver, stubName);
+ // The receiver[stubName] may not be equal to the function if we try to
+ // forward to a super-method. Especially when we create a bound closure
+ // of a super-call we need to make sure that we don't forward back to the
+ // dynamically looked up function.
+ bool isSuperCall = !identical(function, lookedUpFunction);
+
+ if (isCsp || isSuperCall || arity >= 27) {
+ return cspForwardCall(arity, isSuperCall, stubName, function);
+ }
+
+ if (arity == 0) {
+ // Incorporate functionCounter into a local.
+ String selfName = 'self${functionCounter++}';
+ return JS(
+ '',
+ '(new Function(#))()',
+ 'return function(){'
+ 'var $selfName = this.${BoundClosure.selfFieldName()};'
+ 'return $selfName.$stubName();'
+ '}');
+ }
+ assert(1 <= arity && arity < 27);
+ String arguments = JS('String',
+ '"abcdefghijklmnopqrstuvwxyz".split("").splice(0,#).join(",")', arity);
+ arguments += '${functionCounter++}';
+ return JS(
+ '',
+ '(new Function(#))()',
+ 'return function($arguments){'
+ 'return this.${BoundClosure.selfFieldName()}.$stubName($arguments);'
+ '}');
+ }
+
+ static cspForwardInterceptedCall(
+ int arity, bool isSuperCall, String name, function) {
+ var getSelf = RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
+ var getReceiver = RAW_DART_FUNCTION_REF(BoundClosure.receiverOf);
+ // Handle intercepted stub-names with the default slow case.
+ if (isSuperCall) arity = -1;
+ switch (arity) {
+ case 0:
+ // Intercepted functions always takes at least one argument (the
+ // receiver).
+ throw new RuntimeError('Intercepted function with no arguments.');
+ case 1:
+ return JS(
+ '',
+ 'function(n,s,r){'
+ 'return function(){'
+ 'return s(this)[n](r(this))'
+ '}'
+ '}(#,#,#)',
+ name,
+ getSelf,
+ getReceiver);
+ case 2:
+ return JS(
+ '',
+ 'function(n,s,r){'
+ 'return function(a){'
+ 'return s(this)[n](r(this),a)'
+ '}'
+ '}(#,#,#)',
+ name,
+ getSelf,
+ getReceiver);
+ case 3:
+ return JS(
+ '',
+ 'function(n,s,r){'
+ 'return function(a,b){'
+ 'return s(this)[n](r(this),a,b)'
+ '}'
+ '}(#,#,#)',
+ name,
+ getSelf,
+ getReceiver);
+ case 4:
+ return JS(
+ '',
+ 'function(n,s,r){'
+ 'return function(a,b,c){'
+ 'return s(this)[n](r(this),a,b,c)'
+ '}'
+ '}(#,#,#)',
+ name,
+ getSelf,
+ getReceiver);
+ case 5:
+ return JS(
+ '',
+ 'function(n,s,r){'
+ 'return function(a,b,c,d){'
+ 'return s(this)[n](r(this),a,b,c,d)'
+ '}'
+ '}(#,#,#)',
+ name,
+ getSelf,
+ getReceiver);
+ case 6:
+ return JS(
+ '',
+ 'function(n,s,r){'
+ 'return function(a,b,c,d,e){'
+ 'return s(this)[n](r(this),a,b,c,d,e)'
+ '}'
+ '}(#,#,#)',
+ name,
+ getSelf,
+ getReceiver);
+ default:
+ return JS(
+ '',
+ 'function(f,s,r,a){'
+ 'return function(){'
+ 'a=[r(this)];'
+ 'Array.prototype.push.apply(a,arguments);'
+ 'return f.apply(s(this),a)'
+ '}'
+ '}(#,#,#)',
+ function,
+ getSelf,
+ getReceiver);
+ }
+ }
+
+ static forwardInterceptedCallTo(receiver, function) {
+ String selfField = BoundClosure.selfFieldName();
+ String receiverField = BoundClosure.receiverFieldName();
+ String stubName = JS('String|Null', '#.\$stubName', function);
+ int arity = JS('int', '#.length', function);
+ bool isCsp = JS_GET_FLAG('USE_CONTENT_SECURITY_POLICY');
+ var lookedUpFunction = JS('', '#[#]', receiver, stubName);
+ // The receiver[stubName] may not be equal to the function if we try to
+ // forward to a super-method. Especially when we create a bound closure
+ // of a super-call we need to make sure that we don't forward back to the
+ // dynamically looked up function.
+ bool isSuperCall = !identical(function, lookedUpFunction);
+
+ if (isCsp || isSuperCall || arity >= 28) {
+ return cspForwardInterceptedCall(arity, isSuperCall, stubName, function);
+ }
+ if (arity == 1) {
+ return JS(
+ '',
+ '(new Function(#))()',
+ 'return function(){'
+ 'return this.$selfField.$stubName(this.$receiverField);'
+ '${functionCounter++}'
+ '}');
+ }
+ assert(1 < arity && arity < 28);
+ String arguments = JS(
+ 'String',
+ '"abcdefghijklmnopqrstuvwxyz".split("").splice(0,#).join(",")',
+ arity - 1);
+ return JS(
+ '',
+ '(new Function(#))()',
+ 'return function($arguments){'
+ 'return this.$selfField.$stubName(this.$receiverField, $arguments);'
+ '${functionCounter++}'
+ '}');
+ }
+
+ // The backend adds a special getter of the form
+ //
+ // Closure get call => this;
+ //
+ // to allow tearing off a closure from itself. We do this magically in the
+ // backend rather than simply adding it here, as we do not want this getter
+ // to be visible to resolution and the generation of extra stubs.
+
+ String toString() {
+ String name;
+ if (JS_GET_FLAG('USE_NEW_RTI')) {
+ var constructor = JS('', '#.constructor', this);
+ name =
+ constructor == null ? null : JS('String|Null', '#.name', constructor);
+ if (name == null) name = 'unknown';
+ } else {
+ name = Primitives.objectTypeName(this);
+ // Mirrors puts a space in front of some names, so remove it.
+ name = JS('String', '#.trim()', name);
+ }
+ return "Closure '$name'";
+ }
+}
+
+/// Called from implicit method getter (aka tear-off).
+closureFromTearOff(receiver, functions, applyTrampolineIndex, reflectionInfo,
+ isStatic, isIntercepted, name) {
+ return Closure.fromTearOff(
+ receiver,
+ JS('JSArray', '#', functions),
+ JS('int|Null', '#', applyTrampolineIndex),
+ reflectionInfo,
+ JS('bool', '!!#', isStatic),
+ JS('bool', '!!#', isIntercepted),
+ JS('String', '#', name));
+}
+
+/// Represents an implicit closure of a function.
+abstract class TearOffClosure extends Closure {}
+
+class StaticClosure extends TearOffClosure {
+ String toString() {
+ String name =
+ JS('String|Null', '#[#]', this, STATIC_FUNCTION_NAME_PROPERTY_NAME);
+ if (name == null) return 'Closure of unknown static method';
+ return "Closure '${unminifyOrTag(name)}'";
+ }
+}
+
+/// Represents a 'tear-off' or property extraction closure of an instance
+/// method, that is an instance method bound to a specific receiver (instance).
+class BoundClosure extends TearOffClosure {
+ /// The receiver or interceptor.
+ // TODO(ahe): This could just be the interceptor, we always know if
+ // we need the interceptor when generating the call method.
+ final _self;
+
+ /// The method.
+ final _target;
+
+ /// The receiver. Null if [_self] is not an interceptor.
+ final _receiver;
+
+ /// The name of the function. Only used by the mirror system.
+ final String _name;
+
+ BoundClosure(this._self, this._target, this._receiver, this._name);
+
+ bool operator ==(other) {
+ if (identical(this, other)) return true;
+ if (other is! BoundClosure) return false;
+ return JS('bool', '# === #', _self, other._self) &&
+ JS('bool', '# === #', _target, other._target) &&
+ JS('bool', '# === #', _receiver, other._receiver);
+ }
+
+ int get hashCode {
+ int receiverHashCode;
+ if (_receiver == null) {
+ // A bound closure on a regular Dart object, just use the
+ // identity hash code.
+ receiverHashCode = Primitives.objectHashCode(_self);
+ } else if (JS('String', 'typeof #', _receiver) != 'object') {
+ // A bound closure on a primitive JavaScript type. We
+ // use the hashCode method we define for those primitive types.
+ receiverHashCode = _receiver.hashCode;
+ } else {
+ // A bound closure on an intercepted native class, just use the
+ // identity hash code.
+ receiverHashCode = Primitives.objectHashCode(_receiver);
+ }
+ return receiverHashCode ^ Primitives.objectHashCode(_target);
+ }
+
+ toString() {
+ var receiver = _receiver == null ? _self : _receiver;
+ // TODO(sra): When minified, mark [_name] with a tag,
+ // e.g. 'minified-property:' so that it can be unminified.
+ return "Closure '$_name' of "
+ "${Primitives.objectToHumanReadableString(receiver)}";
+ }
+
+ static evalRecipe(BoundClosure closure, String recipe) {
+ return newRti.evalInInstance(closure._self, recipe);
+ }
+
+ static evalRecipeIntercepted(BoundClosure closure, String recipe) {
+ return newRti.evalInInstance(closure._receiver, recipe);
+ }
+
+ @pragma('dart2js:noInline')
+ static selfOf(BoundClosure closure) => closure._self;
+
+ static targetOf(BoundClosure closure) => closure._target;
+
+ @pragma('dart2js:noInline')
+ static receiverOf(BoundClosure closure) => closure._receiver;
+
+ static nameOf(BoundClosure closure) => closure._name;
+
+ static String selfFieldNameCache;
+
+ static String selfFieldName() {
+ if (selfFieldNameCache == null) {
+ selfFieldNameCache = computeFieldNamed('self');
+ }
+ return selfFieldNameCache;
+ }
+
+ static String receiverFieldNameCache;
+
+ static String receiverFieldName() {
+ if (receiverFieldNameCache == null) {
+ receiverFieldNameCache = computeFieldNamed('receiver');
+ }
+ return receiverFieldNameCache;
+ }
+
+ @pragma('dart2js:noInline')
+ @pragma('dart2js:noSideEffects')
+ static String computeFieldNamed(String fieldName) {
+ var template = new BoundClosure('self', 'target', 'receiver', 'name');
+ var names = JSArray.markFixedList(
+ JS('', 'Object.getOwnPropertyNames(#)', template));
+ for (int i = 0; i < names.length; i++) {
+ var name = names[i];
+ if (JS('bool', '#[#] === #', template, name, fieldName)) {
+ return JS('String', '#', name);
+ }
+ }
+ }
+}
+
+bool jsHasOwnProperty(var jsObject, String property) {
+ return JS('bool', r'#.hasOwnProperty(#)', jsObject, property);
+}
+
+jsPropertyAccess(var jsObject, String property) {
+ return JS('var', r'#[#]', jsObject, property);
+}
+
+/// Called at the end of unaborted switch cases to get the singleton
+/// FallThroughError exception that will be thrown.
+getFallThroughError() => new FallThroughErrorImplementation();
+
+/// A metadata annotation describing the types instantiated by a native element.
+///
+/// The annotation is valid on a native method and a field of a native class.
+///
+/// By default, a field of a native class is seen as an instantiation point for
+/// all native classes that are a subtype of the field's type, and a native
+/// method is seen as an instantiation point fo all native classes that are a
+/// subtype of the method's return type, or the argument types of the declared
+/// type of the method's callback parameter.
+///
+/// An @[Creates] annotation overrides the default set of instantiated types.
+/// If one or more @[Creates] annotations are present, the type of the native
+/// element is ignored, and the union of @[Creates] annotations is used instead.
+/// The names in the strings are resolved and the program will fail to compile
+/// with dart2js if they do not name types.
+///
+/// The argument to [Creates] is a string. The string is parsed as the names of
+/// one or more types, separated by vertical bars `|`. There are some special
+/// names:
+///
+/// * `=Object`. This means 'exactly Object', which is a plain JavaScript object
+/// with properties and none of the subtypes of Object.
+///
+/// Example: we may know that a method always returns a specific implementation:
+///
+/// @Creates('_NodeList')
+/// List<Node> getElementsByTagName(String tag) native;
+///
+/// Useful trick: A method can be marked as not instantiating any native classes
+/// with the annotation `@Creates('Null')`. This is useful for fields on native
+/// classes that are used only in Dart code.
+///
+/// @Creates('Null')
+/// var _cachedFoo;
+class Creates {
+ final String types;
+ const Creates(this.types);
+}
+
+/// A metadata annotation describing the types returned or yielded by a native
+/// element.
+///
+/// The annotation is valid on a native method and a field of a native class.
+///
+/// By default, a native method or field is seen as returning or yielding all
+/// subtypes if the method return type or field type. This annotation allows a
+/// more precise set of types to be specified.
+///
+/// See [Creates] for the syntax of the argument.
+///
+/// Example: IndexedDB keys are numbers, strings and JavaScript Arrays of keys.
+///
+/// @Returns('String|num|JSExtendableArray')
+/// dynamic key;
+///
+/// // Equivalent:
+/// @Returns('String') @Returns('num') @Returns('JSExtendableArray')
+/// dynamic key;
+class Returns {
+ final String types;
+ const Returns(this.types);
+}
+
+/// A metadata annotation placed on native methods and fields of native classes
+/// to specify the JavaScript name.
+///
+/// This example declares a Dart field + getter + setter called `$dom_title`
+/// that corresponds to the JavaScript property `title`.
+///
+/// class Document native "*Foo" {
+/// @JSName('title')
+/// String $dom_title;
+/// }
+class JSName {
+ final String name;
+ const JSName(this.name);
+}
+
+/// The following methods are called by the runtime to implement checked mode
+/// and casts. We specialize each primitive type (eg int, bool), and use the
+/// compiler's convention to do is-checks on regular objects.
+boolConversionCheck(value) {
+ // The value from kernel should always be true, false, or null.
+ if (value == null) assertThrow('boolean expression must not be null');
+ return value;
+}
+
+stringTypeCheck(value) {
+ if (value == null) return value;
+ if (value is String) return value;
+ throw new TypeErrorImplementation(value, 'String');
+}
+
+stringTypeCast(value) {
+ if (value is String || value == null) return value;
+ throw new CastErrorImplementation(value, 'String');
+}
+
+doubleTypeCheck(value) {
+ if (value == null) return value;
+ if (value is double) return value;
+ throw new TypeErrorImplementation(value, 'double');
+}
+
+doubleTypeCast(value) {
+ if (value is double || value == null) return value;
+ throw new CastErrorImplementation(value, 'double');
+}
+
+numTypeCheck(value) {
+ if (value == null) return value;
+ if (value is num) return value;
+ throw new TypeErrorImplementation(value, 'num');
+}
+
+numTypeCast(value) {
+ if (value is num || value == null) return value;
+ throw new CastErrorImplementation(value, 'num');
+}
+
+boolTypeCheck(value) {
+ if (value == null) return value;
+ if (value is bool) return value;
+ throw new TypeErrorImplementation(value, 'bool');
+}
+
+boolTypeCast(value) {
+ if (value is bool || value == null) return value;
+ throw new CastErrorImplementation(value, 'bool');
+}
+
+intTypeCheck(value) {
+ if (value == null) return value;
+ if (value is int) return value;
+ throw new TypeErrorImplementation(value, 'int');
+}
+
+intTypeCast(value) {
+ if (value is int || value == null) return value;
+ throw new CastErrorImplementation(value, 'int');
+}
+
+void propertyTypeError(value, property) {
+ String name = isCheckPropertyToJsConstructorName(property);
+ throw new TypeErrorImplementation(value, unminifyOrTag(name));
+}
+
+void propertyTypeCastError(value, property) {
+ // Cuts the property name to the class name.
+ String name = isCheckPropertyToJsConstructorName(property);
+ throw new CastErrorImplementation(value, unminifyOrTag(name));
+}
+
+/// For types that are not supertypes of native (eg DOM) types,
+/// we emit a simple property check to check that an object implements
+/// that type.
+propertyTypeCheck(value, property) {
+ if (value == null) return value;
+ if (JS('bool', '!!#[#]', value, property)) return value;
+ propertyTypeError(value, property);
+}
+
+/// For types that are not supertypes of native (eg DOM) types,
+/// we emit a simple property check to check that an object implements
+/// that type.
+propertyTypeCast(value, property) {
+ if (value == null || JS('bool', '!!#[#]', value, property)) return value;
+ propertyTypeCastError(value, property);
+}
+
+/// For types that are supertypes of native (eg DOM) types, we use the
+/// interceptor for the class because we cannot add a JS property to the
+/// prototype at load time.
+interceptedTypeCheck(value, property) {
+ if (value == null) return value;
+ if ((JS('bool', 'typeof # === "object"', value) ||
+ JS('bool', 'typeof # === "function"', value)) &&
+ JS('bool', '#[#]', getInterceptor(value), property)) {
+ return value;
+ }
+ propertyTypeError(value, property);
+}
+
+/// For types that are supertypes of native (eg DOM) types, we use the
+/// interceptor for the class because we cannot add a JS property to the
+/// prototype at load time.
+interceptedTypeCast(value, property) {
+ if (value == null ||
+ ((JS('bool', 'typeof # === "object"', value) ||
+ JS('bool', 'typeof # === "function"', value)) &&
+ JS('bool', '#[#]', getInterceptor(value), property))) {
+ return value;
+ }
+ propertyTypeCastError(value, property);
+}
+
+/// Specialization of the type check for num and String and their
+/// supertype since [value] can be a JS primitive.
+numberOrStringSuperTypeCheck(value, property) {
+ if (value == null) return value;
+ if (value is String) return value;
+ if (value is num) return value;
+ if (JS('bool', '!!#[#]', value, property)) return value;
+ propertyTypeError(value, property);
+}
+
+numberOrStringSuperTypeCast(value, property) {
+ if (value is String) return value;
+ if (value is num) return value;
+ return propertyTypeCast(value, property);
+}
+
+numberOrStringSuperNativeTypeCheck(value, property) {
+ if (value == null) return value;
+ if (value is String) return value;
+ if (value is num) return value;
+ if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
+ propertyTypeError(value, property);
+}
+
+numberOrStringSuperNativeTypeCast(value, property) {
+ if (value == null) return value;
+ if (value is String) return value;
+ if (value is num) return value;
+ if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
+ propertyTypeCastError(value, property);
+}
+
+/// Specialization of the type check for String and its supertype
+/// since [value] can be a JS primitive.
+stringSuperTypeCheck(value, property) {
+ if (value == null) return value;
+ if (value is String) return value;
+ if (JS('bool', '!!#[#]', value, property)) return value;
+ propertyTypeError(value, property);
+}
+
+stringSuperTypeCast(value, property) {
+ if (value is String) return value;
+ return propertyTypeCast(value, property);
+}
+
+stringSuperNativeTypeCheck(value, property) {
+ if (value == null) return value;
+ if (value is String) return value;
+ if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
+ propertyTypeError(value, property);
+}
+
+stringSuperNativeTypeCast(value, property) {
+ if (value is String || value == null) return value;
+ if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
+ propertyTypeCastError(value, property);
+}
+
+/// Specialization of the type check for List and its supertypes,
+/// since [value] can be a JS array.
+listTypeCheck(value) {
+ if (value == null) return value;
+ if (value is List) return value;
+ throw new TypeErrorImplementation(value, 'List<dynamic>');
+}
+
+listTypeCast(value) {
+ if (value is List || value == null) return value;
+ throw new CastErrorImplementation(value, 'List<dynamic>');
+}
+
+listSuperTypeCheck(value, property) {
+ if (value == null) return value;
+ if (value is List) return value;
+ if (JS('bool', '!!#[#]', value, property)) return value;
+ propertyTypeError(value, property);
+}
+
+listSuperTypeCast(value, property) {
+ if (value is List) return value;
+ return propertyTypeCast(value, property);
+}
+
+listSuperNativeTypeCheck(value, property) {
+ if (value == null) return value;
+ if (value is List) return value;
+ if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
+ propertyTypeError(value, property);
+}
+
+listSuperNativeTypeCast(value, property) {
+ if (value is List || value == null) return value;
+ if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
+ propertyTypeCastError(value, property);
+}
+
+extractFunctionTypeObjectFrom(o) {
+ var interceptor = getInterceptor(o);
+ return extractFunctionTypeObjectFromInternal(interceptor);
+}
+
+extractFunctionTypeObjectFromInternal(o) {
+ var signatureName = JS_GET_NAME(JsGetName.SIGNATURE_NAME);
+ if (JS('bool', '# in #', signatureName, o)) {
+ var signature = JS('', '#[#]', o, signatureName);
+ if (JS('bool', 'typeof # == "number"', signature)) {
+ return getType(signature);
+ } else {
+ return JS('', '#[#]()', o, signatureName);
+ }
+ }
+ return null;
+}
+
+functionTypeTest(value, functionTypeRti) {
+ if (value == null) return false;
+ if (JS('bool', 'typeof # == "function"', value)) {
+ // JavaScript functions do not have an attached type, but for convenient
+ // JS-interop, we pretend they can be any function type.
+ // TODO(sra): Tighten this up to disallow matching function types with
+ // features inaccessible from JavaScript, i.e. optional named parameters
+ // and type parameters functions.
+ // TODO(sra): If the JavaScript function was the output of `dart:js`'s
+ // `allowInterop` then we have access to the wrapped function.
+ return true;
+ }
+ var functionTypeObject = extractFunctionTypeObjectFrom(value);
+ if (functionTypeObject == null) return false;
+ return isFunctionSubtype(functionTypeObject, functionTypeRti);
+}
+
+// Declared as 'var' to avoid assignment checks.
+var _inTypeAssertion = false;
+
+functionTypeCheck(value, functionTypeRti) {
+ if (value == null) return value;
+
+ // The function type test code contains type assertions for function
+ // types. This leads to unbounded recursion, so disable the type checking of
+ // function types while checking function types.
+
+ if (true == _inTypeAssertion) return value;
+
+ _inTypeAssertion = true;
+ try {
+ if (functionTypeTest(value, functionTypeRti)) return value;
+ var self = runtimeTypeToString(functionTypeRti);
+ throw new TypeErrorImplementation(value, self);
+ } finally {
+ _inTypeAssertion = false;
+ }
+}
+
+functionTypeCast(value, functionTypeRti) {
+ if (value == null) return value;
+ if (functionTypeTest(value, functionTypeRti)) return value;
+
+ var self = runtimeTypeToString(functionTypeRti);
+ throw new CastErrorImplementation(value, self);
+}
+
+futureOrTest(o, futureOrRti) => checkSubtypeOfRuntimeType(o, futureOrRti);
+
+futureOrCheck(o, futureOrRti) => assertSubtypeOfRuntimeType(o, futureOrRti);
+
+futureOrCast(o, futureOrRti) => subtypeOfRuntimeTypeCast(o, futureOrRti);
+
+@pragma('dart2js:noInline')
+void checkDeferredIsLoaded(String loadId, String uri) {
+ if (!_loadedLibraries.contains(loadId)) {
+ throw new DeferredNotLoadedError(uri);
+ }
+}
+
+/// Special interface recognized by the compiler and implemented by DOM
+/// objects that support integer indexing. This interface is not
+/// visible to anyone, and is only injected into special libraries.
+abstract class JavaScriptIndexingBehavior<E> extends JSMutableIndexable<E> {}
+
+// TODO(lrn): These exceptions should be implemented in core.
+// When they are, remove the 'Implementation' here.
+
+/// Thrown by type assertions that fail.
+class TypeErrorImplementation extends Error implements TypeError {
+ final String message;
+
+ /// Normal type error caused by a failed subtype test.
+ TypeErrorImplementation(Object value, String type)
+ : message = "TypeError: ${Error.safeToString(value)}: type "
+ "'${_typeDescription(value)}' is not a subtype of type '$type'";
+
+ TypeErrorImplementation.fromMessage(String this.message);
+
+ String toString() => message;
+}
+
+/// Thrown by the 'as' operator if the cast isn't valid.
+class CastErrorImplementation extends Error implements CastError {
+ // TODO(lrn): Rename to CastError (and move implementation into core).
+ final String message;
+
+ /// Normal cast error caused by a failed type cast.
+ CastErrorImplementation(Object value, Object type)
+ : message = "CastError: ${Error.safeToString(value)}: type "
+ "'${_typeDescription(value)}' is not a subtype of type '$type'";
+
+ String toString() => message;
+}
+
+String _typeDescription(value) {
+ if (value is Closure) {
+ var functionTypeObject = extractFunctionTypeObjectFrom(value);
+ if (functionTypeObject != null) {
+ return runtimeTypeToString(functionTypeObject);
+ }
+ return 'Closure';
+ }
+ return Primitives.objectTypeName(value);
+}
+
+class FallThroughErrorImplementation extends FallThroughError {
+ FallThroughErrorImplementation();
+ String toString() => 'Switch case fall-through.';
+}
+
+/// Helper function for implementing asserts. The compiler treats this
+/// specially.
+///
+/// Returns the negation of the condition. That is: `true` if the assert should
+/// fail.
+bool assertTest(condition) {
+ // Do bool success check first, it is common and faster than 'is Function'.
+ if (true == condition) return false;
+ if (condition is bool) return !condition;
+ throw new TypeErrorImplementation(condition, 'bool');
+}
+
+/// Helper function for implementing asserts with messages.
+/// The compiler treats this specially.
+void assertThrow(Object message) {
+ throw new _AssertionError(message);
+}
+
+/// Helper function for implementing asserts without messages.
+/// The compiler treats this specially.
+@pragma('dart2js:noInline')
+void assertHelper(condition) {
+ if (assertTest(condition)) throw new AssertionError();
+}
+
+/// Called by generated code when a method that must be statically
+/// resolved cannot be found.
+void throwNoSuchMethod(obj, name, arguments, expectedArgumentNames) {
+ Symbol memberName = new _symbol_dev.Symbol.unvalidated(name);
+ throw new NoSuchMethodError(obj, memberName, arguments,
+ new Map<Symbol, dynamic>(), expectedArgumentNames);
+}
+
+/// Called by generated code when a static field's initializer references the
+/// field that is currently being initialized.
+void throwCyclicInit(String staticName) {
+ throw new CyclicInitializationError(staticName);
+}
+
+/// Error thrown when a runtime error occurs.
+class RuntimeError extends Error {
+ final message;
+ RuntimeError(this.message);
+ String toString() => 'RuntimeError: $message';
+}
+
+class DeferredNotLoadedError extends Error implements NoSuchMethodError {
+ String libraryName;
+
+ DeferredNotLoadedError(this.libraryName);
+
+ String toString() {
+ return 'Deferred library $libraryName was not loaded.';
+ }
+}
+
+// TODO(ahe): Remove this class and call noSuchMethod instead.
+class UnimplementedNoSuchMethodError extends Error
+ implements NoSuchMethodError {
+ final String _message;
+
+ UnimplementedNoSuchMethodError(this._message);
+
+ String toString() => 'Unsupported operation: $_message';
+}
+
+/// Creates a random number with 64 bits of randomness.
+///
+/// This will be truncated to the 53 bits available in a double.
+int random64() {
+ // TODO(lrn): Use a secure random source.
+ int int32a = JS('int', '(Math.random() * 0x100000000) >>> 0');
+ int int32b = JS('int', '(Math.random() * 0x100000000) >>> 0');
+ return int32a + int32b * 0x100000000;
+}
+
+String jsonEncodeNative(String string) {
+ return JS('String', 'JSON.stringify(#)', string);
+}
+
+/// Returns a property name for placing data on JavaScript objects shared
+/// between DOM isolates. This happens when multiple programs are loaded in the
+/// same JavaScript context (i.e. page). The name is based on [name] but with
+/// an additional part that is unique for each isolate.
+///
+/// The form of the name is '___dart_$name_$id'.
+String getIsolateAffinityTag(String name) {
+ var isolateTagGetter = JS_EMBEDDED_GLOBAL('', GET_ISOLATE_TAG);
+ return JS('String', '#(#)', isolateTagGetter, name);
+}
+
+typedef Future<Null> LoadLibraryFunctionType();
+
+LoadLibraryFunctionType _loadLibraryWrapper(String loadId) {
+ return () => loadDeferredLibrary(loadId);
+}
+
+final Map<String, Future<Null>> _loadingLibraries = <String, Future<Null>>{};
+final Set<String> _loadedLibraries = new Set<String>();
+
+/// Events used to diagnose failures from deferred loading requests.
+final List<String> _eventLog = <String>[];
+
+typedef void DeferredLoadCallback();
+
+// Function that will be called every time a new deferred import is loaded.
+DeferredLoadCallback deferredLoadHook;
+
+Future<Null> loadDeferredLibrary(String loadId) {
+ // For each loadId there is a list of parts to load. The parts are represented
+ // by an index. There are two arrays, one that maps the index into a Uri and
+ // another that maps the index to a hash.
+ var partsMap = JS_EMBEDDED_GLOBAL('', DEFERRED_LIBRARY_PARTS);
+ List indexes = JS('JSExtendableArray|Null', '#[#]', partsMap, loadId);
+ if (indexes == null) return new Future.value(null);
+ List<String> uris = <String>[];
+ List<String> hashes = <String>[];
+ List index2uri = JS_EMBEDDED_GLOBAL('JSArray', DEFERRED_PART_URIS);
+ List index2hash = JS_EMBEDDED_GLOBAL('JSArray', DEFERRED_PART_HASHES);
+ for (int i = 0; i < indexes.length; i++) {
+ int index = JS('int', '#[#]', indexes, i);
+ uris.add(JS('String', '#[#]', index2uri, index));
+ hashes.add(JS('String', '#[#]', index2hash, index));
+ }
+
+ int total = hashes.length;
+ assert(total == uris.length);
+ List<bool> waitingForLoad = new List.filled(total, true);
+ int nextHunkToInitialize = 0;
+ var isHunkLoaded = JS_EMBEDDED_GLOBAL('', IS_HUNK_LOADED);
+ var isHunkInitialized = JS_EMBEDDED_GLOBAL('', IS_HUNK_INITIALIZED);
+ var initializer = JS_EMBEDDED_GLOBAL('', INITIALIZE_LOADED_HUNK);
+
+ void initializeSomeLoadedHunks() {
+ for (int i = nextHunkToInitialize; i < total; ++i) {
+ // A hunk is initialized only if all the preceeding hunks have been
+ // initialized.
+ if (waitingForLoad[i]) return;
+ nextHunkToInitialize++;
+
+ // It is possible for a hash to be repeated. This happens when two
+ // different parts both end up empty. Checking in the loop rather than
+ // pre-filtering prevents duplicate hashes leading to duplicated
+ // initializations.
+ // TODO(29572): Merge small parts.
+ // TODO(29635): Remove duplicate parts from tables and output files.
+ var uri = uris[i];
+ var hash = hashes[i];
+ if (JS('bool', '#(#)', isHunkInitialized, hash)) {
+ _eventLog.add(' - already initialized: $uri ($hash)');
+ continue;
+ }
+ // On strange scenarios, e.g. if js encounters parse errors, we might get
+ // an "success" callback on the script load but the hunk will be null.
+ if (JS('bool', '#(#)', isHunkLoaded, hash)) {
+ _eventLog.add(' - initialize: $uri ($hash)');
+ JS('void', '#(#)', initializer, hash);
+ } else {
+ _eventLog.add(' - missing hunk: $uri ($hash)');
+ throw new DeferredLoadException("Loading ${uris[i]} failed: "
+ "the code with hash '${hash}' was not loaded.\n"
+ "event log:\n${_eventLog.join("\n")}\n");
+ }
+ }
+ }
+
+ Future loadAndInitialize(int i) {
+ if (JS('bool', '#(#)', isHunkLoaded, hashes[i])) {
+ waitingForLoad[i] = false;
+ return new Future.value();
+ }
+ return _loadHunk(uris[i]).then((_) {
+ waitingForLoad[i] = false;
+ initializeSomeLoadedHunks();
+ });
+ }
+
+ return Future.wait(new List.generate(total, loadAndInitialize)).then((_) {
+ initializeSomeLoadedHunks();
+ // At this point all hunks have been loaded, so there should be no pending
+ // initializations to do.
+ assert(nextHunkToInitialize == total);
+ bool updated = _loadedLibraries.add(loadId);
+ if (updated && deferredLoadHook != null) {
+ deferredLoadHook();
+ }
+ });
+}
+
+/// The `nonce` value on the current script used for strict-CSP, if any.
+String _cspNonce = _computeCspNonce();
+
+String _computeCspNonce() {
+ var currentScript = JS_EMBEDDED_GLOBAL('', CURRENT_SCRIPT);
+ if (currentScript == null) return null;
+ String nonce = JS('String|Null', '#.nonce', currentScript);
+ return (nonce != null && nonce != '')
+ ? nonce
+ : JS('String|Null', '#.getAttribute("nonce")', currentScript);
+}
+
+/// The 'crossOrigin' value on the current script used for CORS, if any.
+String _crossOrigin = _computeCrossOrigin();
+
+String _computeCrossOrigin() {
+ var currentScript = JS_EMBEDDED_GLOBAL('', CURRENT_SCRIPT);
+ if (currentScript == null) return null;
+ return JS('String|Null', '#.crossOrigin', currentScript);
+}
+
+/// Returns true if we are currently in a worker context.
+bool _isWorker() {
+ requiresPreamble();
+ return JS('', '!self.window && !!self.postMessage');
+}
+
+/// The src url for the script tag that loaded this code.
+String thisScript = _computeThisScript();
+
+/// The src url for the script tag that loaded this function.
+///
+/// Used to create JavaScript workers and load deferred libraries.
+String _computeThisScript() {
+ var currentScript = JS_EMBEDDED_GLOBAL('', CURRENT_SCRIPT);
+ if (currentScript != null) {
+ return JS('String', 'String(#.src)', currentScript);
+ }
+ // A worker has no script tag - so get an url from a stack-trace.
+ if (_isWorker()) return _computeThisScriptFromTrace();
+ // An isolate that doesn't support workers, but doesn't have a
+ // currentScript either. This is most likely a Chrome extension.
+ return null;
+}
+
+String _computeThisScriptFromTrace() {
+ var stack = JS('String|Null', 'new Error().stack');
+ if (stack == null) {
+ // According to Internet Explorer documentation, the stack
+ // property is not set until the exception is thrown. The stack
+ // property was not provided until IE10.
+ stack = JS(
+ 'String|Null',
+ '(function() {'
+ 'try { throw new Error() } catch(e) { return e.stack }'
+ '})()');
+ if (stack == null) throw new UnsupportedError('No stack trace');
+ }
+ var pattern, matches;
+
+ // This pattern matches V8, Chrome, and Internet Explorer stack
+ // traces that look like this:
+ // Error
+ // at methodName (URI:LINE:COLUMN)
+ pattern = JS('', r'new RegExp("^ *at [^(]*\\((.*):[0-9]*:[0-9]*\\)$", "m")');
+
+ matches = JS('JSExtendableArray|Null', '#.match(#)', stack, pattern);
+ if (matches != null) return JS('String', '#[1]', matches);
+
+ // This pattern matches Firefox stack traces that look like this:
+ // methodName@URI:LINE
+ pattern = JS('', r'new RegExp("^[^@]*@(.*):[0-9]*$", "m")');
+
+ matches = JS('JSExtendableArray|Null', '#.match(#)', stack, pattern);
+ if (matches != null) return JS('String', '#[1]', matches);
+
+ throw new UnsupportedError('Cannot extract URI from "$stack"');
+}
+
+Future<Null> _loadHunk(String hunkName) {
+ Future<Null> future = _loadingLibraries[hunkName];
+ _eventLog.add(' - _loadHunk: $hunkName');
+ if (future != null) {
+ _eventLog.add('reuse: $hunkName');
+ return future.then((_) => null);
+ }
+
+ String uri = thisScript;
+
+ int index = uri.lastIndexOf('/');
+ uri = '${uri.substring(0, index + 1)}$hunkName';
+ _eventLog.add(' - download: $hunkName from $uri');
+
+ var deferredLibraryLoader = JS('', 'self.dartDeferredLibraryLoader');
+ Completer<Null> completer = new Completer<Null>();
+
+ void success() {
+ _eventLog.add(' - download success: $hunkName');
+ completer.complete(null);
+ }
+
+ void failure(error, String context, StackTrace stackTrace) {
+ _eventLog.add(' - download failed: $hunkName (context: $context)');
+ _loadingLibraries[hunkName] = null;
+ stackTrace ??= StackTrace.current;
+ completer.completeError(
+ new DeferredLoadException('Loading $uri failed: $error\n'
+ 'event log:\n${_eventLog.join("\n")}\n'),
+ stackTrace);
+ }
+
+ var jsSuccess = convertDartClosureToJS(success, 0);
+ var jsFailure = convertDartClosureToJS((error) {
+ failure(unwrapException(error), 'js-failure-wrapper',
+ getTraceFromException(error));
+ }, 1);
+
+ if (JS('bool', 'typeof # === "function"', deferredLibraryLoader)) {
+ try {
+ JS('void', '#(#, #, #)', deferredLibraryLoader, uri, jsSuccess,
+ jsFailure);
+ } catch (error, stackTrace) {
+ failure(error, "invoking dartDeferredLibraryLoader hook", stackTrace);
+ }
+ } else if (_isWorker()) {
+ // We are in a web worker. Load the code with an XMLHttpRequest.
+ int index = uri.lastIndexOf('/');
+ uri = '${uri.substring(0, index + 1)}$hunkName';
+ var xhr = JS('var', 'new XMLHttpRequest()');
+ JS('void', '#.open("GET", #)', xhr, uri);
+ JS(
+ 'void',
+ '#.addEventListener("load", #, false)',
+ xhr,
+ convertDartClosureToJS((event) {
+ int status = JS('int', '#.status', xhr);
+ if (status != 200) {
+ failure('Request status: $status', 'worker xhr', null);
+ }
+ String code = JS('String', '#.responseText', xhr);
+ try {
+ // Create a new function to avoid getting access to current function
+ // context.
+ JS('void', '(new Function(#))()', code);
+ success();
+ } catch (error, stackTrace) {
+ failure(error, 'evaluating the code in worker xhr', stackTrace);
+ }
+ }, 1));
+
+ JS('void', '#.addEventListener("error", #, false)', xhr, (e) {
+ failure(e, 'xhr error handler', null);
+ });
+ JS('void', '#.addEventListener("abort", #, false)', xhr, (e) {
+ failure(e, 'xhr abort handler', null);
+ });
+ JS('void', '#.send()', xhr);
+ } else {
+ // We are in a dom-context.
+ // Inject a script tag.
+ var script = JS('', 'document.createElement("script")');
+ JS('', '#.type = "text/javascript"', script);
+ JS('', '#.src = #', script, uri);
+ if (_cspNonce != null && _cspNonce != '') {
+ JS('', '#.nonce = #', script, _cspNonce);
+ JS('', '#.setAttribute("nonce", #)', script, _cspNonce);
+ }
+ if (_crossOrigin != null && _crossOrigin != '') {
+ JS('', '#.crossOrigin = #', script, _crossOrigin);
+ }
+ JS('', '#.addEventListener("load", #, false)', script, jsSuccess);
+ JS('', '#.addEventListener("error", #, false)', script, jsFailure);
+ JS('', 'document.body.appendChild(#)', script);
+ }
+ _loadingLibraries[hunkName] = completer.future;
+ return completer.future;
+}
+
+class MainError extends Error implements NoSuchMethodError {
+ final String _message;
+
+ MainError(this._message);
+
+ String toString() => 'NoSuchMethodError: $_message';
+}
+
+void missingMain() {
+ throw new MainError("No top-level function named 'main'.");
+}
+
+void badMain() {
+ throw new MainError("'main' is not a function.");
+}
+
+void mainHasTooManyParameters() {
+ throw new MainError("'main' expects too many parameters.");
+}
+
+class _AssertionError extends AssertionError {
+ _AssertionError(Object message) : super(message);
+
+ String toString() => "Assertion failed: " + Error.safeToString(message);
+}
+
+// [_UnreachableError] is a separate class because we always resolve
+// [assertUnreachable] and want to reduce the impact of resolving possibly
+// unneeded code.
+class _UnreachableError extends AssertionError {
+ _UnreachableError();
+ String toString() => 'Assertion failed: Reached dead code';
+}
+
+@pragma('dart2js:noInline')
+void assertUnreachable() {
+ throw new _UnreachableError();
+}
+
+// Hook to register new global object if necessary.
+// This is currently a no-op in dart2js.
+void registerGlobalObject(object) {}
+
+// Hook to register new browser classes.
+// This is currently a no-op in dart2js.
+void applyExtension(name, nativeObject) {}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_names.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_names.dart
new file mode 100644
index 0000000..cb4aa0e
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_names.dart
@@ -0,0 +1,167 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._js_names;
+
+import 'dart:_js_embedded_names'
+ show JsGetName, MANGLED_GLOBAL_NAMES, MANGLED_NAMES;
+
+import 'dart:_foreign_helper' show JS, JS_EMBEDDED_GLOBAL, JS_GET_NAME;
+
+import 'dart:_js_helper' show JsCache, NoInline;
+
+import 'dart:_interceptors' show JSArray;
+
+/// No-op method that is called to inform the compiler that unmangled named
+/// must be preserved.
+preserveNames() {}
+
+/// A map from mangled names to "reflective" names, that is, unmangled names
+/// with some additional information, such as, number of required arguments.
+/// This map is for mangled names used as instance members.
+final _LazyMangledNamesMap mangledNames = new _LazyMangledInstanceNamesMap(
+ JS_EMBEDDED_GLOBAL('=Object', MANGLED_NAMES));
+
+/// A map from "reflective" names to mangled names (the reverse of
+/// [mangledNames]).
+final _LazyReflectiveNamesMap reflectiveNames = new _LazyReflectiveNamesMap(
+ JS_EMBEDDED_GLOBAL('=Object', MANGLED_NAMES), true);
+
+/// A map from mangled names to "reflective" names (see [mangledNames]). This
+/// map is for globals, that is, static and top-level members.
+final _LazyMangledNamesMap mangledGlobalNames = new _LazyMangledNamesMap(
+ JS_EMBEDDED_GLOBAL('=Object', MANGLED_GLOBAL_NAMES));
+
+/// A map from "reflective" names to mangled names (the reverse of
+/// [mangledGlobalNames]).
+final _LazyReflectiveNamesMap reflectiveGlobalNames =
+ new _LazyReflectiveNamesMap(
+ JS_EMBEDDED_GLOBAL('=Object', MANGLED_GLOBAL_NAMES), false);
+
+/// Implements a mapping from mangled names to their reflective counterparts.
+/// The propertiy names of [_jsMangledNames] are the mangled names, and the
+/// values are the "reflective" names.
+class _LazyMangledNamesMap {
+ /// [_jsMangledNames] is a JavaScript object literal.
+ var _jsMangledNames;
+
+ _LazyMangledNamesMap(this._jsMangledNames);
+
+ String operator [](String key) {
+ var result = JS('var', '#[#]', _jsMangledNames, key);
+ // Filter out all non-string values to protect against polution from
+ // ancillary fields in [_jsMangledNames].
+ bool filter = JS('bool', 'typeof # !== "string"', result);
+ // To ensure that the inferrer sees that result is a String, we explicitly
+ // give it a better type here.
+ return filter ? null : JS('String', '#', result);
+ }
+}
+
+/// Extends [_LazyMangledNamesMap] with additional support for adding mappings
+/// from mangled setter names to their reflective counterpart by rewriting a
+/// corresponding entry for a getter name, if it exists.
+class _LazyMangledInstanceNamesMap extends _LazyMangledNamesMap {
+ _LazyMangledInstanceNamesMap(_jsMangledNames) : super(_jsMangledNames);
+
+ String operator [](String key) {
+ String result = super[key];
+ String setterPrefix = JS_GET_NAME(JsGetName.SETTER_PREFIX);
+ if (result == null && key.startsWith(setterPrefix)) {
+ String getterPrefix = JS_GET_NAME(JsGetName.GETTER_PREFIX);
+ int setterPrefixLength = setterPrefix.length;
+
+ // Generate the setter name from the getter name.
+ key = '$getterPrefix${key.substring(setterPrefixLength)}';
+ result = super[key];
+ return (result != null) ? "${result}=" : null;
+ }
+ return result;
+ }
+}
+
+/// Implements the inverse of [_LazyMangledNamesMap]. As it would be too
+/// expensive to search the mangled names map for a value that corresponds to
+/// the lookup key on each invocation, we compute the full mapping in demand
+/// and cache it. The cache is invalidated when the underlying [_jsMangledNames]
+/// object changes its length. This condition is sufficient as the name mapping
+/// can only grow over time.
+/// When [_isInstance] is true, we also apply the inverse of the setter/getter
+/// name conversion implemented by [_LazyMangledInstanceNamesMap].
+class _LazyReflectiveNamesMap {
+ /// [_jsMangledNames] is a JavaScript object literal.
+ final _jsMangledNames;
+ final bool _isInstance;
+ int _cacheLength = 0;
+ Map<String, String> _cache;
+
+ _LazyReflectiveNamesMap(this._jsMangledNames, this._isInstance);
+
+ Map<String, String> _updateReflectiveNames() {
+ preserveNames();
+ Map<String, String> result = <String, String>{};
+ List keys = JS('List', 'Object.keys(#)', _jsMangledNames);
+ for (String key in keys) {
+ var reflectiveName = JS('var', '#[#]', _jsMangledNames, key);
+ // Filter out all non-string values to protect against polution from
+ // ancillary fields in [_jsMangledNames].
+ bool filter = JS('bool', 'typeof # !== "string"', reflectiveName);
+ if (filter) continue;
+ result[reflectiveName] = JS('String', '#', key);
+
+ String getterPrefix = JS_GET_NAME(JsGetName.GETTER_PREFIX);
+ if (_isInstance && key.startsWith(getterPrefix)) {
+ int getterPrefixLength = getterPrefix.length;
+ String setterPrefix = JS_GET_NAME(JsGetName.SETTER_PREFIX);
+ result['$reflectiveName='] =
+ '$setterPrefix${key.substring(getterPrefixLength)}';
+ }
+ }
+ return result;
+ }
+
+ int get _jsMangledNamesLength =>
+ JS('int', 'Object.keys(#).length', _jsMangledNames);
+
+ String operator [](String key) {
+ if (_cache == null || _jsMangledNamesLength != _cacheLength) {
+ _cache = _updateReflectiveNames();
+ _cacheLength = _jsMangledNamesLength;
+ }
+ return _cache[key];
+ }
+}
+
+@pragma('dart2js:noInline')
+List extractKeys(victim) {
+ var result = JS('', '# ? Object.keys(#) : []', victim, victim);
+ return new JSArray.markFixed(result);
+}
+
+/// Returns the (global) unmangled version of [name].
+///
+/// Normally, you should use [mangledGlobalNames] directly, but this method
+/// doesn't tell the compiler to preserve names. So this method only returns a
+/// non-null value if some other component has made the compiler preserve names.
+///
+/// This is used, for example, to return unmangled names from TypeImpl.toString
+/// *if* names are being preserved for other reasons (use of dart:mirrors, for
+/// example).
+String unmangleGlobalNameIfPreservedAnyways(String name) {
+ var names = JS_EMBEDDED_GLOBAL('', MANGLED_GLOBAL_NAMES);
+ return JS('String|Null', '#', JsCache.fetch(names, name));
+}
+
+String unmangleAllIdentifiersIfPreservedAnyways(String str) {
+ return JS(
+ 'String',
+ r'''
+ (function(str, names) {
+ return str.replace(
+ /[^<,> ]+/g,
+ function(m) { return names[m] || m; });
+ })(#, #)''',
+ str,
+ JS_EMBEDDED_GLOBAL('', MANGLED_GLOBAL_NAMES));
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_number.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_number.dart
new file mode 100644
index 0000000..918c1ba
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_number.dart
@@ -0,0 +1,707 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _interceptors;
+
+/// The super interceptor class for [JSInt] and [JSDouble]. The compiler
+/// recognizes this class as an interceptor, and changes references to
+/// [:this:] to actually use the receiver of the method, which is
+/// generated as an extra argument added to each member.
+///
+/// Note that none of the methods here delegate to a method defined on JSInt or
+/// JSDouble. This is exploited in [tryComputeConstantInterceptor].
+class JSNumber extends Interceptor implements double {
+ const JSNumber();
+
+ int compareTo(num b) {
+ if (b is! num) throw argumentErrorValue(b);
+ if (this < b) {
+ return -1;
+ } else if (this > b) {
+ return 1;
+ } else if (this == b) {
+ if (this == 0) {
+ bool bIsNegative = b.isNegative;
+ if (isNegative == bIsNegative) return 0;
+ if (isNegative) return -1;
+ return 1;
+ }
+ return 0;
+ } else if (isNaN) {
+ if (b.isNaN) {
+ return 0;
+ }
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+
+ bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0;
+
+ bool get isNaN => JS(
+ 'returns:bool;effects:none;depends:none;throws:never;gvn:true',
+ r'isNaN(#)',
+ this);
+
+ bool get isInfinite {
+ return JS('bool', r'# == (1/0)', this) || JS('bool', r'# == (-1/0)', this);
+ }
+
+ bool get isFinite => JS(
+ 'returns:bool;effects:none;depends:none;throws:never;gvn:true',
+ r'isFinite(#)',
+ this);
+
+ JSNumber remainder(num b) {
+ if (b is! num) throw argumentErrorValue(b);
+ return JS('num', r'# % #', this, b);
+ }
+
+ // Use invoke_dynamic_specializer instead of inlining.
+ @pragma('dart2js:noInline')
+ JSNumber abs() => JS(
+ 'returns:num;effects:none;depends:none;throws:never;gvn:true',
+ r'Math.abs(#)',
+ this);
+
+ JSNumber get sign => this > 0 ? 1 : this < 0 ? -1 : this;
+
+ static const int _MIN_INT32 = -0x80000000;
+ static const int _MAX_INT32 = 0x7FFFFFFF;
+
+ int toInt() {
+ if (this >= _MIN_INT32 && this <= _MAX_INT32) {
+ // 0 and -0.0 handled here.
+ return JS('int', '# | 0', this);
+ }
+ if (JS('bool', r'isFinite(#)', this)) {
+ return JS('int', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0.
+ }
+ // [this] is either NaN, Infinity or -Infinity.
+ throw new UnsupportedError(JS('String', '"" + # + ".toInt()"', this));
+ }
+
+ int truncate() => toInt();
+
+ int ceil() {
+ if (this >= 0) {
+ if (this <= _MAX_INT32) {
+ int truncated = JS('int', '# | 0', this); // converts -0.0 to 0.
+ return this == truncated ? truncated : truncated + 1;
+ }
+ } else {
+ if (this >= _MIN_INT32) {
+ return JS('int', '# | 0', this);
+ }
+ }
+ var d = JS('num', 'Math.ceil(#)', this);
+ if (JS('bool', r'isFinite(#)', d)) {
+ return JS('int', r'#', d);
+ }
+ // [this] is either NaN, Infinity or -Infinity.
+ throw new UnsupportedError(JS('String', '"" + # + ".ceil()"', this));
+ }
+
+ int floor() {
+ if (this >= 0) {
+ if (this <= _MAX_INT32) {
+ return JS('int', '# | 0', this);
+ }
+ } else {
+ if (this >= _MIN_INT32) {
+ int truncated = JS('int', '# | 0', this);
+ return this == truncated ? truncated : truncated - 1;
+ }
+ }
+ var d = JS('num', 'Math.floor(#)', this);
+ if (JS('bool', r'isFinite(#)', d)) {
+ return JS('int', r'#', d);
+ }
+ // [this] is either NaN, Infinity or -Infinity.
+ throw new UnsupportedError(JS('String', '"" + # + ".floor()"', this));
+ }
+
+ int round() {
+ if (this > 0) {
+ // This path excludes the special cases -0.0, NaN and -Infinity, leaving
+ // only +Infinity, for which a direct test is faster than [isFinite].
+ if (JS('bool', r'# !== (1/0)', this)) {
+ return JS('int', r'Math.round(#)', this);
+ }
+ } else if (JS('bool', '# > (-1/0)', this)) {
+ // This test excludes NaN and -Infinity, leaving only -0.0.
+ //
+ // Subtraction from zero rather than negation forces -0.0 to 0.0 so code
+ // inside Math.round and code to handle result never sees -0.0, which on
+ // some JavaScript VMs can be a slow path.
+ return JS('int', r'0 - Math.round(0 - #)', this);
+ }
+ // [this] is either NaN, Infinity or -Infinity.
+ throw new UnsupportedError(JS('String', '"" + # + ".round()"', this));
+ }
+
+ double ceilToDouble() => JS('num', r'Math.ceil(#)', this);
+
+ double floorToDouble() => JS('num', r'Math.floor(#)', this);
+
+ double roundToDouble() {
+ if (this < 0) {
+ return JS('num', r'-Math.round(-#)', this);
+ } else {
+ return JS('num', r'Math.round(#)', this);
+ }
+ }
+
+ double truncateToDouble() => this < 0 ? ceilToDouble() : floorToDouble();
+
+ num clamp(lowerLimit, upperLimit) {
+ if (lowerLimit is! num) throw argumentErrorValue(lowerLimit);
+ if (upperLimit is! num) throw argumentErrorValue(upperLimit);
+ if (lowerLimit.compareTo(upperLimit) > 0) {
+ throw argumentErrorValue(lowerLimit);
+ }
+ if (this.compareTo(lowerLimit) < 0) return lowerLimit;
+ if (this.compareTo(upperLimit) > 0) return upperLimit;
+ return this;
+ }
+
+ // The return type is intentionally omitted to avoid type checker warnings
+ // from assigning JSNumber to double.
+ toDouble() => this;
+
+ String toStringAsFixed(int fractionDigits) {
+ checkInt(fractionDigits);
+ if (fractionDigits < 0 || fractionDigits > 20) {
+ throw new RangeError.range(fractionDigits, 0, 20, 'fractionDigits');
+ }
+ String result = JS('String', r'#.toFixed(#)', this, fractionDigits);
+ if (this == 0 && isNegative) return '-$result';
+ return result;
+ }
+
+ String toStringAsExponential([int fractionDigits]) {
+ String result;
+ if (fractionDigits != null) {
+ checkInt(fractionDigits);
+ if (fractionDigits < 0 || fractionDigits > 20) {
+ throw new RangeError.range(fractionDigits, 0, 20, 'fractionDigits');
+ }
+ result = JS('String', r'#.toExponential(#)', this, fractionDigits);
+ } else {
+ result = JS('String', r'#.toExponential()', this);
+ }
+ if (this == 0 && isNegative) return '-$result';
+ return result;
+ }
+
+ String toStringAsPrecision(int precision) {
+ checkInt(precision);
+ if (precision < 1 || precision > 21) {
+ throw new RangeError.range(precision, 1, 21, 'precision');
+ }
+ String result = JS('String', r'#.toPrecision(#)', this, precision);
+ if (this == 0 && isNegative) return '-$result';
+ return result;
+ }
+
+ String toRadixString(int radix) {
+ checkInt(radix);
+ if (radix < 2 || radix > 36) {
+ throw new RangeError.range(radix, 2, 36, 'radix');
+ }
+ String result = JS('String', r'#.toString(#)', this, radix);
+ const int rightParenCode = 0x29;
+ if (result.codeUnitAt(result.length - 1) != rightParenCode) {
+ return result;
+ }
+ return _handleIEtoString(result);
+ }
+
+ static String _handleIEtoString(String result) {
+ // Result is probably IE's untraditional format for large numbers,
+ // e.g., "8.0000000000008(e+15)" for 0x8000000000000800.toString(16).
+ var match = JS('JSArray|Null',
+ r'/^([\da-z]+)(?:\.([\da-z]+))?\(e\+(\d+)\)$/.exec(#)', result);
+ if (match == null) {
+ // Then we don't know how to handle it at all.
+ throw new UnsupportedError('Unexpected toString result: $result');
+ }
+ result = JS('String', '#', match[1]);
+ int exponent = JS('int', '+#', match[3]);
+ if (match[2] != null) {
+ result = JS('String', '# + #', result, match[2]);
+ exponent -= JS('int', '#.length', match[2]);
+ }
+ return result + '0' * exponent;
+ }
+
+ // Note: if you change this, also change the function [S].
+ String toString() {
+ if (this == 0 && JS('bool', '(1 / #) < 0', this)) {
+ return '-0.0';
+ } else {
+ return JS('String', r'"" + (#)', this);
+ }
+ }
+
+ int get hashCode {
+ int intValue = JS('int', '# | 0', this);
+ // Fast exit for integers in signed 32-bit range. Masking converts -0.0 to 0
+ // and ensures that result fits in JavaScript engine's Smi range.
+ if (this == intValue) return 0x1FFFFFFF & intValue;
+
+ // We would like to access the exponent and mantissa as integers but there
+ // are no JavaScript operations that do this, so use log2-floor-pow-divide
+ // to extract the values.
+ num absolute = JS('num', 'Math.abs(#)', this);
+ num lnAbsolute = JS('num', 'Math.log(#)', absolute);
+ num log2 = lnAbsolute / ln2;
+ // Floor via '# | 0' converts NaN to zero so the final result is not NaN.
+ int floorLog2 = JS('int', '# | 0', log2);
+ num factor = JS('num', 'Math.pow(2, #)', floorLog2);
+ num scaled = absolute < 1 ? absolute / factor : factor / absolute;
+ // [scaled] is in the range [0.5, 1].
+
+ // Multiply and truncate to pick up all the mantissa bits. Multiplying by
+ // 0x20000000000000 (which has 53 zero bits) converts the mantissa into an
+ // integer. There are interesting subsets where all the bit variance is in
+ // the most significant bits of the mantissa (e.g. 0.5, 0.625, 0.75), so we
+ // need to mix in the most significant bits. We do this by scaling with a
+ // constant that has many bits set to use the multiplier to mix in bits from
+ // all over the mantissa into low positions.
+ num rescaled1 = scaled * 0x20000000000000;
+ num rescaled2 = scaled * 0x0C95A6C285A6C9;
+ int d1 = JS('int', '# | 0', rescaled1);
+ int d2 = JS('int', '# | 0', rescaled2);
+ // Mix in exponent to distinguish e.g. 1.25 from 2.5.
+ int d3 = floorLog2;
+ int h = 0x1FFFFFFF & ((d1 + d2) * (601 * 997) + d3 * (1259));
+ return h;
+ }
+
+ JSNumber operator -() => JS('num', r'-#', this);
+
+ JSNumber operator +(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ return JS('num', '# + #', this, other);
+ }
+
+ JSNumber operator -(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ return JS('num', '# - #', this, other);
+ }
+
+ double operator /(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ return JS('num', '# / #', this, other);
+ }
+
+ JSNumber operator *(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ return JS('num', '# * #', this, other);
+ }
+
+ JSNumber operator %(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ // Euclidean Modulo.
+ num result = JS('num', r'# % #', this, other);
+ if (result == 0) return JS('num', '0'); // Make sure we don't return -0.0.
+ if (result > 0) return result;
+ if (JS('num', '#', other) < 0) {
+ return result - JS('num', '#', other);
+ } else {
+ return result + JS('num', '#', other);
+ }
+ }
+
+ bool _isInt32(value) => JS('bool', '(# | 0) === #', value, value);
+
+ int operator ~/(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ if (false) _tdivFast(other); // Ensure resolution.
+ if (_isInt32(this)) {
+ if (other >= 1 || other < -1) {
+ return JS('int', r'(# / #) | 0', this, other);
+ }
+ }
+ return _tdivSlow(other);
+ }
+
+ int _tdivFast(num other) {
+ // [other] is known to be a number outside the range [-1, 1).
+ return _isInt32(this)
+ ? JS('int', r'(# / #) | 0', this, other)
+ : _tdivSlow(other);
+ }
+
+ int _tdivSlow(num other) {
+ var quotient = JS('num', r'# / #', this, other);
+ if (quotient >= _MIN_INT32 && quotient <= _MAX_INT32) {
+ // This path includes -0.0 and +0.0.
+ return JS('int', '# | 0', quotient);
+ }
+ if (quotient > 0) {
+ // This path excludes the special cases -0.0, NaN and -Infinity, leaving
+ // only +Infinity, for which a direct test is faster than [isFinite].
+ if (JS('bool', r'# !== (1/0)', quotient)) {
+ return JS('int', r'Math.floor(#)', quotient);
+ }
+ } else if (JS('bool', '# > (-1/0)', quotient)) {
+ // This test excludes NaN and -Infinity.
+ return JS('int', r'Math.ceil(#)', quotient);
+ }
+
+ // [quotient] is either NaN, Infinity or -Infinity.
+ throw new UnsupportedError(
+ 'Result of truncating division is $quotient: $this ~/ $other');
+ }
+
+ // TODO(ngeoffray): Move the bit operations below to [JSInt] and
+ // make them take an int. Because this will make operations slower,
+ // we define these methods on number for now but we need to decide
+ // the grain at which we do the type checks.
+
+ num operator <<(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ if (JS('num', '#', other) < 0) throw argumentErrorValue(other);
+ return _shlPositive(other);
+ }
+
+ num _shlPositive(num other) {
+ // JavaScript only looks at the last 5 bits of the shift-amount. Shifting
+ // by 33 is hence equivalent to a shift by 1.
+ return JS('bool', r'# > 31', other)
+ ? 0
+ : JS('JSUInt32', r'(# << #) >>> 0', this, other);
+ }
+
+ num operator >>(num other) {
+ if (false) _shrReceiverPositive(other);
+ if (other is! num) throw argumentErrorValue(other);
+ if (JS('num', '#', other) < 0) throw argumentErrorValue(other);
+ return _shrOtherPositive(other);
+ }
+
+ num _shrOtherPositive(num other) {
+ return JS('num', '#', this) > 0
+ ? _shrBothPositive(other)
+ // For negative numbers we just clamp the shift-by amount.
+ // `this` could be negative but not have its 31st bit set.
+ // The ">>" would then shift in 0s instead of 1s. Therefore
+ // we cannot simply return 0xFFFFFFFF.
+ : JS('JSUInt32', r'(# >> #) >>> 0', this, other > 31 ? 31 : other);
+ }
+
+ num _shrReceiverPositive(num other) {
+ if (JS('num', '#', other) < 0) throw argumentErrorValue(other);
+ return _shrBothPositive(other);
+ }
+
+ num _shrBothPositive(num other) {
+ return JS('bool', r'# > 31', other)
+ // JavaScript only looks at the last 5 bits of the shift-amount. In JS
+ // shifting by 33 is hence equivalent to a shift by 1. Shortcut the
+ // computation when that happens.
+ ? 0
+ // Given that `this` is positive we must not use '>>'. Otherwise a
+ // number that has the 31st bit set would be treated as negative and
+ // shift in ones.
+ : JS('JSUInt32', r'# >>> #', this, other);
+ }
+
+ num operator &(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ return JS('JSUInt32', r'(# & #) >>> 0', this, other);
+ }
+
+ num operator |(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ return JS('JSUInt32', r'(# | #) >>> 0', this, other);
+ }
+
+ num operator ^(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ return JS('JSUInt32', r'(# ^ #) >>> 0', this, other);
+ }
+
+ bool operator <(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ return JS('bool', '# < #', this, other);
+ }
+
+ bool operator >(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ return JS('bool', '# > #', this, other);
+ }
+
+ bool operator <=(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ return JS('bool', '# <= #', this, other);
+ }
+
+ bool operator >=(num other) {
+ if (other is! num) throw argumentErrorValue(other);
+ return JS('bool', '# >= #', this, other);
+ }
+
+ Type get runtimeType => num;
+}
+
+/// The interceptor class for [int]s.
+///
+/// This class implements double (indirectly through JSNumber) since in
+/// JavaScript all numbers are doubles, so while we want to treat `2.0` as an
+/// integer for some operations, its interceptor should answer `true` to `is
+/// double`.
+class JSInt extends JSNumber implements int {
+ const JSInt();
+
+ @override
+ // Use invoke_dynamic_specializer instead of inlining.
+ @pragma('dart2js:noInline')
+ JSInt abs() => JS(
+ 'returns:int;effects:none;depends:none;throws:never;gvn:true',
+ r'Math.abs(#)',
+ this);
+
+ @override
+ JSInt get sign => this > 0 ? 1 : this < 0 ? -1 : this;
+
+ @override
+ JSInt operator -() => JS('int', r'-#', this);
+
+ bool get isEven => (this & 1) == 0;
+
+ bool get isOdd => (this & 1) == 1;
+
+ int toUnsigned(int width) {
+ return this & ((1 << width) - 1);
+ }
+
+ int toSigned(int width) {
+ int signMask = 1 << (width - 1);
+ return (this & (signMask - 1)) - (this & signMask);
+ }
+
+ int get bitLength {
+ JSInt nonneg = this < 0 ? -this - 1 : this;
+ int wordBits = 32;
+ while (nonneg >= 0x100000000) {
+ nonneg = nonneg ~/ 0x100000000;
+ wordBits += 32;
+ }
+ return wordBits - _clz32(nonneg);
+ }
+
+ static int _clz32(int uint32) {
+ // TODO(sra): Use `Math.clz32(uint32)` (not available on IE11).
+ return 32 - _bitCount(_spread(uint32));
+ }
+
+ // Returns pow(this, e) % m.
+ int modPow(int e, int m) {
+ if (e is! int) {
+ throw ArgumentError.value(e, 'exponent', 'not an integer');
+ }
+ if (m is! int) {
+ throw ArgumentError.value(m, 'modulus', 'not an integer');
+ }
+ if (e < 0) throw RangeError.range(e, 0, null, 'exponent');
+ if (m <= 0) throw RangeError.range(m, 1, null, 'modulus');
+ if (e == 0) return 1;
+
+ const int maxPreciseInteger = 9007199254740991;
+
+ // Reject inputs that are outside the range of integer values that can be
+ // represented precisely as a Number (double).
+ if (this < -maxPreciseInteger || this > maxPreciseInteger) {
+ throw RangeError.range(
+ this, -maxPreciseInteger, maxPreciseInteger, 'receiver');
+ }
+ if (e > maxPreciseInteger) {
+ throw RangeError.range(e, 0, maxPreciseInteger, 'exponent');
+ }
+ if (m > maxPreciseInteger) {
+ throw RangeError.range(e, 1, maxPreciseInteger, 'modulus');
+ }
+
+ // This is floor(sqrt(maxPreciseInteger)).
+ const int maxValueThatCanBeSquaredWithoutTruncation = 94906265;
+ if (m > maxValueThatCanBeSquaredWithoutTruncation) {
+ // Use BigInt version to avoid truncation in multiplications below. The
+ // 'maxPreciseInteger' check on [m] ensures that toInt() does not round.
+ return BigInt.from(this).modPow(BigInt.from(e), BigInt.from(m)).toInt();
+ }
+
+ int b = this;
+ if (b < 0 || b > m) {
+ b %= m;
+ }
+ int r = 1;
+ while (e > 0) {
+ if (e.isOdd) {
+ r = (r * b) % m;
+ }
+ e ~/= 2;
+ b = (b * b) % m;
+ }
+ return r;
+ }
+
+ // If inv is false, returns gcd(x, y).
+ // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
+ // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
+ static int _binaryGcd(int x, int y, bool inv) {
+ int s = 1;
+ if (!inv) {
+ while (x.isEven && y.isEven) {
+ x ~/= 2;
+ y ~/= 2;
+ s *= 2;
+ }
+ if (y.isOdd) {
+ var t = x;
+ x = y;
+ y = t;
+ }
+ }
+ final bool ac = x.isEven;
+ int u = x;
+ int v = y;
+ int a = 1, b = 0, c = 0, d = 1;
+ do {
+ while (u.isEven) {
+ u ~/= 2;
+ if (ac) {
+ if (!a.isEven || !b.isEven) {
+ a += y;
+ b -= x;
+ }
+ a ~/= 2;
+ } else if (!b.isEven) {
+ b -= x;
+ }
+ b ~/= 2;
+ }
+ while (v.isEven) {
+ v ~/= 2;
+ if (ac) {
+ if (!c.isEven || !d.isEven) {
+ c += y;
+ d -= x;
+ }
+ c ~/= 2;
+ } else if (!d.isEven) {
+ d -= x;
+ }
+ d ~/= 2;
+ }
+ if (u >= v) {
+ u -= v;
+ if (ac) a -= c;
+ b -= d;
+ } else {
+ v -= u;
+ if (ac) c -= a;
+ d -= b;
+ }
+ } while (u != 0);
+ if (!inv) return s * v;
+ if (v != 1) throw new Exception('Not coprime');
+ if (d < 0) {
+ d += x;
+ if (d < 0) d += x;
+ } else if (d > x) {
+ d -= x;
+ if (d > x) d -= x;
+ }
+ return d;
+ }
+
+ // Returns 1/this % m, with m > 0.
+ int modInverse(int m) {
+ if (m is! int) {
+ throw new ArgumentError.value(m, 'modulus', 'not an integer');
+ }
+ if (m <= 0) throw new RangeError.range(m, 1, null, 'modulus');
+ if (m == 1) return 0;
+ int t = this;
+ if ((t < 0) || (t >= m)) t %= m;
+ if (t == 1) return 1;
+ if ((t == 0) || (t.isEven && m.isEven)) {
+ throw new Exception('Not coprime');
+ }
+ return _binaryGcd(m, t, true);
+ }
+
+ // Returns gcd of abs(this) and abs(other).
+ int gcd(int other) {
+ if (other is! int) {
+ throw new ArgumentError.value(other, 'other', 'not an integer');
+ }
+ int x = this.abs();
+ int y = other.abs();
+ if (x == 0) return y;
+ if (y == 0) return x;
+ if ((x == 1) || (y == 1)) return 1;
+ return _binaryGcd(x, y, false);
+ }
+
+ // Assumes i is <= 32-bit and unsigned.
+ static int _bitCount(int i) {
+ // See "Hacker's Delight", section 5-1, "Counting 1-Bits".
+
+ // The basic strategy is to use "divide and conquer" to
+ // add pairs (then quads, etc.) of bits together to obtain
+ // sub-counts.
+ //
+ // A straightforward approach would look like:
+ //
+ // i = (i & 0x55555555) + ((i >> 1) & 0x55555555);
+ // i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
+ // i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F);
+ // i = (i & 0x00FF00FF) + ((i >> 8) & 0x00FF00FF);
+ // i = (i & 0x0000FFFF) + ((i >> 16) & 0x0000FFFF);
+ //
+ // The code below removes unnecessary &'s and uses a
+ // trick to remove one instruction in the first line.
+
+ i = _shru(i, 0) - (_shru(i, 1) & 0x55555555);
+ i = (i & 0x33333333) + (_shru(i, 2) & 0x33333333);
+ i = 0x0F0F0F0F & (i + _shru(i, 4));
+ i += _shru(i, 8);
+ i += _shru(i, 16);
+ return (i & 0x0000003F);
+ }
+
+ static int _shru(int value, int shift) => JS('int', '# >>> #', value, shift);
+ static int _shrs(int value, int shift) => JS('int', '# >> #', value, shift);
+ static int _ors(int a, int b) => JS('int', '# | #', a, b);
+
+ // Assumes i is <= 32-bit
+ static int _spread(int i) {
+ i = _ors(i, _shrs(i, 1));
+ i = _ors(i, _shrs(i, 2));
+ i = _ors(i, _shrs(i, 4));
+ i = _ors(i, _shrs(i, 8));
+ i = _shru(_ors(i, _shrs(i, 16)), 0);
+ return i;
+ }
+
+ Type get runtimeType => int;
+
+ int operator ~() => JS('JSUInt32', r'(~#) >>> 0', this);
+}
+
+class JSDouble extends JSNumber implements double {
+ const JSDouble();
+ Type get runtimeType => double;
+}
+
+class JSPositiveInt extends JSInt {}
+
+class JSUInt32 extends JSPositiveInt {}
+
+class JSUInt31 extends JSUInt32 {}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_primitives.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_primitives.dart
new file mode 100644
index 0000000..97577a0
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_primitives.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// dart2js "primitives", that is, features that cannot be implemented without
+/// access to JavaScript features.
+library dart2js._js_primitives;
+
+import 'dart:_foreign_helper' show JS;
+
+/// This is the low-level method that is used to implement [print]. It is
+/// possible to override this function from JavaScript by defining a function in
+/// JavaScript called "dartPrint".
+///
+/// Notice that it is also possible to intercept calls to [print] from within a
+/// Dart program using zones. This means that there is no guarantee that a call
+/// to print ends in this method.
+void printString(String string) {
+ if (JS('bool', r'typeof dartPrint == "function"')) {
+ // Support overriding print from JavaScript.
+ JS('void', r'dartPrint(#)', string);
+ return;
+ }
+
+ // Inside browser or nodejs.
+ if (JS('bool', r'typeof console == "object"') &&
+ JS('bool', r'typeof console.log != "undefined"')) {
+ JS('void', r'console.log(#)', string);
+ return;
+ }
+
+ // Don't throw inside IE, the console is only defined if dev tools is open.
+ if (JS('bool', r'typeof window == "object"')) {
+ return;
+ }
+
+ // Running in d8, the V8 developer shell, or in Firefox' js-shell.
+ if (JS('bool', r'typeof print == "function"')) {
+ JS('void', r'print(#)', string);
+ return;
+ }
+
+ // This is somewhat nasty, but we don't want to drag in a bunch of
+ // dependencies to handle a situation that cannot happen. So we
+ // avoid using Dart [:throw:] and Dart [toString].
+ JS('void', 'throw "Unable to print message: " + String(#)', string);
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_rti.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_rti.dart
new file mode 100644
index 0000000..fd82931
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_rti.dart
@@ -0,0 +1,1125 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This part contains helpers for supporting runtime type information.
+///
+/// The helper use a mixture of Dart and JavaScript objects. To indicate which
+/// is used where we adopt the scheme of using explicit type annotation for Dart
+/// objects and 'var' or omitted return type for JavaScript objects.
+///
+/// Since bool, int, and String values are represented by the same JavaScript
+/// primitives, type annotations are used for these types in all cases.
+///
+/// Several methods use a common JavaScript encoding of runtime type
+/// information. This encoding is referred to as the type representation which
+/// is one of these:
+/// 1) a JavaScript constructor for a class C: the represented type is the raw
+/// type C.
+/// 2) a JavaScript array: the first entry is of type 1 and contains the
+/// subtyping flags and the substitution of the type and the rest of the
+/// array are the type arguments.
+/// 3) `null`: the dynamic type.
+/// 4) a JavaScript object representing the function type. For instance, it has
+/// the form {ret: rti, args: [rti], opt: [rti], named: {name: rti}} for a
+/// function with a return type, regular, optional and named arguments.
+/// Generic function types have a 'bounds' property.
+///
+/// To check subtype relations between generic classes we use a JavaScript
+/// expression that describes the necessary substitution for type arguments.
+/// Such a substitution expression can be:
+/// 1) `null`, if no substituted check is necessary, because the
+/// type variables are the same or there are no type variables in the class
+/// that is checked for.
+/// 2) A list expression describing the type arguments to be used in the
+/// subtype check, if the type arguments to be used in the check do not
+/// depend on the type arguments of the object.
+/// 3) A function mapping the type variables of the object to be checked to a
+/// list expression. The function may also return null, which is equivalent
+/// to an array containing only null values.
+
+part of _js_helper;
+
+/// Called from generated code.
+Type createRuntimeType(rti) {
+ return new TypeImpl(rti);
+}
+
+class TypeImpl implements Type {
+ final dynamic _rti;
+ String __typeName;
+ String _unmangledName;
+ int _hashCode;
+
+ TypeImpl(this._rti);
+
+ String get _typeName => __typeName ??= runtimeTypeToString(_rti);
+
+ String toString() => _typeName;
+
+ // TODO(ahe): This is a poor hashCode as it collides with its name.
+ int get hashCode => _hashCode ??= _typeName.hashCode;
+
+ @pragma('dart2js:noInline')
+ bool operator ==(other) {
+ return (other is TypeImpl) && _typeName == other._typeName;
+ }
+}
+
+/// Represents a type variable.
+///
+/// This class holds the information needed when reflecting on generic classes
+/// and their members.
+class TypeVariable {
+ final Type owner;
+ final String name;
+ final int bound;
+
+ const TypeVariable(this.owner, this.name, this.bound);
+}
+
+getMangledTypeName(Type t) {
+ TypeImpl type = t;
+ return type._typeName;
+}
+
+/// Sets the runtime type information on [target]. [rti] is a type
+/// representation of type 4 or 5, that is, either a JavaScript array or `null`.
+///
+/// Called from generated code.
+///
+/// This is used only for marking JavaScript Arrays (JSArray) with the element
+/// type.
+// Don't inline. Let the JS engine inline this. The call expression is much
+// more compact that the inlined expansion.
+@pragma('dart2js:noInline')
+Object setRuntimeTypeInfo(Object target, var rti) {
+ assert(rti == null || isJsArray(rti));
+ String rtiName = JS_GET_NAME(JsGetName.RTI_NAME);
+ JS('var', r'#[#] = #', target, rtiName, rti);
+ return target;
+}
+
+/// Returns the runtime type information of [target]. The returned value is a
+/// list of type representations for the type arguments.
+///
+/// Called from generated code.
+getRuntimeTypeInfo(Object target) {
+ if (target == null) return null;
+ String rtiName = JS_GET_NAME(JsGetName.RTI_NAME);
+ return JS('var', r'#[#]', target, rtiName);
+}
+
+/// Returns the type arguments of [object] as an instance of [substitutionName].
+getRuntimeTypeArguments(interceptor, object, substitutionName) {
+ var substitution = getField(interceptor,
+ '${JS_GET_NAME(JsGetName.OPERATOR_AS_PREFIX)}$substitutionName');
+ return substitute(substitution, getRuntimeTypeInfo(object));
+}
+
+/// Returns the [index]th type argument of [target] as an instance of
+/// [substitutionName].
+///
+/// Called from generated code.
+@pragma('dart2js:noThrows')
+@pragma('dart2js:noSideEffects')
+@pragma('dart2js:noInline')
+getRuntimeTypeArgumentIntercepted(
+ interceptor, Object target, String substitutionName, int index) {
+ var arguments =
+ getRuntimeTypeArguments(interceptor, target, substitutionName);
+ return arguments == null ? null : getIndex(arguments, index);
+}
+
+/// Returns the [index]th type argument of [target] as an instance of
+/// [substitutionName].
+///
+/// Called from generated code.
+@pragma('dart2js:noThrows')
+@pragma('dart2js:noSideEffects')
+@pragma('dart2js:noInline')
+getRuntimeTypeArgument(Object target, String substitutionName, int index) {
+ var arguments = getRuntimeTypeArguments(target, target, substitutionName);
+ return arguments == null ? null : getIndex(arguments, index);
+}
+
+/// Returns the [index]th type argument of [target].
+///
+/// Called from generated code.
+@pragma('dart2js:noThrows')
+@pragma('dart2js:noSideEffects')
+@pragma('dart2js:noInline')
+getTypeArgumentByIndex(Object target, int index) {
+ var rti = getRuntimeTypeInfo(target);
+ return rti == null ? null : getIndex(rti, index);
+}
+
+/// Retrieves the class name from type information stored on the constructor
+/// of [object].
+String getClassName(var object) {
+ return rawRtiToJsConstructorName(getRawRuntimeType(getInterceptor(object)));
+}
+
+String _getRuntimeTypeAsString(var rti, List<String> genericContext) {
+ assert(isJsArray(rti));
+ String className = unminifyOrTag(rawRtiToJsConstructorName(getIndex(rti, 0)));
+ return '$className${_joinArguments(rti, 1, genericContext)}';
+}
+
+/// Returns a human-readable representation of the type representation [rti].
+///
+/// Called from generated code.
+@pragma('dart2js:noInline')
+String runtimeTypeToString(var rti) {
+ return _runtimeTypeToString(rti, null);
+}
+
+String _runtimeTypeToString(var rti, List<String> genericContext) {
+ if (isDartDynamicTypeRti(rti)) {
+ return 'dynamic';
+ }
+ if (isDartVoidTypeRti(rti)) {
+ return 'void';
+ }
+ if (isJsArray(rti)) {
+ // A list representing a type with arguments.
+ return _getRuntimeTypeAsString(rti, genericContext);
+ }
+ if (isJsFunction(rti)) {
+ // A reference to the constructor.
+ return unminifyOrTag(rawRtiToJsConstructorName(rti));
+ }
+ if (isDartJsInteropTypeArgumentRti(rti)) {
+ return 'dynamic';
+ }
+ if (isGenericFunctionTypeParameter(rti)) {
+ int index = rti;
+ if (genericContext == null || index < 0 || index >= genericContext.length) {
+ return 'unexpected-generic-index:${index}';
+ }
+ return '${genericContext[genericContext.length - index - 1]}';
+ }
+ if (isDartFunctionType(rti)) {
+ // TODO(sra): If there is a typedef tag, use the typedef name.
+ return _functionRtiToString(rti, genericContext);
+ }
+ if (isDartFutureOrType(rti)) {
+ var typeArgument = getFutureOrArgument(rti);
+ return 'FutureOr<${_runtimeTypeToString(typeArgument, genericContext)}>';
+ }
+ // We should not get here.
+ return 'unknown-reified-type';
+}
+
+// Returns a formatted String version of a function type.
+//
+// [genericContext] is list of the names of generic type parameters for generic
+// function types. The de Bruijn indexing scheme references the type variables
+// from the inner scope out. The parameters for each scope are pushed in
+// reverse, e.g. `<P,Q>(<R,S,T>(R))` creates the list `[Q,P,T,S,R]`. This
+// allows the de Bruijn index to simply index backwards from the end of
+// [genericContext], e.g. in the outer scope index `0` is P and `1` is Q, and in
+// the inner scope index `0` is R, `3` is P, and `4` is Q.
+//
+// [genericContext] is initially `null`.
+String _functionRtiToString(var rti, List<String> genericContext) {
+ String typeParameters = '';
+ int outerContextLength;
+
+ String boundsTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG);
+ if (hasField(rti, boundsTag)) {
+ List boundsRti = JS('JSFixedArray', '#[#]', rti, boundsTag);
+ if (genericContext == null) {
+ genericContext = <String>[];
+ } else {
+ outerContextLength = genericContext.length;
+ }
+ int offset = genericContext.length;
+ for (int i = boundsRti.length; i > 0; i--) {
+ genericContext.add('T${offset + i}');
+ }
+ // All variables are in scope in the bounds.
+ String typeSep = '';
+ typeParameters = '<';
+ for (int i = 0; i < boundsRti.length; i++) {
+ typeParameters += typeSep;
+ typeParameters += genericContext[genericContext.length - i - 1];
+ typeSep = ', ';
+ var boundRti = boundsRti[i];
+ if (isInterestingBound(boundRti)) {
+ typeParameters +=
+ ' extends ' + _runtimeTypeToString(boundRti, genericContext);
+ }
+ }
+ typeParameters += '>';
+ }
+
+ String returnTypeText;
+ String voidTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG);
+ if (JS('bool', '!!#[#]', rti, voidTag)) {
+ returnTypeText = 'void';
+ } else {
+ String returnTypeTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG);
+ var returnRti = JS('', '#[#]', rti, returnTypeTag);
+ returnTypeText = _runtimeTypeToString(returnRti, genericContext);
+ }
+
+ String argumentsText = '';
+ String sep = '';
+
+ String requiredParamsTag =
+ JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG);
+ if (hasField(rti, requiredParamsTag)) {
+ List arguments = JS('JSFixedArray', '#[#]', rti, requiredParamsTag);
+ for (var argument in arguments) {
+ argumentsText += sep;
+ argumentsText += _runtimeTypeToString(argument, genericContext);
+ sep = ', ';
+ }
+ }
+
+ String optionalParamsTag =
+ JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG);
+ bool hasOptionalArguments = JS('bool', '# in #', optionalParamsTag, rti);
+ if (hasOptionalArguments) {
+ List optionalArguments = JS('JSFixedArray', '#[#]', rti, optionalParamsTag);
+ argumentsText += '$sep[';
+ sep = '';
+ for (var argument in optionalArguments) {
+ argumentsText += sep;
+ argumentsText += _runtimeTypeToString(argument, genericContext);
+ sep = ', ';
+ }
+ argumentsText += ']';
+ }
+
+ String namedParamsTag =
+ JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG);
+ bool hasNamedArguments = JS('bool', '# in #', namedParamsTag, rti);
+ if (hasNamedArguments) {
+ var namedArguments = JS('', '#[#]', rti, namedParamsTag);
+ argumentsText += '$sep{';
+ sep = '';
+ for (String name in extractKeys(namedArguments)) {
+ argumentsText += sep;
+ argumentsText += _runtimeTypeToString(
+ JS('', '#[#]', namedArguments, name), genericContext);
+ argumentsText += ' $name';
+ sep = ', ';
+ }
+ argumentsText += '}';
+ }
+
+ if (outerContextLength != null) {
+ // Pop all of the generic type parameters.
+ JS('', '#.length = #', genericContext, outerContextLength);
+ }
+
+ // TODO(sra): Below is the same format as the VM. Change to:
+ //
+ // return '${returnTypeText} Function${typeParameters}(${argumentsText})';
+ //
+ return '${typeParameters}(${argumentsText}) => ${returnTypeText}';
+}
+
+/// Creates a comma-separated string of human-readable representations of the
+/// type representations in the JavaScript array [types] starting at index
+/// [startIndex].
+String joinArguments(var types, int startIndex) {
+ return _joinArguments(types, startIndex, null);
+}
+
+String _joinArguments(var types, int startIndex, List<String> genericContext) {
+ if (types == null) return '';
+ assert(isJsArray(types));
+ var separator = '';
+ bool allDynamic = true;
+ StringBuffer buffer = new StringBuffer('');
+ for (int index = startIndex; index < getLength(types); index++) {
+ buffer.write(separator);
+ separator = ', ';
+ var argument = getIndex(types, index);
+ if (argument != null) {
+ allDynamic = false;
+ }
+ buffer.write(_runtimeTypeToString(argument, genericContext));
+ }
+ return '<$buffer>';
+}
+
+/// Returns a human-readable representation of the type of [object].
+///
+/// In minified mode does *not* use unminified identifiers (even when present).
+String getRuntimeTypeString(var object) {
+ if (object is Closure) {
+ // This excludes classes that implement Function via a `call` method, but
+ // includes classes generated to represent closures in closure conversion.
+ var functionRti = extractFunctionTypeObjectFrom(object);
+ if (functionRti != null) {
+ return runtimeTypeToString(functionRti);
+ }
+ }
+ String className = getClassName(object);
+ if (object == null) return className;
+ String rtiName = JS_GET_NAME(JsGetName.RTI_NAME);
+ var rti = JS('var', r'#[#]', object, rtiName);
+ return "$className${joinArguments(rti, 0)}";
+}
+
+/// Returns the full type of [o] in the runtime type representation.
+getRti(o) {
+ if (o is Closure) {
+ // This excludes classes that implement Function via a `call` method, but
+ // includes classes generated to represent closures in closure conversion.
+ var functionRti = extractFunctionTypeObjectFrom(o);
+ if (functionRti != null) return functionRti;
+ }
+ var interceptor = getInterceptor(o);
+ var type = getRawRuntimeType(interceptor);
+ if (o == null) return type;
+ if (JS('bool', 'typeof # != "object"', o)) return type;
+ var rti = getRuntimeTypeInfo(o);
+ if (rti != null) {
+ // If the type has type variables (that is, `rti != null`), make a copy of
+ // the type arguments and insert [o] in the first position to create a
+ // compound type representation.
+ rti = JS('JSExtendableArray', '#.slice()', rti); // Make a copy.
+ JS('', '#.splice(0, 0, #)', rti, type); // Insert type at position 0.
+ type = rti;
+ }
+ return type;
+}
+
+Type getRuntimeType(var object) {
+ if (JS_GET_FLAG('USE_NEW_RTI')) return newRti.getRuntimeType(object);
+ return new TypeImpl(getRti(object));
+}
+
+/// Applies the [substitution] on the [arguments].
+///
+/// See the comment in the beginning of this file for a description of the
+/// possible values for [substitution].
+substitute(var substitution, var arguments) {
+ if (substitution == null) return arguments;
+ assert(isJsFunction(substitution));
+ assert(arguments == null || isJsArray(arguments));
+ substitution = invoke(substitution, arguments);
+ if (substitution == null) return null;
+ if (isJsArray(substitution)) {
+ // Substitutions are generated too late to mark Array as used, so use a
+ // tautological JS 'cast' to mark Array as used. This is needed only in
+ // some tiny tests where the substition is the only thing that creates an
+ // Array.
+ return JS('JSArray', '#', substitution);
+ }
+ if (isJsFunction(substitution)) {
+ // TODO(johnniwinther): Check if this is still needed.
+ return invoke(substitution, arguments);
+ }
+ return arguments;
+}
+
+/// Perform a type check with arguments on the Dart object [object].
+///
+/// Parameters:
+/// - [isField]: the name of the flag/function to check if the object
+/// is of the correct class.
+/// - [checks]: the (JavaScript) list of type representations for the
+/// arguments to check against.
+/// - [asField]: the name of the function that transforms the type
+/// arguments of [objects] to an instance of the class that we check
+/// against.
+bool checkSubtype(Object object, String isField, List checks, String asField) {
+ if (object == null) return false;
+ var arguments = getRuntimeTypeInfo(object);
+ // Interceptor is needed for JSArray and native classes.
+ // TODO(sra): It could be a more specialized interceptor since [object] is not
+ // `null` or a primitive.
+ var interceptor = getInterceptor(object);
+ var isSubclass = getField(interceptor, isField);
+ // When we read the field and it is not there, [isSubclass] will be `null`.
+ if (isSubclass == null) return false;
+ // Should the asField function be passed the receiver?
+ var substitution = getField(interceptor, asField);
+ return checkArguments(substitution, arguments, null, checks, null);
+}
+
+/// Returns the field's type name.
+///
+/// In minified mode, uses the unminified names if available.
+String computeTypeName(String isField, List arguments) {
+ // Extract the class name from the is field and append the textual
+ // representation of the type arguments.
+ return Primitives.formatType(
+ unminifyOrTag(isCheckPropertyToJsConstructorName(isField)), arguments);
+}
+
+/// Called from generated code.
+Object subtypeCast(Object object, String isField, List checks, String asField) {
+ if (object == null) return object;
+ if (checkSubtype(object, isField, checks, asField)) return object;
+ String typeName = computeTypeName(isField, checks);
+ throw new CastErrorImplementation(object, typeName);
+}
+
+/// Called from generated code.
+Object assertSubtype(
+ Object object, String isField, List checks, String asField) {
+ if (object == null) return object;
+ if (checkSubtype(object, isField, checks, asField)) return object;
+ String typeName = computeTypeName(isField, checks);
+ throw new TypeErrorImplementation(object, typeName);
+}
+
+/// Checks that the type represented by [subtype] is a subtype of [supertype].
+/// If not a type error is thrown using [prefix], [infix], [suffix] and the
+/// runtime types [subtype] and [supertype] to generate the error message.
+///
+/// Called from generated code.
+assertIsSubtype(
+ var subtype, var supertype, String prefix, String infix, String suffix) {
+ if (!isSubtype(subtype, supertype)) {
+ String message = "TypeError: "
+ "$prefix${runtimeTypeToString(subtype)}$infix"
+ "${runtimeTypeToString(supertype)}$suffix";
+ throwTypeError(message);
+ }
+}
+
+throwTypeError(message) {
+ throw new TypeErrorImplementation.fromMessage(message);
+}
+
+bool checkArguments(
+ var substitution, var arguments, var sEnv, var checks, var tEnv) {
+ return areSubtypes(substitute(substitution, arguments), sEnv, checks, tEnv);
+}
+
+/// Checks whether the types of [s] are all subtypes of the types of [t].
+///
+/// [s] and [t] are either `null` or JavaScript arrays of type representations,
+/// A `null` argument is interpreted as the arguments of a raw type, that is a
+/// list of `dynamic`. If [s] and [t] are JavaScript arrays they must be of the
+/// same length.
+///
+/// See the comment in the beginning of this file for a description of type
+/// representations.
+
+bool areSubtypes(var s, var sEnv, var t, var tEnv) {
+ // `null` means a raw type.
+ if (t == null) return true;
+ if (s == null) {
+ int len = getLength(t);
+ for (int i = 0; i < len; i++) {
+ if (!_isSubtype(null, null, getIndex(t, i), tEnv)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ assert(isJsArray(s));
+ assert(isJsArray(t));
+ assert(getLength(s) == getLength(t));
+
+ int len = getLength(s);
+ for (int i = 0; i < len; i++) {
+ if (!_isSubtype(getIndex(s, i), sEnv, getIndex(t, i), tEnv)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/// Computes the signature by applying the type arguments of [context] as an
+/// instance of [contextName] to the signature function [signature].
+computeSignature(var signature, var context, var contextName) {
+ var interceptor = getInterceptor(context);
+ var typeArguments =
+ getRuntimeTypeArguments(interceptor, context, contextName);
+ return invokeOn(signature, context, typeArguments);
+}
+
+/// Returns `true` if the runtime type representation [type] is a top type.
+/// That is, either `dynamic`, `void` or `Object`.
+@pragma('dart2js:tryInline')
+bool isTopType(var type) {
+ return isDartDynamicTypeRti(type) ||
+ isDartVoidTypeRti(type) ||
+ isDartObjectTypeRti(type) ||
+ isDartJsInteropTypeArgumentRti(type);
+}
+
+/// Returns `true` if the runtime type representation [type] is a supertype of
+/// [Null].
+@pragma('dart2js:tryInline')
+bool isSupertypeOfNull(var type) {
+ return isSupertypeOfNullBase(type) || isSupertypeOfNullRecursive(type);
+}
+
+/// Returns `true` if the runtime type representation [type] is a simple
+/// supertype of [Null].
+///
+/// This method doesn't handle `FutureOr<Null>`. This is handle by
+/// [isSupertypeOfNullRecursive] because it requires a recursive check.
+@pragma('dart2js:tryInline')
+bool isSupertypeOfNullBase(var type) {
+ return isDartDynamicTypeRti(type) ||
+ isDartObjectTypeRti(type) ||
+ isNullTypeRti(type) ||
+ isDartVoidTypeRti(type) ||
+ isDartJsInteropTypeArgumentRti(type);
+}
+
+/// Returns `true` if the runtime type representation [type] is a `FutureOr`
+/// type that is a supertype of [Null].
+///
+/// This method is recursive to be able to handle both `FutureOr<Null>` and
+/// `FutureOr<FutureOr<Null>>` etc.
+bool isSupertypeOfNullRecursive(var type) {
+ if (isGenericFunctionTypeParameter(type)) {
+ // We need to check for function type variables because `isDartFutureOrType`
+ // doesn't work on numbers.
+ return false;
+ }
+ if (isDartFutureOrType(type)) {
+ var typeArgument = getFutureOrArgument(type);
+ return isSupertypeOfNullBase(type) ||
+ isSupertypeOfNullRecursive(typeArgument);
+ }
+ return false;
+}
+
+/// Returns the type argument of the `FutureOr` runtime type representation
+/// [type].
+///
+/// For instance `num` of `FutureOr<num>`.
+@pragma('dart2js:tryInline')
+Object getFutureOrArgument(var type) {
+ assert(isDartFutureOrType(type));
+ var typeArgumentTag = JS_GET_NAME(JsGetName.FUTURE_OR_TYPE_ARGUMENT_TAG);
+ return hasField(type, typeArgumentTag)
+ ? getField(type, typeArgumentTag)
+ : null;
+}
+
+/// Tests whether the Dart object [o] is a subtype of the runtime type
+/// representation [t].
+///
+/// See the comment in the beginning of this file for a description of type
+/// representations.
+bool checkSubtypeOfRuntimeType(o, t) {
+ if (o == null) return isSupertypeOfNull(t);
+ if (isTopType(t)) return true;
+ if (JS('bool', 'typeof # == "object"', t)) {
+ if (isDartFutureOrType(t)) {
+ // `o is FutureOr<T>` is equivalent to
+ //
+ // o is T || o is Future<T>
+ //
+ // T might be a function type, requiring extracting the closure's
+ // signature, so do the `o is T` check here and let the `Future` interface
+ // type test fall through to the `isSubtype` check at the end of this
+ // function.
+ var tTypeArgument = getFutureOrArgument(t);
+ if (checkSubtypeOfRuntimeType(o, tTypeArgument)) return true;
+ }
+
+ if (isDartFunctionType(t)) {
+ return functionTypeTest(o, t);
+ }
+ }
+
+ var interceptor = getInterceptor(o);
+ var type = getRawRuntimeType(interceptor);
+ var rti = getRuntimeTypeInfo(o);
+ if (rti != null) {
+ // If the type has type variables (that is, `rti != null`), make a copy of
+ // the type arguments and insert [o] in the first position to create a
+ // compound type representation.
+ rti = JS('JSExtendableArray', '#.slice()', rti); // Make a copy.
+ JS('', '#.splice(0, 0, #)', rti, type); // Insert type at position 0.
+ type = rti;
+ }
+ return isSubtype(type, t);
+}
+
+/// Called from generated code.
+Object subtypeOfRuntimeTypeCast(Object object, var type) {
+ if (object != null && !checkSubtypeOfRuntimeType(object, type)) {
+ throw new CastErrorImplementation(object, runtimeTypeToString(type));
+ }
+ return object;
+}
+
+/// Called from generated code.
+Object assertSubtypeOfRuntimeType(Object object, var type) {
+ if (object != null && !checkSubtypeOfRuntimeType(object, type)) {
+ throw new TypeErrorImplementation(object, runtimeTypeToString(type));
+ }
+ return object;
+}
+
+/// Extracts the type arguments from a type representation. The result is a
+/// JavaScript array or `null`.
+getArguments(var type) {
+ return isJsArray(type) ? JS('var', r'#.slice(1)', type) : null;
+}
+
+/// Checks whether the type represented by the type representation [s] is a
+/// subtype of the type represented by the type representation [t].
+///
+/// See the comment in the beginning of this file for a description of type
+/// representations.
+///
+/// The arguments [s] and [t] must be types, usually represented by the
+/// constructor of the class, or an array (for generic class types).
+bool isSubtype(var s, var t) {
+ return _isSubtype(s, null, t, null);
+}
+
+bool _isSubtype(var s, var sEnv, var t, var tEnv) {
+ // Subtyping is reflexive.
+ if (isIdentical(s, t)) return true;
+
+ // [t] is a top type?
+ if (isTopType(t)) return true;
+
+ if (isDartJsInteropTypeArgumentRti(s)) return true;
+
+ // [s] is a top type?
+ if (isTopType(s)) {
+ if (isGenericFunctionTypeParameter(t)) {
+ // We need to check for function type variables because
+ // `isDartFutureOrType` doesn't work on numbers.
+ return false;
+ }
+ if (isDartFutureOrType(t)) {
+ // [t] is FutureOr<T>. Check [s] <: T.
+ var tTypeArgument = getFutureOrArgument(t);
+ return _isSubtype(s, sEnv, tTypeArgument, tEnv);
+ }
+ return false;
+ }
+
+ // Generic function type parameters must match exactly, which would have
+ // exited earlier. The de Bruijn indexing ensures the representation as a
+ // small number can be used for type comparison.
+ if (isGenericFunctionTypeParameter(s)) {
+ // TODO(sra): Use the bound of the type variable.
+ return false;
+ }
+ if (isGenericFunctionTypeParameter(t)) return false;
+
+ if (isNullType(s)) return true;
+
+ // Get the object describing the class and check for the subtyping flag
+ // constructed from the type of [s].
+ var typeOfS = isJsArray(s) ? getIndex(s, 0) : s;
+
+ if (isDartFutureOrType(t)) {
+ // [t] is FutureOr<T>
+ var tTypeArgument = getFutureOrArgument(t);
+ if (isDartFutureOrType(s)) {
+ // [S] is FutureOr<S>. Check S <: T
+ var sTypeArgument = getFutureOrArgument(s);
+ return _isSubtype(sTypeArgument, sEnv, tTypeArgument, tEnv);
+ } else if (_isSubtype(s, sEnv, tTypeArgument, tEnv)) {
+ // `true` because [s] <: T.
+ return true;
+ } else {
+ // Check [s] <: Future<T>.
+ String futureClass = JS_GET_NAME(JsGetName.FUTURE_CLASS_TYPE_NAME);
+ if (!builtinIsSubtype(typeOfS, futureClass)) {
+ // [s] doesn't implement Future.
+ return false;
+ }
+ var typeOfSPrototype = JS('', '#.prototype', typeOfS);
+ var field = '${JS_GET_NAME(JsGetName.OPERATOR_AS_PREFIX)}${futureClass}';
+ var futureSubstitution = getField(typeOfSPrototype, field);
+ var futureArguments = substitute(futureSubstitution, getArguments(s));
+ var futureArgument =
+ isJsArray(futureArguments) ? getIndex(futureArguments, 0) : null;
+ // [s] implements Future<S>. Check S <: T.
+ return _isSubtype(futureArgument, sEnv, tTypeArgument, tEnv);
+ }
+ }
+
+ if (isDartFunctionType(t)) {
+ return _isFunctionSubtype(s, sEnv, t, tEnv);
+ }
+
+ if (isDartFunctionType(s)) {
+ // Check function types against the `Function` class (`Object` is also a
+ // supertype, but is tested above with other 'top' types.).
+ return isDartFunctionTypeRti(t);
+ }
+
+ // Get the object describing the class and check for the subtyping flag
+ // constructed from the type of [t].
+ var typeOfT = isJsArray(t) ? getIndex(t, 0) : t;
+
+ // Check for a subtyping flag.
+ // Get the necessary substitution of the type arguments, if there is one.
+ var substitution;
+ if (isNotIdentical(typeOfT, typeOfS)) {
+ String typeOfTString = rawRtiToJsConstructorName(typeOfT);
+ if (!builtinIsSubtype(typeOfS, typeOfTString)) {
+ return false;
+ }
+ var typeOfSPrototype = JS('', '#.prototype', typeOfS);
+ var field = '${JS_GET_NAME(JsGetName.OPERATOR_AS_PREFIX)}${typeOfTString}';
+ substitution = getField(typeOfSPrototype, field);
+ }
+ // The class of [s] is a subclass of the class of [t]. If [t] has no
+ // type arguments, it used as a raw type and [s] is a subtype of [t].
+ if (!isJsArray(t)) {
+ return true;
+ }
+ // Recursively check the type arguments.
+ return checkArguments(
+ substitution, getArguments(s), sEnv, getArguments(t), tEnv);
+}
+
+/// Top-level function subtype check when [t] is known to be a function type
+/// rti.
+bool isFunctionSubtype(var s, var t) {
+ return _isFunctionSubtype(s, null, t, null);
+}
+
+bool _isFunctionSubtype(var s, var sEnv, var t, var tEnv) {
+ assert(isDartFunctionType(t));
+ if (!isDartFunctionType(s)) return false;
+ var genericBoundsTag =
+ JS_GET_NAME(JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG);
+ var voidReturnTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG);
+ var returnTypeTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG);
+
+ // Generic function types must agree on number of type parameters and bounds.
+ if (hasField(s, genericBoundsTag)) {
+ if (hasNoField(t, genericBoundsTag)) return false;
+ var sBounds = getField(s, genericBoundsTag);
+ var tBounds = getField(t, genericBoundsTag);
+ int sGenericParameters = getLength(sBounds);
+ int tGenericParameters = getLength(tBounds);
+ if (sGenericParameters != tGenericParameters) return false;
+ // TODO(sra): Compare bounds, which should be 'equal' trees due to the de
+ // Bruijn numbering of type parameters.
+ // TODO(sra): Extend [sEnv] and [tEnv] with bindings for the [s] and [t]
+ // type parameters to enable checking the bound against non-type-parameter
+ // terms.
+ } else if (hasField(t, genericBoundsTag)) {
+ return false;
+ }
+
+ var sReturnType = getField(s, returnTypeTag);
+ var tReturnType = getField(t, returnTypeTag);
+ if (!_isSubtype(sReturnType, sEnv, tReturnType, tEnv)) return false;
+
+ var requiredParametersTag =
+ JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG);
+ var sParameterTypes = getField(s, requiredParametersTag);
+ var tParameterTypes = getField(t, requiredParametersTag);
+
+ var optionalParametersTag =
+ JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG);
+ var sOptionalParameterTypes = getField(s, optionalParametersTag);
+ var tOptionalParameterTypes = getField(t, optionalParametersTag);
+
+ int sParametersLen = sParameterTypes != null ? getLength(sParameterTypes) : 0;
+ int tParametersLen = tParameterTypes != null ? getLength(tParameterTypes) : 0;
+
+ int sOptionalParametersLen =
+ sOptionalParameterTypes != null ? getLength(sOptionalParameterTypes) : 0;
+ int tOptionalParametersLen =
+ tOptionalParameterTypes != null ? getLength(tOptionalParameterTypes) : 0;
+
+ if (sParametersLen > tParametersLen) {
+ // Too many required parameters in [s].
+ return false;
+ }
+ if (sParametersLen + sOptionalParametersLen <
+ tParametersLen + tOptionalParametersLen) {
+ // Too few required and optional parameters in [s].
+ return false;
+ }
+
+ int pos = 0;
+ // Check all required parameters of [s].
+ for (; pos < sParametersLen; pos++) {
+ if (!_isSubtype(getIndex(tParameterTypes, pos), tEnv,
+ getIndex(sParameterTypes, pos), sEnv)) {
+ return false;
+ }
+ }
+ int sPos = 0;
+ int tPos = pos;
+ // Check the remaining parameters of [t] with the first optional parameters
+ // of [s].
+ for (; tPos < tParametersLen; sPos++, tPos++) {
+ if (!_isSubtype(getIndex(tParameterTypes, tPos), tEnv,
+ getIndex(sOptionalParameterTypes, sPos), sEnv)) {
+ return false;
+ }
+ }
+ tPos = 0;
+ // Check the optional parameters of [t] with the remaining optional
+ // parameters of [s]:
+ for (; tPos < tOptionalParametersLen; sPos++, tPos++) {
+ if (!_isSubtype(getIndex(tOptionalParameterTypes, tPos), tEnv,
+ getIndex(sOptionalParameterTypes, sPos), sEnv)) {
+ return false;
+ }
+ }
+
+ var namedParametersTag =
+ JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG);
+ var sNamedParameters = getField(s, namedParametersTag);
+ var tNamedParameters = getField(t, namedParametersTag);
+ if (tNamedParameters == null) return true;
+ if (sNamedParameters == null) return false;
+ return namedParametersSubtypeCheck(
+ sNamedParameters, sEnv, tNamedParameters, tEnv);
+}
+
+bool namedParametersSubtypeCheck(var s, var sEnv, var t, var tEnv) {
+ assert(isJsObject(s));
+ assert(isJsObject(t));
+
+ // Each named parameter in [t] must exist in [s] and be a subtype of the type
+ // in [s].
+ List names = JS('JSFixedArray', 'Object.getOwnPropertyNames(#)', t);
+ for (int i = 0; i < names.length; i++) {
+ var name = names[i];
+ if (JS('bool', '!Object.hasOwnProperty.call(#, #)', s, name)) {
+ return false;
+ }
+ var tType = JS('', '#[#]', t, name);
+ var sType = JS('', '#[#]', s, name);
+ if (!_isSubtype(tType, tEnv, sType, sEnv)) return false;
+ }
+ return true;
+}
+
+/// Returns whether [type] is the representation of a generic function type
+/// parameter. Generic function type parameters are represented de Bruijn
+/// indexes.
+///
+/// This test is only valid if [type] is known _not_ to be the void rti, whose
+/// runtime representation is -1.
+bool isGenericFunctionTypeParameter(var type) {
+ assert(!isDartVoidTypeRti(type));
+ return type is num; // Actually int, but 'is num' is faster.
+}
+
+/// Returns [genericFunctionRti] with type parameters bound to [parameters].
+///
+/// [genericFunctionRti] must be an rti representation with a number of generic
+/// type parameters matching the number of types in [parameters].
+///
+/// Called from generated code.
+@pragma('dart2js:noInline')
+instantiatedGenericFunctionType(genericFunctionRti, parameters) {
+ if (genericFunctionRti == null) return null;
+
+ assert(isDartFunctionType(genericFunctionRti));
+
+ var genericBoundsTag =
+ JS_GET_NAME(JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG);
+
+ assert(hasField(genericFunctionRti, genericBoundsTag));
+ var bounds = getField(genericFunctionRti, genericBoundsTag);
+
+ // Generic function types must agree on number of type parameters and bounds.
+ int boundLength = getLength(bounds);
+ int parametersLength = getLength(parameters);
+ assert(boundLength == parametersLength);
+
+ var result = JS('', '{#:1}', JS_GET_NAME(JsGetName.FUNCTION_TYPE_TAG));
+ return finishBindInstantiatedFunctionType(
+ genericFunctionRti, result, parameters, 0);
+}
+
+bindInstantiatedFunctionType(rti, parameters, int depth) {
+ var result = JS('', '{#:1}', JS_GET_NAME(JsGetName.FUNCTION_TYPE_TAG));
+
+ var genericBoundsTag =
+ JS_GET_NAME(JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG);
+ if (hasField(rti, genericBoundsTag)) {
+ var bounds = getField(rti, genericBoundsTag);
+ depth += getLength(bounds);
+ setField(result, genericBoundsTag,
+ bindInstantiatedTypes(bounds, parameters, depth));
+ }
+
+ return finishBindInstantiatedFunctionType(rti, result, parameters, depth);
+}
+
+/// Common code for function types that copies all non-bounds parts of the
+/// function [rti] into [result].
+finishBindInstantiatedFunctionType(rti, result, parameters, int depth) {
+ var voidReturnTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG);
+ var returnTypeTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG);
+
+ if (hasField(rti, voidReturnTag)) {
+ setField(result, voidReturnTag, getField(rti, voidReturnTag));
+ } else if (hasField(rti, returnTypeTag)) {
+ setField(result, returnTypeTag,
+ bindInstantiatedType(getField(rti, returnTypeTag), parameters, depth));
+ }
+
+ var requiredParametersTag =
+ JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG);
+ if (hasField(rti, requiredParametersTag)) {
+ setField(
+ result,
+ requiredParametersTag,
+ bindInstantiatedTypes(
+ getField(rti, requiredParametersTag), parameters, depth));
+ }
+
+ String optionalParametersTag =
+ JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG);
+ if (hasField(rti, optionalParametersTag)) {
+ setField(
+ result,
+ optionalParametersTag,
+ bindInstantiatedTypes(
+ getField(rti, optionalParametersTag), parameters, depth));
+ }
+
+ String namedParametersTag =
+ JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG);
+ if (hasField(rti, namedParametersTag)) {
+ var namedParameters = getField(rti, namedParametersTag);
+ var boundNamed = JS('', '{}');
+ var names = JS('JSFixedArray', 'Object.keys(#)', namedParameters);
+ for (var name in names) {
+ setField(
+ boundNamed,
+ name,
+ bindInstantiatedType(
+ getField(namedParameters, name), parameters, depth));
+ }
+ setField(result, namedParametersTag, boundNamed);
+ }
+
+ return result;
+}
+
+/// Copies [rti], substituting generic type parameters from [parameters].
+///
+/// Generic type parameters are de Bruijn indexes counting up through the
+/// generic function type parameters scopes to index into [parameters].
+///
+/// [depth] is the number of subsequent generic function parameters that are in
+/// scope. This is subtracted off the de Bruijn index for the type parameter to
+/// arrive at an potential index into [parameters].
+bindInstantiatedType(rti, parameters, int depth) {
+ if (isDartDynamicTypeRti(rti)) return rti; // dynamic.
+ if (isDartVoidTypeRti(rti)) return rti; // void.
+ // Functions are constructors denoting the class of the constructor.
+ if (isJsFunction(rti)) return rti;
+
+ // de Bruijn type indexes.
+ if (isGenericFunctionTypeParameter(rti)) {
+ if (rti < depth) return rti;
+ return JS('', '#[#]', parameters, rti - depth);
+ }
+ // Other things encoded as numbers.
+ if (rti is num) return rti;
+
+ if (isJsArray(rti)) {
+ // An array is a parameterized class type, e.g. the list of three
+ // constructor functions [Map, String, int] represents `Map<String, int>`.
+ // Since the 'head' of the term and the arguments are encoded in the same
+ // scheme, it is sufficient to walk all the types.
+ return bindInstantiatedTypes(rti, parameters, depth);
+ }
+ if (isDartFunctionType(rti)) {
+ return bindInstantiatedFunctionType(rti, parameters, depth);
+ }
+
+ // Can't include the bad [rti] since it is not a Dart value.
+ throw new ArgumentError('Unknown RTI format in bindInstantiatedType.');
+}
+
+/// Returns a copy of array [rti] with each type bound.
+bindInstantiatedTypes(rti, parameters, int depth) {
+ List array = JS('JSFixedArray', '#.slice()', rti);
+ for (int i = 0; i < array.length; i++) {
+ array[i] = bindInstantiatedType(array[i], parameters, depth);
+ }
+ return array;
+}
+
+/// Calls the JavaScript [function] with the [arguments] with the global scope
+/// as the `this` context.
+invoke(var function, var arguments) => invokeOn(function, null, arguments);
+
+/// Calls the JavaScript [function] with the [arguments] with [receiver] as the
+/// `this` context.
+Object invokeOn(function, receiver, arguments) {
+ assert(isJsFunction(function));
+ assert(arguments == null || isJsArray(arguments));
+ return JS('var', r'#.apply(#, #)', function, receiver, arguments);
+}
+
+/// Calls the property [name] on the JavaScript [object].
+call(var object, String name) => JS('var', r'#[#]()', object, name);
+
+/// Returns the property [name] of the JavaScript object [object].
+getField(var object, String name) => JS('var', r'#[#]', object, name);
+
+/// Returns the property [index] of the JavaScript array [array].
+getIndex(var array, int index) {
+ assert(isJsArray(array));
+ return JS('var', r'#[#]', array, index);
+}
+
+setField(var object, String name, var value) {
+ JS('', '#[#] = #', object, name, value);
+}
+
+setIndex(var array, int index, var value) {
+ JS('', '#[#] = #', array, index, value);
+}
+
+/// Returns the length of the JavaScript array [array].
+int getLength(var array) {
+ assert(isJsArray(array));
+ return JS('int', r'#.length', array);
+}
+
+/// Returns whether [value] is a JavaScript array.
+bool isJsArray(var value) {
+ return value is JSArray;
+}
+
+hasField(var object, var name) => JS('bool', r'# in #', name, object);
+
+hasNoField(var object, var name) => !hasField(object, name);
+
+/// Returns `true` if [o] is a JavaScript function.
+bool isJsFunction(var o) => JS('bool', r'typeof # == "function"', o);
+
+/// Returns `true` if [o] is a JavaScript object.
+bool isJsObject(var o) => JS('bool', r"typeof # == 'object'", o);
+
+/// Returns `true` if the JavaScript values [s] and [t] are identical. We use
+/// this helper instead of [identical] because `identical` needs to merge
+/// `null` and `undefined` (which we can avoid).
+bool isIdentical(var s, var t) => JS('bool', '# === #', s, t);
+
+/// Returns `true` if the JavaScript values [s] and [t] are not identical. We
+/// use this helper instead of [identical] because `identical` needs to merge
+/// `null` and `undefined` (which we can avoid).
+bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t);
+
+/// 'Top' bounds are uninteresting: null/undefined and Object.
+bool isInterestingBound(rti) =>
+ rti != null &&
+ isNotIdentical(
+ rti,
+ JS_BUILTIN(
+ 'depends:none;effects:none;', JsBuiltin.dartObjectConstructor));
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_string.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_string.dart
new file mode 100644
index 0000000..39370d7
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_string.dart
@@ -0,0 +1,470 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _interceptors;
+
+/// The interceptor class for [String]. The compiler recognizes this
+/// class as an interceptor, and changes references to [:this:] to
+/// actually use the receiver of the method, which is generated as an extra
+/// argument added to each member.
+class JSString extends Interceptor implements String, JSIndexable {
+ const JSString();
+
+ @pragma('dart2js:noInline')
+ int codeUnitAt(int index) {
+ if (index is! int) throw diagnoseIndexError(this, index);
+ if (index < 0) throw diagnoseIndexError(this, index);
+ return _codeUnitAt(index);
+ }
+
+ int _codeUnitAt(int index) {
+ if (index >= length) throw diagnoseIndexError(this, index);
+ return JS('JSUInt31', r'#.charCodeAt(#)', this, index);
+ }
+
+ Iterable<Match> allMatches(String string, [int start = 0]) {
+ checkString(string);
+ checkInt(start);
+ if (0 > start || start > string.length) {
+ throw new RangeError.range(start, 0, string.length);
+ }
+ return allMatchesInStringUnchecked(this, string, start);
+ }
+
+ Match matchAsPrefix(String string, [int start = 0]) {
+ if (start < 0 || start > string.length) {
+ throw new RangeError.range(start, 0, string.length);
+ }
+ if (start + this.length > string.length) return null;
+ // TODO(lrn): See if this can be optimized.
+ for (int i = 0; i < this.length; i++) {
+ if (string.codeUnitAt(start + i) != this.codeUnitAt(i)) {
+ return null;
+ }
+ }
+ return new StringMatch(start, string, this);
+ }
+
+ String operator +(String other) {
+ if (other is! String) throw new ArgumentError.value(other);
+ return JS('String', r'# + #', this, other);
+ }
+
+ bool endsWith(String other) {
+ checkString(other);
+ int otherLength = other.length;
+ if (otherLength > length) return false;
+ return other == substring(length - otherLength);
+ }
+
+ String replaceAll(Pattern from, String to) {
+ return stringReplaceAllUnchecked(this, from, checkString(to));
+ }
+
+ String replaceAllMapped(Pattern from, String convert(Match match)) {
+ return this.splitMapJoin(from, onMatch: convert);
+ }
+
+ String splitMapJoin(Pattern from,
+ {String onMatch(Match match), String onNonMatch(String nonMatch)}) {
+ return stringReplaceAllFuncUnchecked(this, from, onMatch, onNonMatch);
+ }
+
+ String replaceFirst(Pattern from, String to, [int startIndex = 0]) {
+ checkString(to);
+ checkInt(startIndex);
+ RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex");
+ return stringReplaceFirstUnchecked(this, from, to, startIndex);
+ }
+
+ String replaceFirstMapped(Pattern from, String replace(Match match),
+ [int startIndex = 0]) {
+ checkNull(replace);
+ checkInt(startIndex);
+ RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex");
+ return stringReplaceFirstMappedUnchecked(this, from, replace, startIndex);
+ }
+
+ List<String> split(Pattern pattern) {
+ checkNull(pattern);
+ if (pattern is String) {
+ return stringSplitUnchecked(this, pattern);
+ } else if (pattern is JSSyntaxRegExp && regExpCaptureCount(pattern) == 0) {
+ var re = regExpGetNative(pattern);
+ return stringSplitUnchecked(this, re);
+ } else {
+ return _defaultSplit(pattern);
+ }
+ }
+
+ String replaceRange(int start, int end, String replacement) {
+ checkString(replacement);
+ checkInt(start);
+ end = RangeError.checkValidRange(start, end, this.length);
+ checkInt(end);
+ return stringReplaceRangeUnchecked(this, start, end, replacement);
+ }
+
+ List<String> _defaultSplit(Pattern pattern) {
+ List<String> result = <String>[];
+ // End of most recent match. That is, start of next part to add to result.
+ int start = 0;
+ // Length of most recent match.
+ // Set >0, so no match on the empty string causes the result to be [""].
+ int length = 1;
+ for (var match in pattern.allMatches(this)) {
+ int matchStart = match.start;
+ int matchEnd = match.end;
+ length = matchEnd - matchStart;
+ if (length == 0 && start == matchStart) {
+ // An empty match right after another match is ignored.
+ // This includes an empty match at the start of the string.
+ continue;
+ }
+ int end = matchStart;
+ result.add(this.substring(start, end));
+ start = matchEnd;
+ }
+ if (start < this.length || length > 0) {
+ // An empty match at the end of the string does not cause a "" at the end.
+ // A non-empty match ending at the end of the string does add a "".
+ result.add(this.substring(start));
+ }
+ return result;
+ }
+
+ bool startsWith(Pattern pattern, [int index = 0]) {
+ checkInt(index);
+ if (index < 0 || index > this.length) {
+ throw new RangeError.range(index, 0, this.length);
+ }
+ if (pattern is String) {
+ String other = pattern;
+ int otherLength = other.length;
+ int endIndex = index + otherLength;
+ if (endIndex > length) return false;
+ return other == JS('String', r'#.substring(#, #)', this, index, endIndex);
+ }
+ return pattern.matchAsPrefix(this, index) != null;
+ }
+
+ String substring(int startIndex, [int endIndex]) {
+ checkInt(startIndex);
+ if (endIndex == null) endIndex = length;
+ checkInt(endIndex);
+ if (startIndex < 0) throw new RangeError.value(startIndex);
+ if (startIndex > endIndex) throw new RangeError.value(startIndex);
+ if (endIndex > length) throw new RangeError.value(endIndex);
+ return JS('String', r'#.substring(#, #)', this, startIndex, endIndex);
+ }
+
+ String toLowerCase() {
+ return JS('returns:String;effects:none;depends:none;throws:null(1)',
+ r'#.toLowerCase()', this);
+ }
+
+ String toUpperCase() {
+ return JS('returns:String;effects:none;depends:none;throws:null(1)',
+ r'#.toUpperCase()', this);
+ }
+
+ // Characters with Whitespace property (Unicode 6.3).
+ // 0009..000D ; White_Space # Cc <control-0009>..<control-000D>
+ // 0020 ; White_Space # Zs SPACE
+ // 0085 ; White_Space # Cc <control-0085>
+ // 00A0 ; White_Space # Zs NO-BREAK SPACE
+ // 1680 ; White_Space # Zs OGHAM SPACE MARK
+ // 2000..200A ; White_Space # Zs EN QUAD..HAIR SPACE
+ // 2028 ; White_Space # Zl LINE SEPARATOR
+ // 2029 ; White_Space # Zp PARAGRAPH SEPARATOR
+ // 202F ; White_Space # Zs NARROW NO-BREAK SPACE
+ // 205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE
+ // 3000 ; White_Space # Zs IDEOGRAPHIC SPACE
+ //
+ // BOM: 0xFEFF
+ static bool _isWhitespace(int codeUnit) {
+ // Most codeUnits should be less than 256. Special case with a smaller
+ // switch.
+ if (codeUnit < 256) {
+ switch (codeUnit) {
+ case 0x09:
+ case 0x0A:
+ case 0x0B:
+ case 0x0C:
+ case 0x0D:
+ case 0x20:
+ case 0x85:
+ case 0xA0:
+ return true;
+ default:
+ return false;
+ }
+ }
+ switch (codeUnit) {
+ case 0x1680:
+ case 0x2000:
+ case 0x2001:
+ case 0x2002:
+ case 0x2003:
+ case 0x2004:
+ case 0x2005:
+ case 0x2006:
+ case 0x2007:
+ case 0x2008:
+ case 0x2009:
+ case 0x200A:
+ case 0x2028:
+ case 0x2029:
+ case 0x202F:
+ case 0x205F:
+ case 0x3000:
+ case 0xFEFF:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /// Finds the index of the first non-whitespace character, or the
+ /// end of the string. Start looking at position [index].
+ static int _skipLeadingWhitespace(String string, int index) {
+ const int SPACE = 0x20;
+ const int CARRIAGE_RETURN = 0x0D;
+ while (index < string.length) {
+ int codeUnit = string.codeUnitAt(index);
+ if (codeUnit != SPACE &&
+ codeUnit != CARRIAGE_RETURN &&
+ !_isWhitespace(codeUnit)) {
+ break;
+ }
+ index++;
+ }
+ return index;
+ }
+
+ /// Finds the index after the last non-whitespace character, or 0.
+ /// Start looking at position [index - 1].
+ static int _skipTrailingWhitespace(String string, int index) {
+ const int SPACE = 0x20;
+ const int CARRIAGE_RETURN = 0x0D;
+ while (index > 0) {
+ int codeUnit = string.codeUnitAt(index - 1);
+ if (codeUnit != SPACE &&
+ codeUnit != CARRIAGE_RETURN &&
+ !_isWhitespace(codeUnit)) {
+ break;
+ }
+ index--;
+ }
+ return index;
+ }
+
+ // Dart2js can't use JavaScript trim directly,
+ // because JavaScript does not trim
+ // the NEXT LINE (NEL) character (0x85).
+ String trim() {
+ const int NEL = 0x85;
+
+ // Start by doing JS trim. Then check if it leaves a NEL at
+ // either end of the string.
+ String result = JS('String', '#.trim()', this);
+ if (result.length == 0) return result;
+ int firstCode = result.codeUnitAt(0);
+ int startIndex = 0;
+ if (firstCode == NEL) {
+ startIndex = _skipLeadingWhitespace(result, 1);
+ if (startIndex == result.length) return "";
+ }
+
+ int endIndex = result.length;
+ // We know that there is at least one character that is non-whitespace.
+ // Therefore we don't need to verify that endIndex > startIndex.
+ int lastCode = result.codeUnitAt(endIndex - 1);
+ if (lastCode == NEL) {
+ endIndex = _skipTrailingWhitespace(result, endIndex - 1);
+ }
+ if (startIndex == 0 && endIndex == result.length) return result;
+ return JS('String', r'#.substring(#, #)', result, startIndex, endIndex);
+ }
+
+ // Dart2js can't use JavaScript trimLeft directly,
+ // because it is not in ES5, so not every browser implements it,
+ // and because those that do will not trim the NEXT LINE character (0x85).
+ String trimLeft() {
+ const int NEL = 0x85;
+
+ // Start by doing JS trim. Then check if it leaves a NEL at
+ // the beginning of the string.
+ String result;
+ int startIndex = 0;
+ if (JS('bool', 'typeof #.trimLeft != "undefined"', this)) {
+ result = JS('String', '#.trimLeft()', this);
+ if (result.length == 0) return result;
+ int firstCode = result.codeUnitAt(0);
+ if (firstCode == NEL) {
+ startIndex = _skipLeadingWhitespace(result, 1);
+ }
+ } else {
+ result = this;
+ startIndex = _skipLeadingWhitespace(this, 0);
+ }
+ if (startIndex == 0) return result;
+ if (startIndex == result.length) return "";
+ return JS('String', r'#.substring(#)', result, startIndex);
+ }
+
+ // Dart2js can't use JavaScript trimRight directly,
+ // because it is not in ES5 and because JavaScript does not trim
+ // the NEXT LINE character (0x85).
+ String trimRight() {
+ const int NEL = 0x85;
+
+ // Start by doing JS trim. Then check if it leaves a NEL or BOM at
+ // the end of the string.
+ String result;
+ int endIndex;
+ // trimRight is implemented by Firefox and Chrome/Blink,
+ // so use it if it is there.
+ if (JS('bool', 'typeof #.trimRight != "undefined"', this)) {
+ result = JS('String', '#.trimRight()', this);
+ endIndex = result.length;
+ if (endIndex == 0) return result;
+ int lastCode = result.codeUnitAt(endIndex - 1);
+ if (lastCode == NEL) {
+ endIndex = _skipTrailingWhitespace(result, endIndex - 1);
+ }
+ } else {
+ result = this;
+ endIndex = _skipTrailingWhitespace(this, this.length);
+ }
+
+ if (endIndex == result.length) return result;
+ if (endIndex == 0) return "";
+ return JS('String', r'#.substring(#, #)', result, 0, endIndex);
+ }
+
+ String operator *(int times) {
+ if (0 >= times) return ''; // Unnecessary but hoists argument type check.
+ if (times == 1 || this.length == 0) return this;
+ if (times != JS('JSUInt32', '# >>> 0', times)) {
+ // times >= 2^32. We can't create a string that big.
+ throw const OutOfMemoryError();
+ }
+ var result = '';
+ var s = this;
+ while (true) {
+ if (times & 1 == 1) result = s + result;
+ times = JS('JSUInt31', '# >>> 1', times);
+ if (times == 0) break;
+ s += s;
+ }
+ return result;
+ }
+
+ String padLeft(int width, [String padding = ' ']) {
+ int delta = width - this.length;
+ if (delta <= 0) return this;
+ return padding * delta + this;
+ }
+
+ String padRight(int width, [String padding = ' ']) {
+ int delta = width - this.length;
+ if (delta <= 0) return this;
+ return this + padding * delta;
+ }
+
+ List<int> get codeUnits => new CodeUnits(this);
+
+ Runes get runes => new Runes(this);
+
+ int indexOf(Pattern pattern, [int start = 0]) {
+ checkNull(pattern);
+ if (start is! int) throw argumentErrorValue(start);
+ if (start < 0 || start > this.length) {
+ throw new RangeError.range(start, 0, this.length);
+ }
+ if (pattern is String) {
+ return stringIndexOfStringUnchecked(this, pattern, start);
+ }
+ if (pattern is JSSyntaxRegExp) {
+ JSSyntaxRegExp re = pattern;
+ Match match = firstMatchAfter(re, this, start);
+ return (match == null) ? -1 : match.start;
+ }
+ for (int i = start; i <= this.length; i++) {
+ if (pattern.matchAsPrefix(this, i) != null) return i;
+ }
+ return -1;
+ }
+
+ int lastIndexOf(Pattern pattern, [int start]) {
+ checkNull(pattern);
+ if (start == null) {
+ start = length;
+ } else if (start is! int) {
+ throw argumentErrorValue(start);
+ } else if (start < 0 || start > this.length) {
+ throw new RangeError.range(start, 0, this.length);
+ }
+ if (pattern is String) {
+ String other = pattern;
+ if (start + other.length > this.length) {
+ start = this.length - other.length;
+ }
+ return stringLastIndexOfUnchecked(this, other, start);
+ }
+ for (int i = start; i >= 0; i--) {
+ if (pattern.matchAsPrefix(this, i) != null) return i;
+ }
+ return -1;
+ }
+
+ bool contains(Pattern other, [int startIndex = 0]) {
+ checkNull(other);
+ if (startIndex < 0 || startIndex > this.length) {
+ throw new RangeError.range(startIndex, 0, this.length);
+ }
+ return stringContainsUnchecked(this, other, startIndex);
+ }
+
+ bool get isEmpty => length == 0;
+
+ bool get isNotEmpty => !isEmpty;
+
+ int compareTo(String other) {
+ if (other is! String) throw argumentErrorValue(other);
+ return this == other ? 0 : JS('bool', r'# < #', this, other) ? -1 : 1;
+ }
+
+ // Note: if you change this, also change the function [S].
+ String toString() => this;
+
+ /// This is the [Jenkins hash function][1] but using masking to keep
+ /// values in SMI range.
+ ///
+ /// [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+ int get hashCode {
+ // TODO(ahe): This method shouldn't have to use JS. Update when our
+ // optimizations are smarter.
+ int hash = 0;
+ for (int i = 0; i < length; i++) {
+ hash = 0x1fffffff & (hash + JS('int', r'#.charCodeAt(#)', this, i));
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+ hash = JS('int', '# ^ (# >> 6)', hash, hash);
+ }
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+ hash = JS('int', '# ^ (# >> 11)', hash, hash);
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+ }
+
+ Type get runtimeType => String;
+
+ int get length => JS('int', r'#.length', this);
+
+ String operator [](int index) {
+ if (index is! int) throw diagnoseIndexError(this, index);
+ if (index >= length || index < 0) throw diagnoseIndexError(this, index);
+ return JS('String', '#[#]', this, index);
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/linked_hash_map.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/linked_hash_map.dart
new file mode 100644
index 0000000..42ad0c4
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/linked_hash_map.dart
@@ -0,0 +1,439 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Efficient JavaScript based implementation of a linked hash map used as a
+// backing map for constant maps and the [LinkedHashMap] patch
+
+part of _js_helper;
+
+const _USE_ES6_MAPS = const bool.fromEnvironment("dart2js.use.es6.maps");
+
+class JsLinkedHashMap<K, V> extends MapBase<K, V>
+ implements LinkedHashMap<K, V>, InternalMap {
+ int _length = 0;
+
+ // The hash map contents are divided into three parts: one part for
+ // string keys, one for numeric keys, and one for the rest. String
+ // and numeric keys map directly to their linked cells, but the rest
+ // of the entries are stored in bucket lists of the form:
+ //
+ // [cell-0, cell-1, ...]
+ //
+ // where all keys in the same bucket share the same hash code.
+ var _strings;
+ var _nums;
+ var _rest;
+
+ // The keys and values are stored in cells that are linked together
+ // to form a double linked list.
+ LinkedHashMapCell _first;
+ LinkedHashMapCell _last;
+
+ // We track the number of modifications done to the key set of the
+ // hash map to be able to throw when the map is modified while being
+ // iterated over.
+ int _modifications = 0;
+
+ static bool get _supportsEs6Maps {
+ return JS('returns:bool;depends:none;effects:none;throws:never;gvn:true',
+ 'typeof Map != "undefined"');
+ }
+
+ JsLinkedHashMap();
+
+ /// If ES6 Maps are available returns a linked hash-map backed by an ES6 Map.
+ @pragma('dart2js:tryInline')
+ factory JsLinkedHashMap.es6() {
+ return (_USE_ES6_MAPS && JsLinkedHashMap._supportsEs6Maps)
+ ? new Es6LinkedHashMap<K, V>()
+ : new JsLinkedHashMap<K, V>();
+ }
+
+ int get length => _length;
+ bool get isEmpty => _length == 0;
+ bool get isNotEmpty => !isEmpty;
+
+ Iterable<K> get keys {
+ return new LinkedHashMapKeyIterable<K>(this);
+ }
+
+ Iterable<V> get values {
+ return new MappedIterable<K, V>(keys, (each) => this[each]);
+ }
+
+ bool containsKey(Object key) {
+ if (_isStringKey(key)) {
+ var strings = _strings;
+ if (strings == null) return false;
+ return _containsTableEntry(strings, key);
+ } else if (_isNumericKey(key)) {
+ var nums = _nums;
+ if (nums == null) return false;
+ return _containsTableEntry(nums, key);
+ } else {
+ return internalContainsKey(key);
+ }
+ }
+
+ bool internalContainsKey(Object key) {
+ var rest = _rest;
+ if (rest == null) return false;
+ var bucket = _getBucket(rest, key);
+ return internalFindBucketIndex(bucket, key) >= 0;
+ }
+
+ bool containsValue(Object value) {
+ return keys.any((each) => this[each] == value);
+ }
+
+ void addAll(Map<K, V> other) {
+ other.forEach((K key, V value) {
+ this[key] = value;
+ });
+ }
+
+ V operator [](Object key) {
+ if (_isStringKey(key)) {
+ var strings = _strings;
+ if (strings == null) return null;
+ LinkedHashMapCell cell = _getTableCell(strings, key);
+ return JS('', '#', cell == null ? null : cell.hashMapCellValue);
+ } else if (_isNumericKey(key)) {
+ var nums = _nums;
+ if (nums == null) return null;
+ LinkedHashMapCell cell = _getTableCell(nums, key);
+ return JS('', '#', cell == null ? null : cell.hashMapCellValue);
+ } else {
+ return internalGet(key);
+ }
+ }
+
+ V internalGet(Object key) {
+ var rest = _rest;
+ if (rest == null) return null;
+ var bucket = _getBucket(rest, key);
+ int index = internalFindBucketIndex(bucket, key);
+ if (index < 0) return null;
+ LinkedHashMapCell cell = JS('var', '#[#]', bucket, index);
+ return JS('', '#', cell.hashMapCellValue);
+ }
+
+ void operator []=(K key, V value) {
+ if (_isStringKey(key)) {
+ var strings = _strings;
+ if (strings == null) _strings = strings = _newHashTable();
+ _addHashTableEntry(strings, key, value);
+ } else if (_isNumericKey(key)) {
+ var nums = _nums;
+ if (nums == null) _nums = nums = _newHashTable();
+ _addHashTableEntry(nums, key, value);
+ } else {
+ internalSet(key, value);
+ }
+ }
+
+ void internalSet(K key, V value) {
+ var rest = _rest;
+ if (rest == null) _rest = rest = _newHashTable();
+ var hash = internalComputeHashCode(key);
+ var bucket = _getTableBucket(rest, hash);
+ if (bucket == null) {
+ LinkedHashMapCell cell = _newLinkedCell(key, value);
+ _setTableEntry(rest, hash, JS('var', '[#]', cell));
+ } else {
+ int index = internalFindBucketIndex(bucket, key);
+ if (index >= 0) {
+ LinkedHashMapCell cell = JS('var', '#[#]', bucket, index);
+ cell.hashMapCellValue = value;
+ } else {
+ LinkedHashMapCell cell = _newLinkedCell(key, value);
+ JS('void', '#.push(#)', bucket, cell);
+ }
+ }
+ }
+
+ V putIfAbsent(K key, V ifAbsent()) {
+ if (containsKey(key)) return this[key];
+ V value = ifAbsent();
+ this[key] = value;
+ return value;
+ }
+
+ V remove(Object key) {
+ if (_isStringKey(key)) {
+ return _removeHashTableEntry(_strings, key);
+ } else if (_isNumericKey(key)) {
+ return _removeHashTableEntry(_nums, key);
+ } else {
+ return internalRemove(key);
+ }
+ }
+
+ V internalRemove(Object key) {
+ var rest = _rest;
+ if (rest == null) return null;
+ var hash = internalComputeHashCode(key);
+ var bucket = _getTableBucket(rest, hash);
+ int index = internalFindBucketIndex(bucket, key);
+ if (index < 0) return null;
+ // Use splice to remove the [cell] element at the index and
+ // unlink the cell before returning its value.
+ LinkedHashMapCell cell = JS('var', '#.splice(#, 1)[0]', bucket, index);
+ _unlinkCell(cell);
+ // Remove empty bucket list to avoid memory leak.
+ if (JS('int', '#.length', bucket) == 0) {
+ _deleteTableEntry(rest, hash);
+ }
+ return JS('', '#', cell.hashMapCellValue);
+ }
+
+ void clear() {
+ if (_length > 0) {
+ _strings = _nums = _rest = _first = _last = null;
+ _length = 0;
+ _modified();
+ }
+ }
+
+ void forEach(void action(K key, V value)) {
+ LinkedHashMapCell cell = _first;
+ int modifications = _modifications;
+ while (cell != null) {
+ K key = JS('', '#', cell.hashMapCellKey);
+ V value = JS('', '#', cell.hashMapCellValue);
+ action(key, value);
+ if (modifications != _modifications) {
+ throw new ConcurrentModificationError(this);
+ }
+ cell = cell._next;
+ }
+ }
+
+ void _addHashTableEntry(var table, K key, V value) {
+ LinkedHashMapCell cell = _getTableCell(table, key);
+ if (cell == null) {
+ _setTableEntry(table, key, _newLinkedCell(key, value));
+ } else {
+ cell.hashMapCellValue = value;
+ }
+ }
+
+ V _removeHashTableEntry(var table, Object key) {
+ if (table == null) return null;
+ LinkedHashMapCell cell = _getTableCell(table, key);
+ if (cell == null) return null;
+ _unlinkCell(cell);
+ _deleteTableEntry(table, key);
+ return JS('', '#', cell.hashMapCellValue);
+ }
+
+ void _modified() {
+ // Value cycles after 2^30 modifications so that modification counts are
+ // always unboxed (Smi) values. Modification detection will be missed if you
+ // make exactly some multiple of 2^30 modifications between advances of an
+ // iterator.
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+
+ // Create a new cell and link it in as the last one in the list.
+ LinkedHashMapCell _newLinkedCell(K key, V value) {
+ LinkedHashMapCell cell = new LinkedHashMapCell(key, value);
+ if (_first == null) {
+ _first = _last = cell;
+ } else {
+ LinkedHashMapCell last = _last;
+ cell._previous = last;
+ _last = last._next = cell;
+ }
+ _length++;
+ _modified();
+ return cell;
+ }
+
+ // Unlink the given cell from the linked list of cells.
+ void _unlinkCell(LinkedHashMapCell cell) {
+ LinkedHashMapCell previous = cell._previous;
+ LinkedHashMapCell next = cell._next;
+ if (previous == null) {
+ assert(cell == _first);
+ _first = next;
+ } else {
+ previous._next = next;
+ }
+ if (next == null) {
+ assert(cell == _last);
+ _last = previous;
+ } else {
+ next._previous = previous;
+ }
+ _length--;
+ _modified();
+ }
+
+ static bool _isStringKey(var key) {
+ return key is String;
+ }
+
+ static bool _isNumericKey(var key) {
+ // Only treat unsigned 30-bit integers as numeric keys. This way,
+ // we avoid converting them to strings when we use them as keys in
+ // the JavaScript hash table object.
+ return key is num && JS('bool', '(# & 0x3ffffff) === #', key, key);
+ }
+
+ int internalComputeHashCode(var key) {
+ // We force the hash codes to be unsigned 30-bit integers to avoid
+ // issues with problematic keys like '__proto__'. Another option
+ // would be to throw an exception if the hash code isn't a number.
+ return JS('int', '# & 0x3ffffff', key.hashCode);
+ }
+
+ List<LinkedHashMapCell> _getBucket(var table, var key) {
+ var hash = internalComputeHashCode(key);
+ return _getTableBucket(table, hash);
+ }
+
+ int internalFindBucketIndex(var bucket, var key) {
+ if (bucket == null) return -1;
+ int length = JS('int', '#.length', bucket);
+ for (int i = 0; i < length; i++) {
+ LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
+ if (cell.hashMapCellKey == key) return i;
+ }
+ return -1;
+ }
+
+ String toString() => MapBase.mapToString(this);
+
+ LinkedHashMapCell _getTableCell(var table, var key) {
+ return JS('var', '#[#]', table, key);
+ }
+
+ List<LinkedHashMapCell> _getTableBucket(var table, var key) {
+ return JS('var', '#[#]', table, key);
+ }
+
+ void _setTableEntry(var table, var key, var value) {
+ assert(value != null);
+ JS('void', '#[#] = #', table, key, value);
+ }
+
+ void _deleteTableEntry(var table, var key) {
+ JS('void', 'delete #[#]', table, key);
+ }
+
+ bool _containsTableEntry(var table, var key) {
+ LinkedHashMapCell cell = _getTableCell(table, key);
+ return cell != null;
+ }
+
+ _newHashTable() {
+ // Create a new JavaScript object to be used as a hash table. Use
+ // Object.create to avoid the properties on Object.prototype
+ // showing up as entries.
+ var table = JS('var', 'Object.create(null)');
+ // Attempt to force the hash table into 'dictionary' mode by
+ // adding a property to it and deleting it again.
+ var temporaryKey = '<non-identifier-key>';
+ _setTableEntry(table, temporaryKey, table);
+ _deleteTableEntry(table, temporaryKey);
+ return table;
+ }
+}
+
+class Es6LinkedHashMap<K, V> extends JsLinkedHashMap<K, V> {
+ @override
+ LinkedHashMapCell _getTableCell(var table, var key) {
+ return JS('var', '#.get(#)', table, key);
+ }
+
+ @override
+ List<LinkedHashMapCell> _getTableBucket(var table, var key) {
+ return JS('var', '#.get(#)', table, key);
+ }
+
+ @override
+ void _setTableEntry(var table, var key, var value) {
+ JS('void', '#.set(#, #)', table, key, value);
+ }
+
+ @override
+ void _deleteTableEntry(var table, var key) {
+ JS('void', '#.delete(#)', table, key);
+ }
+
+ @override
+ bool _containsTableEntry(var table, var key) {
+ return JS('bool', '#.has(#)', table, key);
+ }
+
+ @override
+ _newHashTable() {
+ return JS('var', 'new Map()');
+ }
+}
+
+class LinkedHashMapCell {
+ final dynamic hashMapCellKey;
+ dynamic hashMapCellValue;
+
+ LinkedHashMapCell _next;
+ LinkedHashMapCell _previous;
+
+ LinkedHashMapCell(this.hashMapCellKey, this.hashMapCellValue);
+}
+
+class LinkedHashMapKeyIterable<E> extends EfficientLengthIterable<E> {
+ final dynamic _map;
+ LinkedHashMapKeyIterable(this._map);
+
+ int get length => _map._length;
+ bool get isEmpty => _map._length == 0;
+
+ Iterator<E> get iterator {
+ return new LinkedHashMapKeyIterator<E>(_map, _map._modifications);
+ }
+
+ bool contains(Object element) {
+ return _map.containsKey(element);
+ }
+
+ void forEach(void f(E element)) {
+ LinkedHashMapCell cell = _map._first;
+ int modifications = _map._modifications;
+ while (cell != null) {
+ f(JS('', '#', cell.hashMapCellKey));
+ if (modifications != _map._modifications) {
+ throw new ConcurrentModificationError(_map);
+ }
+ cell = cell._next;
+ }
+ }
+}
+
+class LinkedHashMapKeyIterator<E> implements Iterator<E> {
+ final dynamic _map;
+ final int _modifications;
+ LinkedHashMapCell _cell;
+ E _current;
+
+ LinkedHashMapKeyIterator(this._map, this._modifications) {
+ _cell = _map._first;
+ }
+
+ E get current => _current;
+
+ bool moveNext() {
+ if (_modifications != _map._modifications) {
+ throw new ConcurrentModificationError(_map);
+ } else if (_cell == null) {
+ _current = null;
+ return false;
+ } else {
+ _current = JS('', '#', _cell.hashMapCellKey);
+ _cell = _cell._next;
+ return true;
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/math_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/math_patch.dart
new file mode 100644
index 0000000..677953e
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/math_patch.dart
@@ -0,0 +1,329 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:math library.
+import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper' show patch, checkNum;
+import 'dart:typed_data' show ByteData;
+
+@patch
+T min<T extends num>(T a, T b) => JS(
+ 'returns:num;depends:none;effects:none;gvn:true',
+ r'Math.min(#, #)',
+ checkNum(a),
+ checkNum(b));
+
+@patch
+T max<T extends num>(T a, T b) => JS(
+ 'returns:num;depends:none;effects:none;gvn:true',
+ r'Math.max(#, #)',
+ checkNum(a),
+ checkNum(b));
+
+@patch
+double sqrt(num x) => JS('num', r'Math.sqrt(#)', checkNum(x));
+
+@patch
+double sin(num radians) => JS('num', r'Math.sin(#)', checkNum(radians));
+
+@patch
+double cos(num radians) => JS('num', r'Math.cos(#)', checkNum(radians));
+
+@patch
+double tan(num radians) => JS('num', r'Math.tan(#)', checkNum(radians));
+
+@patch
+double acos(num x) => JS('num', r'Math.acos(#)', checkNum(x));
+
+@patch
+double asin(num x) => JS('num', r'Math.asin(#)', checkNum(x));
+
+@patch
+double atan(num x) => JS('num', r'Math.atan(#)', checkNum(x));
+
+@patch
+double atan2(num a, num b) =>
+ JS('num', r'Math.atan2(#, #)', checkNum(a), checkNum(b));
+
+@patch
+double exp(num x) => JS('num', r'Math.exp(#)', checkNum(x));
+
+@patch
+double log(num x) => JS('num', r'Math.log(#)', checkNum(x));
+
+@patch
+num pow(num x, num exponent) {
+ checkNum(x);
+ checkNum(exponent);
+ return JS('num', r'Math.pow(#, #)', x, exponent);
+}
+
+const int _POW2_32 = 0x100000000;
+
+@patch
+class Random {
+ static Random _secureRandom;
+
+ @patch
+ factory Random([int seed]) =>
+ (seed == null) ? const _JSRandom() : new _Random(seed);
+
+ @patch
+ factory Random.secure() => _secureRandom ??= _JSSecureRandom();
+}
+
+class _JSRandom implements Random {
+ // The Dart2JS implementation of Random doesn't use a seed.
+ const _JSRandom();
+
+ int nextInt(int max) {
+ if (max <= 0 || max > _POW2_32) {
+ throw new RangeError('max must be in range 0 < max ≤ 2^32, was $max');
+ }
+ return JS('int', '(Math.random() * #) >>> 0', max);
+ }
+
+ /// Generates a positive random floating point value uniformly distributed on
+ /// the range from 0.0, inclusive, to 1.0, exclusive.
+ double nextDouble() => JS('double', 'Math.random()');
+
+ /// Generates a random boolean value.
+ bool nextBool() => JS('bool', 'Math.random() < 0.5');
+}
+
+class _Random implements Random {
+ // Constants used by the algorithm or masking.
+ static const double _POW2_53_D = 1.0 * (0x20000000000000);
+ static const double _POW2_27_D = 1.0 * (1 << 27);
+ static const int _MASK32 = 0xFFFFFFFF;
+
+ // State comprised of two unsigned 32 bit integers.
+ int _lo = 0;
+ int _hi = 0;
+
+ // Implements:
+ // uint64_t hash = 0;
+ // do {
+ // hash = hash * 1037 ^ mix64((uint64_t)seed);
+ // seed >>= 64;
+ // } while (seed != 0 && seed != -1); // Limits for pos/neg seed.
+ // if (hash == 0) {
+ // hash = 0x5A17;
+ // }
+ // _lo = hash & _MASK_32;
+ // _hi = hash >> 32;
+ // and then does four _nextState calls to shuffle bits around.
+ _Random(int seed) {
+ int empty_seed = 0;
+ if (seed < 0) {
+ empty_seed = -1;
+ }
+ do {
+ int low = seed & _MASK32;
+ seed = (seed - low) ~/ _POW2_32;
+ int high = seed & _MASK32;
+ seed = (seed - high) ~/ _POW2_32;
+
+ // Thomas Wang's 64-bit mix function.
+ // http://www.concentric.net/~Ttwang/tech/inthash.htm
+ // via. http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
+
+ // key = ~key + (key << 21);
+ int tmplow = low << 21;
+ int tmphigh = (high << 21) | (low >> 11);
+ tmplow = (~low & _MASK32) + tmplow;
+ low = tmplow & _MASK32;
+ high = (~high + tmphigh + ((tmplow - low) ~/ 0x100000000)) & _MASK32;
+ // key = key ^ (key >> 24).
+ tmphigh = high >> 24;
+ tmplow = (low >> 24) | (high << 8);
+ low ^= tmplow;
+ high ^= tmphigh;
+ // key = key * 265
+ tmplow = low * 265;
+ low = tmplow & _MASK32;
+ high = (high * 265 + (tmplow - low) ~/ 0x100000000) & _MASK32;
+ // key = key ^ (key >> 14);
+ tmphigh = high >> 14;
+ tmplow = (low >> 14) | (high << 18);
+ low ^= tmplow;
+ high ^= tmphigh;
+ // key = key * 21
+ tmplow = low * 21;
+ low = tmplow & _MASK32;
+ high = (high * 21 + (tmplow - low) ~/ 0x100000000) & _MASK32;
+ // key = key ^ (key >> 28).
+ tmphigh = high >> 28;
+ tmplow = (low >> 28) | (high << 4);
+ low ^= tmplow;
+ high ^= tmphigh;
+ // key = key + (key << 31);
+ tmplow = low << 31;
+ tmphigh = (high << 31) | (low >> 1);
+ tmplow += low;
+ low = tmplow & _MASK32;
+ high = (high + tmphigh + (tmplow - low) ~/ 0x100000000) & _MASK32;
+ // Mix end.
+
+ // seed = seed * 1037 ^ key;
+ tmplow = _lo * 1037;
+ _lo = tmplow & _MASK32;
+ _hi = (_hi * 1037 + (tmplow - _lo) ~/ 0x100000000) & _MASK32;
+ _lo ^= low;
+ _hi ^= high;
+ } while (seed != empty_seed);
+
+ if (_hi == 0 && _lo == 0) {
+ _lo = 0x5A17;
+ }
+ _nextState();
+ _nextState();
+ _nextState();
+ _nextState();
+ }
+
+ // The algorithm used here is Multiply with Carry (MWC) with a Base b = 2^32.
+ // http://en.wikipedia.org/wiki/Multiply-with-carry
+ // The constant A (0xFFFFDA61) is selected from "Numerical Recipes 3rd
+ // Edition" p.348 B1.
+
+ // Implements:
+ // var state = (A * _lo + _hi) & _MASK_64;
+ // _lo = state & _MASK_32;
+ // _hi = state >> 32;
+ void _nextState() {
+ // Simulate (0xFFFFDA61 * lo + hi) without overflowing 53 bits.
+ int tmpHi = 0xFFFF0000 * _lo; // At most 48 bits of significant result.
+ int tmpHiLo = tmpHi & _MASK32; // Get the lower 32 bits.
+ int tmpHiHi = tmpHi - tmpHiLo; // And just the upper 32 bits.
+ int tmpLo = 0xDA61 * _lo;
+ int tmpLoLo = tmpLo & _MASK32;
+ int tmpLoHi = tmpLo - tmpLoLo;
+
+ int newLo = tmpLoLo + tmpHiLo + _hi;
+ _lo = newLo & _MASK32;
+ int newLoHi = newLo - _lo;
+ _hi = ((tmpLoHi + tmpHiHi + newLoHi) ~/ _POW2_32) & _MASK32;
+ assert(_lo < _POW2_32);
+ assert(_hi < _POW2_32);
+ }
+
+ int nextInt(int max) {
+ if (max <= 0 || max > _POW2_32) {
+ throw new RangeError('max must be in range 0 < max ≤ 2^32, was $max');
+ }
+ if ((max & (max - 1)) == 0) {
+ // Fast case for powers of two.
+ _nextState();
+ return _lo & (max - 1);
+ }
+
+ int rnd32;
+ int result;
+ do {
+ _nextState();
+ rnd32 = _lo;
+ result = rnd32.remainder(max); // % max;
+ } while ((rnd32 - result + max) >= _POW2_32);
+ return result;
+ }
+
+ double nextDouble() {
+ _nextState();
+ int bits26 = _lo & ((1 << 26) - 1);
+ _nextState();
+ int bits27 = _lo & ((1 << 27) - 1);
+ return (bits26 * _POW2_27_D + bits27) / _POW2_53_D;
+ }
+
+ bool nextBool() {
+ _nextState();
+ return (_lo & 1) == 0;
+ }
+}
+
+class _JSSecureRandom implements Random {
+ // Reused buffer with room enough for a double.
+ final _buffer = new ByteData(8);
+
+ _JSSecureRandom() {
+ var crypto = JS('', 'self.crypto');
+ if (crypto != null) {
+ var getRandomValues = JS('', '#.getRandomValues', crypto);
+ if (getRandomValues != null) {
+ return;
+ }
+ }
+ throw new UnsupportedError(
+ 'No source of cryptographically secure random numbers available.');
+ }
+
+ /// Fill _buffer from [start] to `start + length` with random bytes.
+ void _getRandomBytes(int start, int length) {
+ JS('void', 'crypto.getRandomValues(#)',
+ _buffer.buffer.asUint8List(start, length));
+ }
+
+ bool nextBool() {
+ _getRandomBytes(0, 1);
+ return _buffer.getUint8(0).isOdd;
+ }
+
+ double nextDouble() {
+ _getRandomBytes(1, 7);
+ // Set top bits 12 of double to 0x3FF which is the exponent for numbers
+ // between 1.0 and 2.0.
+ _buffer.setUint8(0, 0x3F);
+ int highByte = _buffer.getUint8(1);
+ _buffer.setUint8(1, highByte | 0xF0);
+
+ // Buffer now contains double in the range [1.0-2.0)
+ // with 52 bits of entropy (not 53).
+ // To get 53 bits, we extract the 53rd bit from higthByte before
+ // overwriting it, and add that as a least significant bit.
+ // The getFloat64 method is big-endian as default.
+ double result = _buffer.getFloat64(0) - 1.0;
+ if (highByte & 0x10 != 0) {
+ result += 1.1102230246251565e-16; // pow(2,-53).
+ }
+ return result;
+ }
+
+ int nextInt(int max) {
+ if (max <= 0 || max > _POW2_32) {
+ throw new RangeError('max must be in range 0 < max ≤ 2^32, was $max');
+ }
+ int byteCount = 1;
+ if (max > 0xFF) {
+ byteCount++;
+ if (max > 0xFFFF) {
+ byteCount++;
+ if (max > 0xFFFFFF) {
+ byteCount++;
+ }
+ }
+ }
+ _buffer.setUint32(0, 0);
+ int start = 4 - byteCount;
+ int randomLimit = pow(256, byteCount);
+ while (true) {
+ _getRandomBytes(start, byteCount);
+ // The getUint32 method is big-endian as default.
+ int random = _buffer.getUint32(0);
+ if (max & (max - 1) == 0) {
+ // Max is power of 2.
+ return random & (max - 1);
+ }
+ int result = random.remainder(max);
+ // Ensure results have equal probability by rejecting values in the
+ // last range of k*max .. 256**byteCount.
+ // TODO: Consider picking a higher byte count if the last range is a
+ // significant portion of the entire range - a 50% chance of having
+ // to use two more bytes is no worse than always using one more.
+ if (random - result + max < randomLimit) {
+ return result;
+ }
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart
new file mode 100644
index 0000000..6f8018a
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch library for dart:mirrors.
+
+import 'dart:_js_helper' show patch;
+import 'dart:mirrors';
+
+const String _message = 'dart:mirrors is no longer supported for web apps';
+
+@patch
+MirrorSystem currentMirrorSystem() => throw new UnsupportedError(_message);
+
+@patch
+InstanceMirror reflect(Object reflectee) =>
+ throw new UnsupportedError(_message);
+
+@patch
+ClassMirror reflectClass(Type key) => throw new UnsupportedError(_message);
+
+@patch
+TypeMirror reflectType(Type key, [List<Type> typeArguments]) =>
+ throw new UnsupportedError(_message);
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/native_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/native_helper.dart
new file mode 100644
index 0000000..ccfa26f
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/native_helper.dart
@@ -0,0 +1,592 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _js_helper;
+
+// TODO(ngeoffray): stop using this method once our optimizers can
+// change str1.contains(str2) into str1.indexOf(str2) != -1.
+bool contains(String userAgent, String name) {
+ return JS('int', '#.indexOf(#)', userAgent, name) != -1;
+}
+
+int arrayLength(List array) {
+ return JS('int', '#.length', array);
+}
+
+arrayGet(List array, int index) {
+ return JS('var', '#[#]', array, index);
+}
+
+void arraySet(List array, int index, var value) {
+ JS('var', '#[#] = #', array, index, value);
+}
+
+propertyGet(var object, String property) {
+ return JS('var', '#[#]', object, property);
+}
+
+bool callHasOwnProperty(var function, var object, String property) {
+ return JS('bool', '#.call(#, #)', function, object, property);
+}
+
+void propertySet(var object, String property, var value) {
+ JS('var', '#[#] = #', object, property, value);
+}
+
+getPropertyFromPrototype(var object, String name) {
+ return JS('var', 'Object.getPrototypeOf(#)[#]', object, name);
+}
+
+/// Returns a String tag identifying the type of the native object, or `null`.
+/// The tag is not the name of the type, but usually the name of the JavaScript
+/// constructor function. Initialized by [initHooks].
+Function getTagFunction;
+
+/// If a lookup via [getTagFunction] on an object [object] that has [tag] fails,
+/// this function is called to provide an alternate tag. This allows us to fail
+/// gracefully if we can make a good guess, for example, when browsers add novel
+/// kinds of HTMLElement that we have never heard of. Initialized by
+/// [initHooks].
+Function alternateTagFunction;
+
+/// Returns the prototype for the JavaScript constructor named by an input tag.
+/// Returns `null` if there is no such constructor, or if pre-patching of the
+/// constructor is to be avoided. Initialized by [initHooks].
+Function prototypeForTagFunction;
+
+String toStringForNativeObject(var obj) {
+ // TODO(sra): Is this code dead?
+ // [getTagFunction] might be uninitialized, but in usual usage, toString has
+ // been called via an interceptor and initialized it.
+ String name = getTagFunction == null
+ ? '<Unknown>'
+ : JS('String', '#', getTagFunction(obj));
+ return 'Instance of $name';
+}
+
+int hashCodeForNativeObject(object) => Primitives.objectHashCode(object);
+
+/// Sets a JavaScript property on an object.
+void defineProperty(var obj, String property, var value) {
+ JS(
+ 'void',
+ 'Object.defineProperty(#, #, '
+ '{value: #, enumerable: false, writable: true, configurable: true})',
+ obj,
+ property,
+ value);
+}
+
+// Is [obj] an instance of a Dart-defined class?
+bool isDartObject(obj) {
+ // Some of the extra parens here are necessary.
+ return JS(
+ 'bool',
+ '((#) instanceof (#))',
+ obj,
+ JS_BUILTIN(
+ 'depends:none;effects:none;', JsBuiltin.dartObjectConstructor));
+}
+
+/// A JavaScript object mapping tags to the constructors of interceptors.
+/// This is a JavaScript object with no prototype.
+///
+/// Example: 'HTMLImageElement' maps to the ImageElement class constructor.
+get interceptorsByTag => JS_EMBEDDED_GLOBAL('=Object', INTERCEPTORS_BY_TAG);
+
+/// A JavaScript object mapping tags to `true` or `false`.
+///
+/// Example: 'HTMLImageElement' maps to `true` since, as there are no subclasses
+/// of ImageElement, it is a leaf class in the native class hierarchy.
+get leafTags => JS_EMBEDDED_GLOBAL('=Object', LEAF_TAGS);
+
+String findDispatchTagForInterceptorClass(interceptorClassConstructor) {
+ return JS(
+ '', r'#.#', interceptorClassConstructor, NATIVE_SUPERCLASS_TAG_NAME);
+}
+
+/// Cache of dispatch records for instances. This is a JavaScript object used
+/// as a map. Keys are instance tags, e.g. "!SomeThing". The cache permits the
+/// sharing of one dispatch record between multiple instances.
+var dispatchRecordsForInstanceTags;
+
+/// Cache of interceptors indexed by uncacheable tags, e.g. "~SomeThing".
+/// This is a JavaScript object used as a map.
+var interceptorsForUncacheableTags;
+
+lookupInterceptor(String tag) {
+ return propertyGet(interceptorsByTag, tag);
+}
+
+// Dispatch tag marks are optional prefixes for a dispatch tag that direct how
+// the interceptor for the tag may be cached.
+
+/// No caching permitted.
+const UNCACHED_MARK = '~';
+
+/// Dispatch record must be cached per instance
+const INSTANCE_CACHED_MARK = '!';
+
+/// Dispatch record is cached on immediate prototype.
+const LEAF_MARK = '-';
+
+/// Dispatch record is cached on immediate prototype with a prototype
+/// verification to prevent the interceptor being associated with a subclass
+/// before a dispatch record is cached on the subclass.
+const INTERIOR_MARK = '+';
+
+/// A 'discriminator' function is to be used. TBD.
+const DISCRIMINATED_MARK = '*';
+
+/// Returns the interceptor for a native object, or returns `null` if not found.
+///
+/// A dispatch record is cached according to the specification of the dispatch
+/// tag for [obj].
+@pragma('dart2js:noInline')
+lookupAndCacheInterceptor(obj) {
+ assert(!isDartObject(obj));
+ String tag = getTagFunction(obj);
+
+ // Fast path for instance (and uncached) tags because the lookup is repeated
+ // for each instance (or getInterceptor call).
+ var record = propertyGet(dispatchRecordsForInstanceTags, tag);
+ if (record != null) return patchInstance(obj, record);
+ var interceptor = propertyGet(interceptorsForUncacheableTags, tag);
+ if (interceptor != null) return interceptor;
+
+ // This lookup works for derived dispatch tags because we add them all in
+ // [initNativeDispatch].
+ var interceptorClass = lookupInterceptor(tag);
+ if (interceptorClass == null) {
+ tag = alternateTagFunction(obj, tag);
+ if (tag != null) {
+ // Fast path for instance and uncached tags again.
+ record = propertyGet(dispatchRecordsForInstanceTags, tag);
+ if (record != null) return patchInstance(obj, record);
+ interceptor = propertyGet(interceptorsForUncacheableTags, tag);
+ if (interceptor != null) return interceptor;
+
+ interceptorClass = lookupInterceptor(tag);
+ }
+ }
+
+ if (interceptorClass == null) {
+ // This object is not known to Dart. There could be several reasons for
+ // that, including (but not limited to):
+ //
+ // * A bug in native code (hopefully this is caught during development).
+ // * An unknown DOM object encountered.
+ // * JavaScript code running in an unexpected context. For example, on
+ // node.js.
+ return null;
+ }
+
+ interceptor = JS('', '#.prototype', interceptorClass);
+
+ var mark = JS('String|Null', '#[0]', tag);
+
+ if (mark == INSTANCE_CACHED_MARK) {
+ record = makeLeafDispatchRecord(interceptor);
+ propertySet(dispatchRecordsForInstanceTags, tag, record);
+ return patchInstance(obj, record);
+ }
+
+ if (mark == UNCACHED_MARK) {
+ propertySet(interceptorsForUncacheableTags, tag, interceptor);
+ return interceptor;
+ }
+
+ if (mark == LEAF_MARK) {
+ return patchProto(obj, makeLeafDispatchRecord(interceptor));
+ }
+
+ if (mark == INTERIOR_MARK) {
+ return patchInteriorProto(obj, interceptor);
+ }
+
+ if (mark == DISCRIMINATED_MARK) {
+ // TODO(sra): Use discriminator of tag.
+ throw new UnimplementedError(tag);
+ }
+
+ // [tag] was not explicitly an interior or leaf tag, so
+ var isLeaf = JS('bool', '(#[#]) === true', leafTags, tag);
+ if (isLeaf) {
+ return patchProto(obj, makeLeafDispatchRecord(interceptor));
+ } else {
+ return patchInteriorProto(obj, interceptor);
+ }
+}
+
+patchInstance(obj, record) {
+ setDispatchProperty(obj, record);
+ return dispatchRecordInterceptor(record);
+}
+
+patchProto(obj, record) {
+ setDispatchProperty(JS('', 'Object.getPrototypeOf(#)', obj), record);
+ return dispatchRecordInterceptor(record);
+}
+
+patchInteriorProto(obj, interceptor) {
+ var proto = JS('', 'Object.getPrototypeOf(#)', obj);
+ var record = makeDispatchRecord(interceptor, proto, null, null);
+ setDispatchProperty(proto, record);
+ return interceptor;
+}
+
+makeLeafDispatchRecord(interceptor) {
+ var fieldName = JS_GET_NAME(JsGetName.IS_INDEXABLE_FIELD_NAME);
+ bool indexability = JS('bool', r'!!#[#]', interceptor, fieldName);
+ return makeDispatchRecord(interceptor, false, null, indexability);
+}
+
+makeDefaultDispatchRecord(tag, interceptorClass, proto) {
+ var interceptor = JS('', '#.prototype', interceptorClass);
+ var isLeaf = JS('bool', '(#[#]) === true', leafTags, tag);
+ if (isLeaf) {
+ return makeLeafDispatchRecord(interceptor);
+ } else {
+ return makeDispatchRecord(interceptor, proto, null, null);
+ }
+}
+
+/// [proto] should have no shadowing prototypes that are not also assigned a
+/// dispatch rescord.
+setNativeSubclassDispatchRecord(proto, interceptor) {
+ setDispatchProperty(proto, makeLeafDispatchRecord(interceptor));
+}
+
+String constructorNameFallback(object) {
+ return JS('String', '#(#)', _constructorNameFallback, object);
+}
+
+var initNativeDispatchFlag; // null or true
+
+@pragma('dart2js:noInline')
+void initNativeDispatch() {
+ if (true == initNativeDispatchFlag) return;
+ initNativeDispatchFlag = true;
+ initNativeDispatchContinue();
+}
+
+@pragma('dart2js:noInline')
+void initNativeDispatchContinue() {
+ dispatchRecordsForInstanceTags = JS('', 'Object.create(null)');
+ interceptorsForUncacheableTags = JS('', 'Object.create(null)');
+
+ initHooks();
+
+ // Try to pro-actively patch prototypes of DOM objects. For each of our known
+ // tags `TAG`, if `window.TAG` is a (constructor) function, set the dispatch
+ // property if the function's prototype to a dispatch record.
+ var map = interceptorsByTag;
+ var tags = JS('JSMutableArray', 'Object.getOwnPropertyNames(#)', map);
+
+ if (JS('bool', 'typeof window != "undefined"')) {
+ var context = JS('=Object', 'window');
+ var fun = JS('=Object', 'function () {}');
+ for (int i = 0; i < tags.length; i++) {
+ var tag = tags[i];
+ var proto = prototypeForTagFunction(tag);
+ if (proto != null) {
+ var interceptorClass = JS('', '#[#]', map, tag);
+ var record = makeDefaultDispatchRecord(tag, interceptorClass, proto);
+ if (record != null) {
+ setDispatchProperty(proto, record);
+ // Ensure the modified prototype is still fast by assigning it to
+ // the prototype property of a function object.
+ JS('', '#.prototype = #', fun, proto);
+ }
+ }
+ }
+ }
+
+ // [interceptorsByTag] maps 'plain' dispatch tags. Add all the derived
+ // dispatch tags to simplify lookup of derived tags.
+ for (int i = 0; i < tags.length; i++) {
+ var tag = JS('String', '#[#]', tags, i);
+ if (JS('bool', '/^[A-Za-z_]/.test(#)', tag)) {
+ var interceptorClass = propertyGet(map, tag);
+ propertySet(map, INSTANCE_CACHED_MARK + tag, interceptorClass);
+ propertySet(map, UNCACHED_MARK + tag, interceptorClass);
+ propertySet(map, LEAF_MARK + tag, interceptorClass);
+ propertySet(map, INTERIOR_MARK + tag, interceptorClass);
+ propertySet(map, DISCRIMINATED_MARK + tag, interceptorClass);
+ }
+ }
+}
+
+/// Initializes [getTagFunction] and [alternateTagFunction].
+///
+/// These functions are 'hook functions', collectively 'hooks'. They
+/// initialized by applying a series of hooks transformers. Built-in hooks
+/// transformers deal with various known browser behaviours.
+///
+/// Each hook tranformer takes a 'hooks' input which is a JavaScript object
+/// containing the hook functions, and returns the same or a new object with
+/// replacements. The replacements can wrap the originals to provide alternate
+/// or modified behaviour.
+///
+/// { getTag: function(obj) {...},
+/// getUnknownTag: function(obj, tag) {...},
+/// prototypeForTag: function(tag) {...},
+/// discriminator: function(tag) {...},
+/// }
+///
+/// * getTag(obj) returns the dispatch tag, or `null`.
+/// * getUnknownTag(obj, tag) returns a tag when [getTag] fails.
+/// * prototypeForTag(tag) returns the prototype of the constructor for tag,
+/// or `null` if not available or prepatching is undesirable.
+/// * discriminator(tag) returns a function TBD.
+///
+/// The web site can adapt a dart2js application by loading code ahead of the
+/// dart2js application that defines hook transformers to be after the built in
+/// ones. Code defining a transformer HT should use the following pattern to
+/// ensure multiple transformers can be composed:
+///
+/// (dartNativeDispatchHooksTransformer =
+/// window.dartNativeDispatchHooksTransformer || []).push(HT);
+///
+///
+/// TODO: Implement and describe dispatch tags and their caching methods.
+void initHooks() {
+ // The initial simple hooks:
+ var hooks = JS('', '#()', _baseHooks);
+
+ // Customize for browsers where `object.constructor.name` fails:
+ var _fallbackConstructorHooksTransformer = JS('', '#(#)',
+ _fallbackConstructorHooksTransformerGenerator, _constructorNameFallback);
+ hooks = applyHooksTransformer(_fallbackConstructorHooksTransformer, hooks);
+
+ // Customize for browsers:
+ hooks = applyHooksTransformer(_firefoxHooksTransformer, hooks);
+ hooks = applyHooksTransformer(_ieHooksTransformer, hooks);
+ hooks = applyHooksTransformer(_operaHooksTransformer, hooks);
+ hooks = applyHooksTransformer(_safariHooksTransformer, hooks);
+
+ hooks = applyHooksTransformer(_fixDocumentHooksTransformer, hooks);
+
+ // TODO(sra): Update ShadowDOM polyfil to use
+ // [dartNativeDispatchHooksTransformer] and remove this hook.
+ hooks = applyHooksTransformer(
+ _dartExperimentalFixupGetTagHooksTransformer, hooks);
+
+ // Apply global hooks.
+ //
+ // If defined, dartNativeDispatchHookdTransformer should be a single function
+ // of a JavaScript Array of functions.
+
+ if (JS('bool', 'typeof dartNativeDispatchHooksTransformer != "undefined"')) {
+ var transformers = JS('', 'dartNativeDispatchHooksTransformer');
+ if (JS('bool', 'typeof # == "function"', transformers)) {
+ transformers = [transformers];
+ }
+ if (JS('bool', '#.constructor == Array', transformers)) {
+ for (int i = 0; i < JS('int', '#.length', transformers); i++) {
+ var transformer = JS('', '#[#]', transformers, i);
+ if (JS('bool', 'typeof # == "function"', transformer)) {
+ hooks = applyHooksTransformer(transformer, hooks);
+ }
+ }
+ }
+ }
+
+ var getTag = JS('', '#.getTag', hooks);
+ var getUnknownTag = JS('', '#.getUnknownTag', hooks);
+ var prototypeForTag = JS('', '#.prototypeForTag', hooks);
+
+ getTagFunction = (o) => JS('String|Null', '#(#)', getTag, o);
+ alternateTagFunction =
+ (o, String tag) => JS('String|Null', '#(#, #)', getUnknownTag, o, tag);
+ prototypeForTagFunction =
+ (String tag) => JS('', '#(#)', prototypeForTag, tag);
+}
+
+applyHooksTransformer(transformer, hooks) {
+ var newHooks = JS('=Object|Null', '#(#)', transformer, hooks);
+ return JS('', '# || #', newHooks, hooks);
+}
+
+// JavaScript code fragments.
+//
+// This is a temporary place for the JavaScript code.
+//
+// TODO(sra): These code fragments are not minified. They could be generated by
+// the code emitter, or JS_CONST could be improved to parse entire functions and
+// take care of the minification.
+
+const _baseHooks = const JS_CONST(r'''
+function() {
+ var toStringFunction = Object.prototype.toString;
+ function getTag(o) {
+ var s = toStringFunction.call(o);
+ return s.substring(8, s.length - 1);
+ }
+ function getUnknownTag(object, tag) {
+ // This code really belongs in [getUnknownTagGenericBrowser] but having it
+ // here allows [getUnknownTag] to be tested on d8.
+ if (/^HTML[A-Z].*Element$/.test(tag)) {
+ // Check that it is not a simple JavaScript object.
+ var name = toStringFunction.call(object);
+ if (name == "[object Object]") return null;
+ return "HTMLElement";
+ }
+ }
+ function getUnknownTagGenericBrowser(object, tag) {
+ if (self.HTMLElement && object instanceof HTMLElement) return "HTMLElement";
+ return getUnknownTag(object, tag);
+ }
+ function prototypeForTag(tag) {
+ if (typeof window == "undefined") return null;
+ if (typeof window[tag] == "undefined") return null;
+ var constructor = window[tag];
+ if (typeof constructor != "function") return null;
+ return constructor.prototype;
+ }
+ function discriminator(tag) { return null; }
+
+ var isBrowser = typeof navigator == "object";
+
+ return {
+ getTag: getTag,
+ getUnknownTag: isBrowser ? getUnknownTagGenericBrowser : getUnknownTag,
+ prototypeForTag: prototypeForTag,
+ discriminator: discriminator };
+}''');
+
+/// Returns the name of the constructor function for browsers where
+/// `object.constructor.name` is not reliable.
+///
+/// This function is split out of
+/// [_fallbackConstructorHooksTransformerGenerator] as it is called from both
+/// the dispatch hooks and via [constructorNameFallback] from objectToString.
+const _constructorNameFallback = const JS_CONST(r'''
+function getTagFallback(o) {
+ var s = Object.prototype.toString.call(o);
+ return s.substring(8, s.length - 1);
+}''');
+
+const _fallbackConstructorHooksTransformerGenerator = const JS_CONST(r'''
+function(getTagFallback) {
+ return function(hooks) {
+ // If we are not in a browser, assume we are in d8.
+ // TODO(sra): Recognize jsshell.
+ if (typeof navigator != "object") return hooks;
+
+ var ua = navigator.userAgent;
+ // TODO(antonm): remove a reference to DumpRenderTree.
+ if (ua.indexOf("DumpRenderTree") >= 0) return hooks;
+ if (ua.indexOf("Chrome") >= 0) {
+ // Confirm constructor name is usable for dispatch.
+ function confirm(p) {
+ return typeof window == "object" && window[p] && window[p].name == p;
+ }
+ if (confirm("Window") && confirm("HTMLElement")) return hooks;
+ }
+
+ hooks.getTag = getTagFallback;
+ };
+}''');
+
+const _ieHooksTransformer = const JS_CONST(r'''
+function(hooks) {
+ var userAgent = typeof navigator == "object" ? navigator.userAgent : "";
+ if (userAgent.indexOf("Trident/") == -1) return hooks;
+
+ var getTag = hooks.getTag;
+
+ var quickMap = {
+ "BeforeUnloadEvent": "Event",
+ "DataTransfer": "Clipboard",
+ "HTMLDDElement": "HTMLElement",
+ "HTMLDTElement": "HTMLElement",
+ "HTMLPhraseElement": "HTMLElement",
+ "Position": "Geoposition"
+ };
+
+ function getTagIE(o) {
+ var tag = getTag(o);
+ var newTag = quickMap[tag];
+ if (newTag) return newTag;
+ // Patches for types which report themselves as Objects.
+ if (tag == "Object") {
+ if (window.DataView && (o instanceof window.DataView)) return "DataView";
+ }
+ return tag;
+ }
+
+ function prototypeForTagIE(tag) {
+ var constructor = window[tag];
+ if (constructor == null) return null;
+ return constructor.prototype;
+ }
+
+ hooks.getTag = getTagIE;
+ hooks.prototypeForTag = prototypeForTagIE;
+}''');
+
+const _fixDocumentHooksTransformer = const JS_CONST(r'''
+function(hooks) {
+ var getTag = hooks.getTag;
+ var prototypeForTag = hooks.prototypeForTag;
+ function getTagFixed(o) {
+ var tag = getTag(o);
+ if (tag == "Document") {
+ // Some browsers and the polymer polyfill call both HTML and XML documents
+ // "Document", so we check for the xmlVersion property, which is the empty
+ // string on HTML documents. Since both dart:html classes Document and
+ // HtmlDocument share the same type, we must patch the instances and not
+ // the prototype.
+ if (!!o.xmlVersion) return "!Document";
+ return "!HTMLDocument";
+ }
+ return tag;
+ }
+
+ function prototypeForTagFixed(tag) {
+ if (tag == "Document") return null; // Do not pre-patch Document.
+ return prototypeForTag(tag);
+ }
+
+ hooks.getTag = getTagFixed;
+ hooks.prototypeForTag = prototypeForTagFixed;
+}''');
+
+const _firefoxHooksTransformer = const JS_CONST(r'''
+function(hooks) {
+ var userAgent = typeof navigator == "object" ? navigator.userAgent : "";
+ if (userAgent.indexOf("Firefox") == -1) return hooks;
+
+ var getTag = hooks.getTag;
+
+ var quickMap = {
+ "BeforeUnloadEvent": "Event",
+ "DataTransfer": "Clipboard",
+ "GeoGeolocation": "Geolocation",
+ "Location": "!Location", // Fixes issue 18151
+ "WorkerMessageEvent": "MessageEvent",
+ "XMLDocument": "!Document"};
+
+ function getTagFirefox(o) {
+ var tag = getTag(o);
+ return quickMap[tag] || tag;
+ }
+
+ hooks.getTag = getTagFirefox;
+}''');
+
+const _operaHooksTransformer = const JS_CONST(r'''
+function(hooks) { return hooks; }
+''');
+
+const _safariHooksTransformer = const JS_CONST(r'''
+function(hooks) { return hooks; }
+''');
+
+const _dartExperimentalFixupGetTagHooksTransformer = const JS_CONST(r'''
+function(hooks) {
+ if (typeof dartExperimentalFixupGetTag != "function") return hooks;
+ hooks.getTag = dartExperimentalFixupGetTag(hooks.getTag);
+}''');
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/native_typed_data.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/native_typed_data.dart
new file mode 100644
index 0000000..0a91641
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/native_typed_data.dart
@@ -0,0 +1,1821 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Specialized integers and floating point numbers,
+/// with SIMD support and efficient lists.
+library dart.typed_data.implementation;
+
+import 'dart:collection' show ListMixin;
+import 'dart:_internal' show FixedLengthListMixin hide Symbol;
+import 'dart:_interceptors' show JSIndexable, JSUInt32, JSUInt31;
+import 'dart:_js_helper'
+ show
+ Creates,
+ JavaScriptIndexingBehavior,
+ JSName,
+ Native,
+ Returns,
+ diagnoseIndexError,
+ diagnoseRangeError;
+import 'dart:_foreign_helper' show JS;
+import 'dart:math' as Math;
+
+import 'dart:typed_data';
+
+@Native('ArrayBuffer')
+class NativeByteBuffer implements ByteBuffer {
+ @JSName('byteLength')
+ final int lengthInBytes;
+
+ Type get runtimeType => ByteBuffer;
+
+ Uint8List asUint8List([int offsetInBytes = 0, int length]) {
+ return new NativeUint8List.view(this, offsetInBytes, length);
+ }
+
+ Int8List asInt8List([int offsetInBytes = 0, int length]) {
+ return new NativeInt8List.view(this, offsetInBytes, length);
+ }
+
+ Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]) {
+ return new NativeUint8ClampedList.view(this, offsetInBytes, length);
+ }
+
+ Uint16List asUint16List([int offsetInBytes = 0, int length]) {
+ return new NativeUint16List.view(this, offsetInBytes, length);
+ }
+
+ Int16List asInt16List([int offsetInBytes = 0, int length]) {
+ return new NativeInt16List.view(this, offsetInBytes, length);
+ }
+
+ Uint32List asUint32List([int offsetInBytes = 0, int length]) {
+ return new NativeUint32List.view(this, offsetInBytes, length);
+ }
+
+ Int32List asInt32List([int offsetInBytes = 0, int length]) {
+ return new NativeInt32List.view(this, offsetInBytes, length);
+ }
+
+ Uint64List asUint64List([int offsetInBytes = 0, int length]) {
+ throw new UnsupportedError('Uint64List not supported by dart2js.');
+ }
+
+ Int64List asInt64List([int offsetInBytes = 0, int length]) {
+ throw new UnsupportedError('Int64List not supported by dart2js.');
+ }
+
+ Int32x4List asInt32x4List([int offsetInBytes = 0, int length]) {
+ NativeInt32List storage =
+ this.asInt32List(offsetInBytes, length != null ? length * 4 : null);
+ return new NativeInt32x4List._externalStorage(storage);
+ }
+
+ Float32List asFloat32List([int offsetInBytes = 0, int length]) {
+ return new NativeFloat32List.view(this, offsetInBytes, length);
+ }
+
+ Float64List asFloat64List([int offsetInBytes = 0, int length]) {
+ return new NativeFloat64List.view(this, offsetInBytes, length);
+ }
+
+ Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]) {
+ NativeFloat32List storage =
+ this.asFloat32List(offsetInBytes, length != null ? length * 4 : null);
+ return new NativeFloat32x4List._externalStorage(storage);
+ }
+
+ Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]) {
+ NativeFloat64List storage =
+ this.asFloat64List(offsetInBytes, length != null ? length * 2 : null);
+ return new NativeFloat64x2List._externalStorage(storage);
+ }
+
+ ByteData asByteData([int offsetInBytes = 0, int length]) {
+ return new NativeByteData.view(this, offsetInBytes, length);
+ }
+}
+
+/// A fixed-length list of Float32x4 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
+class NativeFloat32x4List extends Object
+ with ListMixin<Float32x4>, FixedLengthListMixin<Float32x4>
+ implements Float32x4List {
+ final NativeFloat32List _storage;
+
+ /// Creates a [Float32x4List] of the specified length (in elements),
+ /// all of whose elements are initially zero.
+ NativeFloat32x4List(int length)
+ : _storage = new NativeFloat32List(length * 4);
+
+ NativeFloat32x4List._externalStorage(this._storage);
+
+ NativeFloat32x4List._slowFromList(List<Float32x4> list)
+ : _storage = new NativeFloat32List(list.length * 4) {
+ for (int i = 0; i < list.length; i++) {
+ var e = list[i];
+ _storage[(i * 4) + 0] = e.x;
+ _storage[(i * 4) + 1] = e.y;
+ _storage[(i * 4) + 2] = e.z;
+ _storage[(i * 4) + 3] = e.w;
+ }
+ }
+
+ Type get runtimeType => Float32x4List;
+
+ /// Creates a [Float32x4List] with the same size as the [elements] list
+ /// and copies over the elements.
+ factory NativeFloat32x4List.fromList(List<Float32x4> list) {
+ if (list is NativeFloat32x4List) {
+ return new NativeFloat32x4List._externalStorage(
+ new NativeFloat32List.fromList(list._storage));
+ } else {
+ return new NativeFloat32x4List._slowFromList(list);
+ }
+ }
+
+ ByteBuffer get buffer => _storage.buffer;
+
+ int get lengthInBytes => _storage.lengthInBytes;
+
+ int get offsetInBytes => _storage.offsetInBytes;
+
+ int get elementSizeInBytes => Float32x4List.bytesPerElement;
+
+ int get length => _storage.length ~/ 4;
+
+ Float32x4 operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ double _x = _storage[(index * 4) + 0];
+ double _y = _storage[(index * 4) + 1];
+ double _z = _storage[(index * 4) + 2];
+ double _w = _storage[(index * 4) + 3];
+ return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ void operator []=(int index, Float32x4 value) {
+ _checkValidIndex(index, this, this.length);
+ _storage[(index * 4) + 0] = value.x;
+ _storage[(index * 4) + 1] = value.y;
+ _storage[(index * 4) + 2] = value.z;
+ _storage[(index * 4) + 3] = value.w;
+ }
+
+ Float32x4List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ return new NativeFloat32x4List._externalStorage(
+ _storage.sublist(start * 4, end * 4));
+ }
+}
+
+/// A fixed-length list of Int32x4 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
+class NativeInt32x4List extends Object
+ with ListMixin<Int32x4>, FixedLengthListMixin<Int32x4>
+ implements Int32x4List {
+ final Int32List _storage;
+
+ /// Creates a [Int32x4List] of the specified length (in elements),
+ /// all of whose elements are initially zero.
+ NativeInt32x4List(int length) : _storage = new NativeInt32List(length * 4);
+
+ NativeInt32x4List._externalStorage(Int32List storage) : _storage = storage;
+
+ NativeInt32x4List._slowFromList(List<Int32x4> list)
+ : _storage = new NativeInt32List(list.length * 4) {
+ for (int i = 0; i < list.length; i++) {
+ var e = list[i];
+ _storage[(i * 4) + 0] = e.x;
+ _storage[(i * 4) + 1] = e.y;
+ _storage[(i * 4) + 2] = e.z;
+ _storage[(i * 4) + 3] = e.w;
+ }
+ }
+
+ Type get runtimeType => Int32x4List;
+
+ /// Creates a [Int32x4List] with the same size as the [elements] list
+ /// and copies over the elements.
+ factory NativeInt32x4List.fromList(List<Int32x4> list) {
+ if (list is NativeInt32x4List) {
+ return new NativeInt32x4List._externalStorage(
+ new NativeInt32List.fromList(list._storage));
+ } else {
+ return new NativeInt32x4List._slowFromList(list);
+ }
+ }
+
+ ByteBuffer get buffer => _storage.buffer;
+
+ int get lengthInBytes => _storage.lengthInBytes;
+
+ int get offsetInBytes => _storage.offsetInBytes;
+
+ int get elementSizeInBytes => Int32x4List.bytesPerElement;
+
+ int get length => _storage.length ~/ 4;
+
+ Int32x4 operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ int _x = _storage[(index * 4) + 0];
+ int _y = _storage[(index * 4) + 1];
+ int _z = _storage[(index * 4) + 2];
+ int _w = _storage[(index * 4) + 3];
+ return new NativeInt32x4._truncated(_x, _y, _z, _w);
+ }
+
+ void operator []=(int index, Int32x4 value) {
+ _checkValidIndex(index, this, this.length);
+ _storage[(index * 4) + 0] = value.x;
+ _storage[(index * 4) + 1] = value.y;
+ _storage[(index * 4) + 2] = value.z;
+ _storage[(index * 4) + 3] = value.w;
+ }
+
+ Int32x4List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ return new NativeInt32x4List._externalStorage(
+ _storage.sublist(start * 4, end * 4));
+ }
+}
+
+/// A fixed-length list of Float64x2 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
+class NativeFloat64x2List extends Object
+ with ListMixin<Float64x2>, FixedLengthListMixin<Float64x2>
+ implements Float64x2List {
+ final NativeFloat64List _storage;
+
+ /// Creates a [Float64x2List] of the specified length (in elements),
+ /// all of whose elements are initially zero.
+ NativeFloat64x2List(int length)
+ : _storage = new NativeFloat64List(length * 2);
+
+ NativeFloat64x2List._externalStorage(this._storage);
+
+ NativeFloat64x2List._slowFromList(List<Float64x2> list)
+ : _storage = new NativeFloat64List(list.length * 2) {
+ for (int i = 0; i < list.length; i++) {
+ var e = list[i];
+ _storage[(i * 2) + 0] = e.x;
+ _storage[(i * 2) + 1] = e.y;
+ }
+ }
+
+ /// Creates a [Float64x2List] with the same size as the [elements] list
+ /// and copies over the elements.
+ factory NativeFloat64x2List.fromList(List<Float64x2> list) {
+ if (list is NativeFloat64x2List) {
+ return new NativeFloat64x2List._externalStorage(
+ new NativeFloat64List.fromList(list._storage));
+ } else {
+ return new NativeFloat64x2List._slowFromList(list);
+ }
+ }
+
+ Type get runtimeType => Float64x2List;
+
+ ByteBuffer get buffer => _storage.buffer;
+
+ int get lengthInBytes => _storage.lengthInBytes;
+
+ int get offsetInBytes => _storage.offsetInBytes;
+
+ int get elementSizeInBytes => Float64x2List.bytesPerElement;
+
+ int get length => _storage.length ~/ 2;
+
+ Float64x2 operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ double _x = _storage[(index * 2) + 0];
+ double _y = _storage[(index * 2) + 1];
+ return new Float64x2(_x, _y);
+ }
+
+ void operator []=(int index, Float64x2 value) {
+ _checkValidIndex(index, this, this.length);
+ _storage[(index * 2) + 0] = value.x;
+ _storage[(index * 2) + 1] = value.y;
+ }
+
+ Float64x2List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ return new NativeFloat64x2List._externalStorage(
+ _storage.sublist(start * 2, end * 2));
+ }
+}
+
+@Native('ArrayBufferView')
+class NativeTypedData implements TypedData {
+ /// Returns the byte buffer associated with this object.
+ @Creates('NativeByteBuffer')
+ // May be Null for IE's CanvasPixelArray.
+ @Returns('NativeByteBuffer|Null')
+ final ByteBuffer buffer;
+
+ /// Returns the length of this view, in bytes.
+ @JSName('byteLength')
+ final int lengthInBytes;
+
+ /// Returns the offset in bytes into the underlying byte buffer of this view.
+ @JSName('byteOffset')
+ final int offsetInBytes;
+
+ /// Returns the number of bytes in the representation of each element in this
+ /// list.
+ @JSName('BYTES_PER_ELEMENT')
+ final int elementSizeInBytes;
+
+ void _invalidPosition(int position, int length, String name) {
+ if (position is! int) {
+ throw new ArgumentError.value(position, name, 'Invalid list position');
+ } else {
+ throw new RangeError.range(position, 0, length, name);
+ }
+ }
+
+ void _checkPosition(int position, int length, String name) {
+ if (JS('bool', '(# >>> 0) !== #', position, position) ||
+ JS('int', '#', position) > length) {
+ // 'int' guaranteed by above test.
+ _invalidPosition(position, length, name);
+ }
+ }
+}
+
+// Validates the unnamed constructor length argument. Checking is necessary
+// because passing unvalidated values to the native constructors can cause
+// conversions or create views.
+int _checkLength(length) {
+ return length is int
+ ? length
+ : throw new ArgumentError('Invalid length $length');
+}
+
+// Validates `.view` constructor arguments. Checking is necessary because
+// passing unvalidated values to the native constructors can cause conversions
+// (e.g. String arguments) or create typed data objects that are not actually
+// views of the input.
+void _checkViewArguments(buffer, offsetInBytes, length) {
+ if (buffer is! NativeByteBuffer) {
+ throw new ArgumentError('Invalid view buffer');
+ }
+ if (offsetInBytes is! int) {
+ throw new ArgumentError('Invalid view offsetInBytes $offsetInBytes');
+ }
+ if (length != null && length is! int) {
+ throw new ArgumentError('Invalid view length $length');
+ }
+}
+
+// Ensures that [list] is a JavaScript Array or a typed array. If necessary,
+// returns a copy of the list.
+List _ensureNativeList(List list) {
+ if (list is JSIndexable) return list;
+ List result = new List(list.length);
+ for (int i = 0; i < list.length; i++) {
+ result[i] = list[i];
+ }
+ return result;
+}
+
+@Native('DataView')
+class NativeByteData extends NativeTypedData implements ByteData {
+ /// Creates a [ByteData] of the specified length (in elements), all of
+ /// whose elements are initially zero.
+ factory NativeByteData(int length) => _create1(_checkLength(length));
+
+ /// Creates an [ByteData] _view_ of the specified region in the specified
+ /// byte buffer. Changes in the [ByteData] will be visible in the byte
+ /// buffer and vice versa. If the [offsetInBytes] index of the region is not
+ /// specified, it defaults to zero (the first byte in the byte buffer).
+ /// If the length is not specified, it defaults to null, which indicates
+ /// that the view extends to the end of the byte buffer.
+ ///
+ /// Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ /// if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ /// the length of [buffer].
+ factory NativeByteData.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => ByteData;
+
+ int get elementSizeInBytes => 1;
+
+ /// Returns the floating point number represented by the four bytes at
+ /// the specified [byteOffset] in this object, in IEEE 754
+ /// single-precision binary floating-point format (binary32).
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 4` is greater than the length of this object.
+ double getFloat32(int byteOffset, [Endian endian = Endian.big]) =>
+ _getFloat32(byteOffset, Endian.little == endian);
+
+ @JSName('getFloat32')
+ @Returns('num')
+ num _getFloat32(int byteOffset, [bool littleEndian]) native;
+
+ /// Returns the floating point number represented by the eight bytes at
+ /// the specified [byteOffset] in this object, in IEEE 754
+ /// double-precision binary floating-point format (binary64).
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 8` is greater than the length of this object.
+ double getFloat64(int byteOffset, [Endian endian = Endian.big]) =>
+ _getFloat64(byteOffset, Endian.little == endian);
+
+ @JSName('getFloat64')
+ @Returns('num')
+ num _getFloat64(int byteOffset, [bool littleEndian]) native;
+
+ /// Returns the (possibly negative) integer represented by the two bytes at
+ /// the specified [byteOffset] in this object, in two's complement binary
+ /// form.
+ /// The return value will be between 2<sup>15</sup> and 2<sup>15</sup> - 1,
+ /// inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 2` is greater than the length of this object.
+ int getInt16(int byteOffset, [Endian endian = Endian.big]) =>
+ _getInt16(byteOffset, Endian.little == endian);
+
+ @JSName('getInt16')
+ @Returns('int')
+ int _getInt16(int byteOffset, [bool littleEndian]) native;
+
+ /// Returns the (possibly negative) integer represented by the four bytes at
+ /// the specified [byteOffset] in this object, in two's complement binary
+ /// form.
+ /// The return value will be between 2<sup>31</sup> and 2<sup>31</sup> - 1,
+ /// inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 4` is greater than the length of this object.
+ int getInt32(int byteOffset, [Endian endian = Endian.big]) =>
+ _getInt32(byteOffset, Endian.little == endian);
+
+ @JSName('getInt32')
+ @Returns('int')
+ int _getInt32(int byteOffset, [bool littleEndian]) native;
+
+ /// Returns the (possibly negative) integer represented by the eight bytes at
+ /// the specified [byteOffset] in this object, in two's complement binary
+ /// form.
+ /// The return value will be between 2<sup>63</sup> and 2<sup>63</sup> - 1,
+ /// inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 8` is greater than the length of this object.
+ int getInt64(int byteOffset, [Endian endian = Endian.big]) {
+ throw new UnsupportedError('Int64 accessor not supported by dart2js.');
+ }
+
+ /// Returns the (possibly negative) integer represented by the byte at the
+ /// specified [byteOffset] in this object, in two's complement binary
+ /// representation. The return value will be between -128 and 127, inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// greater than or equal to the length of this object.
+ int getInt8(int byteOffset) native;
+
+ /// Returns the positive integer represented by the two bytes starting
+ /// at the specified [byteOffset] in this object, in unsigned binary
+ /// form.
+ /// The return value will be between 0 and 2<sup>16</sup> - 1, inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 2` is greater than the length of this object.
+ int getUint16(int byteOffset, [Endian endian = Endian.big]) =>
+ _getUint16(byteOffset, Endian.little == endian);
+
+ @JSName('getUint16')
+ @Returns('JSUInt31')
+ int _getUint16(int byteOffset, [bool littleEndian]) native;
+
+ /// Returns the positive integer represented by the four bytes starting
+ /// at the specified [byteOffset] in this object, in unsigned binary
+ /// form.
+ /// The return value will be between 0 and 2<sup>32</sup> - 1, inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 4` is greater than the length of this object.
+ int getUint32(int byteOffset, [Endian endian = Endian.big]) =>
+ _getUint32(byteOffset, Endian.little == endian);
+
+ @JSName('getUint32')
+ @Returns('JSUInt32')
+ int _getUint32(int byteOffset, [bool littleEndian]) native;
+
+ /// Returns the positive integer represented by the eight bytes starting
+ /// at the specified [byteOffset] in this object, in unsigned binary
+ /// form.
+ /// The return value will be between 0 and 2<sup>64</sup> - 1, inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 8` is greater than the length of this object.
+ int getUint64(int byteOffset, [Endian endian = Endian.big]) {
+ throw new UnsupportedError('Uint64 accessor not supported by dart2js.');
+ }
+
+ /// Returns the positive integer represented by the byte at the specified
+ /// [byteOffset] in this object, in unsigned binary form. The
+ /// return value will be between 0 and 255, inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// greater than or equal to the length of this object.
+ int getUint8(int byteOffset) native;
+
+ /// Sets the four bytes starting at the specified [byteOffset] in this
+ /// object to the IEEE 754 single-precision binary floating-point
+ /// (binary32) representation of the specified [value].
+ ///
+ /// **Note that this method can lose precision.** The input [value] is
+ /// a 64-bit floating point value, which will be converted to 32-bit
+ /// floating point value by IEEE 754 rounding rules before it is stored.
+ /// If [value] cannot be represented exactly as a binary32, it will be
+ /// converted to the nearest binary32 value. If two binary32 values are
+ /// equally close, the one whose least significant bit is zero will be used.
+ /// Note that finite (but large) values can be converted to infinity, and
+ /// small non-zero values can be converted to zero.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 4` is greater than the length of this object.
+ void setFloat32(int byteOffset, num value, [Endian endian = Endian.big]) =>
+ _setFloat32(byteOffset, value, Endian.little == endian);
+
+ @JSName('setFloat32')
+ void _setFloat32(int byteOffset, num value, [bool littleEndian]) native;
+
+ /// Sets the eight bytes starting at the specified [byteOffset] in this
+ /// object to the IEEE 754 double-precision binary floating-point
+ /// (binary64) representation of the specified [value].
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 8` is greater than the length of this object.
+ void setFloat64(int byteOffset, num value, [Endian endian = Endian.big]) =>
+ _setFloat64(byteOffset, value, Endian.little == endian);
+
+ @JSName('setFloat64')
+ void _setFloat64(int byteOffset, num value, [bool littleEndian]) native;
+
+ /// Sets the two bytes starting at the specified [byteOffset] in this
+ /// object to the two's complement binary representation of the specified
+ /// [value], which must fit in two bytes. In other words, [value] must lie
+ /// between 2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 2` is greater than the length of this object.
+ void setInt16(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _setInt16(byteOffset, value, Endian.little == endian);
+
+ @JSName('setInt16')
+ void _setInt16(int byteOffset, int value, [bool littleEndian]) native;
+
+ /// Sets the four bytes starting at the specified [byteOffset] in this
+ /// object to the two's complement binary representation of the specified
+ /// [value], which must fit in four bytes. In other words, [value] must lie
+ /// between 2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 4` is greater than the length of this object.
+ void setInt32(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _setInt32(byteOffset, value, Endian.little == endian);
+
+ @JSName('setInt32')
+ void _setInt32(int byteOffset, int value, [bool littleEndian]) native;
+
+ /// Sets the eight bytes starting at the specified [byteOffset] in this
+ /// object to the two's complement binary representation of the specified
+ /// [value], which must fit in eight bytes. In other words, [value] must lie
+ /// between 2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 8` is greater than the length of this object.
+ void setInt64(int byteOffset, int value, [Endian endian = Endian.big]) {
+ throw new UnsupportedError('Int64 accessor not supported by dart2js.');
+ }
+
+ /// Sets the byte at the specified [byteOffset] in this object to the
+ /// two's complement binary representation of the specified [value], which
+ /// must fit in a single byte. In other words, [value] must be between
+ /// -128 and 127, inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// greater than or equal to the length of this object.
+ void setInt8(int byteOffset, int value) native;
+
+ /// Sets the two bytes starting at the specified [byteOffset] in this object
+ /// to the unsigned binary representation of the specified [value],
+ /// which must fit in two bytes. in other words, [value] must be between
+ /// 0 and 2<sup>16</sup> - 1, inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 2` is greater than the length of this object.
+ void setUint16(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _setUint16(byteOffset, value, Endian.little == endian);
+
+ @JSName('setUint16')
+ void _setUint16(int byteOffset, int value, [bool littleEndian]) native;
+
+ /// Sets the four bytes starting at the specified [byteOffset] in this object
+ /// to the unsigned binary representation of the specified [value],
+ /// which must fit in four bytes. in other words, [value] must be between
+ /// 0 and 2<sup>32</sup> - 1, inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 4` is greater than the length of this object.
+ void setUint32(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _setUint32(byteOffset, value, Endian.little == endian);
+
+ @JSName('setUint32')
+ void _setUint32(int byteOffset, int value, [bool littleEndian]) native;
+
+ /// Sets the eight bytes starting at the specified [byteOffset] in this object
+ /// to the unsigned binary representation of the specified [value],
+ /// which must fit in eight bytes. in other words, [value] must be between
+ /// 0 and 2<sup>64</sup> - 1, inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative, or
+ /// `byteOffset + 8` is greater than the length of this object.
+ void setUint64(int byteOffset, int value, [Endian endian = Endian.big]) {
+ throw new UnsupportedError('Uint64 accessor not supported by dart2js.');
+ }
+
+ /// Sets the byte at the specified [byteOffset] in this object to the
+ /// unsigned binary representation of the specified [value], which must fit
+ /// in a single byte. in other words, [value] must be between 0 and 255,
+ /// inclusive.
+ ///
+ /// Throws [RangeError] if [byteOffset] is negative,
+ /// or greater than or equal to the length of this object.
+ void setUint8(int byteOffset, int value) native;
+
+ static NativeByteData _create1(arg) =>
+ JS('NativeByteData', 'new DataView(new ArrayBuffer(#))', arg);
+
+ static NativeByteData _create2(arg1, arg2) =>
+ JS('NativeByteData', 'new DataView(#, #)', arg1, arg2);
+
+ static NativeByteData _create3(arg1, arg2, arg3) =>
+ JS('NativeByteData', 'new DataView(#, #, #)', arg1, arg2, arg3);
+}
+
+abstract class NativeTypedArray extends NativeTypedData
+ implements JavaScriptIndexingBehavior {
+ int get length => JS('JSUInt32', '#.length', this);
+
+ void _setRangeFast(
+ int start, int end, NativeTypedArray source, int skipCount) {
+ int targetLength = this.length;
+ _checkPosition(start, targetLength, 'start');
+ _checkPosition(end, targetLength, 'end');
+ if (start > end) throw new RangeError.range(start, 0, end);
+ int count = end - start;
+
+ if (skipCount < 0) throw new ArgumentError(skipCount);
+
+ int sourceLength = source.length;
+ if (sourceLength - skipCount < count) {
+ throw new StateError('Not enough elements');
+ }
+
+ if (skipCount != 0 || sourceLength != count) {
+ // Create a view of the exact subrange that is copied from the source.
+ source = JS('', '#.subarray(#, #)', source, skipCount, skipCount + count);
+ }
+ JS('void', '#.set(#, #)', this, source, start);
+ }
+}
+
+abstract class NativeTypedArrayOfDouble extends NativeTypedArray
+ with ListMixin<double>, FixedLengthListMixin<double> {
+ double operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS('num', '#[#]', this, index);
+ }
+
+ void operator []=(int index, double value) {
+ _checkValidIndex(index, this, this.length);
+ JS('void', '#[#] = #', this, index, value);
+ }
+
+ void setRange(int start, int end, Iterable<double> iterable,
+ [int skipCount = 0]) {
+ if (iterable is NativeTypedArrayOfDouble) {
+ _setRangeFast(start, end, iterable, skipCount);
+ return;
+ }
+ super.setRange(start, end, iterable, skipCount);
+ }
+}
+
+abstract class NativeTypedArrayOfInt extends NativeTypedArray
+ with ListMixin<int>, FixedLengthListMixin<int>
+ implements List<int> {
+ // operator[]() is not here since different versions have different return
+ // types
+
+ void operator []=(int index, int value) {
+ _checkValidIndex(index, this, this.length);
+ JS('void', '#[#] = #', this, index, value);
+ }
+
+ void setRange(int start, int end, Iterable<int> iterable,
+ [int skipCount = 0]) {
+ if (iterable is NativeTypedArrayOfInt) {
+ _setRangeFast(start, end, iterable, skipCount);
+ return;
+ }
+ super.setRange(start, end, iterable, skipCount);
+ }
+}
+
+@Native('Float32Array')
+class NativeFloat32List extends NativeTypedArrayOfDouble
+ implements Float32List {
+ factory NativeFloat32List(int length) => _create1(_checkLength(length));
+
+ factory NativeFloat32List.fromList(List<double> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeFloat32List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Float32List;
+
+ Float32List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS('NativeFloat32List', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeFloat32List _create1(arg) =>
+ JS('NativeFloat32List', 'new Float32Array(#)', arg);
+
+ static NativeFloat32List _create2(arg1, arg2) =>
+ JS('NativeFloat32List', 'new Float32Array(#, #)', arg1, arg2);
+
+ static NativeFloat32List _create3(arg1, arg2, arg3) =>
+ JS('NativeFloat32List', 'new Float32Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Float64Array')
+class NativeFloat64List extends NativeTypedArrayOfDouble
+ implements Float64List {
+ factory NativeFloat64List(int length) => _create1(_checkLength(length));
+
+ factory NativeFloat64List.fromList(List<double> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeFloat64List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Float64List;
+
+ Float64List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS('NativeFloat64List', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeFloat64List _create1(arg) =>
+ JS('NativeFloat64List', 'new Float64Array(#)', arg);
+
+ static NativeFloat64List _create2(arg1, arg2) =>
+ JS('NativeFloat64List', 'new Float64Array(#, #)', arg1, arg2);
+
+ static NativeFloat64List _create3(arg1, arg2, arg3) =>
+ JS('NativeFloat64List', 'new Float64Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Int16Array')
+class NativeInt16List extends NativeTypedArrayOfInt implements Int16List {
+ factory NativeInt16List(int length) => _create1(_checkLength(length));
+
+ factory NativeInt16List.fromList(List<int> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeInt16List.view(
+ NativeByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Int16List;
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS('int', '#[#]', this, index);
+ }
+
+ Int16List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS('NativeInt16List', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeInt16List _create1(arg) =>
+ JS('NativeInt16List', 'new Int16Array(#)', arg);
+
+ static NativeInt16List _create2(arg1, arg2) =>
+ JS('NativeInt16List', 'new Int16Array(#, #)', arg1, arg2);
+
+ static NativeInt16List _create3(arg1, arg2, arg3) =>
+ JS('NativeInt16List', 'new Int16Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Int32Array')
+class NativeInt32List extends NativeTypedArrayOfInt implements Int32List {
+ factory NativeInt32List(int length) => _create1(_checkLength(length));
+
+ factory NativeInt32List.fromList(List<int> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeInt32List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Int32List;
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS('int', '#[#]', this, index);
+ }
+
+ Int32List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS('NativeInt32List', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeInt32List _create1(arg) =>
+ JS('NativeInt32List', 'new Int32Array(#)', arg);
+
+ static NativeInt32List _create2(arg1, arg2) =>
+ JS('NativeInt32List', 'new Int32Array(#, #)', arg1, arg2);
+
+ static NativeInt32List _create3(arg1, arg2, arg3) =>
+ JS('NativeInt32List', 'new Int32Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Int8Array')
+class NativeInt8List extends NativeTypedArrayOfInt implements Int8List {
+ factory NativeInt8List(int length) => _create1(_checkLength(length));
+
+ factory NativeInt8List.fromList(List<int> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeInt8List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Int8List;
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS('int', '#[#]', this, index);
+ }
+
+ Int8List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS('NativeInt8List', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeInt8List _create1(arg) =>
+ JS('NativeInt8List', 'new Int8Array(#)', arg);
+
+ static NativeInt8List _create2(arg1, arg2) =>
+ JS('NativeInt8List', 'new Int8Array(#, #)', arg1, arg2);
+
+ static Int8List _create3(arg1, arg2, arg3) =>
+ JS('NativeInt8List', 'new Int8Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Uint16Array')
+class NativeUint16List extends NativeTypedArrayOfInt implements Uint16List {
+ factory NativeUint16List(int length) => _create1(_checkLength(length));
+
+ factory NativeUint16List.fromList(List<int> list) =>
+ _create1(_ensureNativeList(list));
+
+ factory NativeUint16List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Uint16List;
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS('JSUInt31', '#[#]', this, index);
+ }
+
+ Uint16List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS('NativeUint16List', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeUint16List _create1(arg) =>
+ JS('NativeUint16List', 'new Uint16Array(#)', arg);
+
+ static NativeUint16List _create2(arg1, arg2) =>
+ JS('NativeUint16List', 'new Uint16Array(#, #)', arg1, arg2);
+
+ static NativeUint16List _create3(arg1, arg2, arg3) =>
+ JS('NativeUint16List', 'new Uint16Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Uint32Array')
+class NativeUint32List extends NativeTypedArrayOfInt implements Uint32List {
+ factory NativeUint32List(int length) => _create1(_checkLength(length));
+
+ factory NativeUint32List.fromList(List<int> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeUint32List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Uint32List;
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS('JSUInt32', '#[#]', this, index);
+ }
+
+ Uint32List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS('NativeUint32List', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeUint32List _create1(arg) =>
+ JS('NativeUint32List', 'new Uint32Array(#)', arg);
+
+ static NativeUint32List _create2(arg1, arg2) =>
+ JS('NativeUint32List', 'new Uint32Array(#, #)', arg1, arg2);
+
+ static NativeUint32List _create3(arg1, arg2, arg3) =>
+ JS('NativeUint32List', 'new Uint32Array(#, #, #)', arg1, arg2, arg3);
+}
+
+@Native('Uint8ClampedArray,CanvasPixelArray')
+class NativeUint8ClampedList extends NativeTypedArrayOfInt
+ implements Uint8ClampedList {
+ factory NativeUint8ClampedList(int length) => _create1(_checkLength(length));
+
+ factory NativeUint8ClampedList.fromList(List<int> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeUint8ClampedList.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Uint8ClampedList;
+
+ int get length => JS('JSUInt32', '#.length', this);
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS('JSUInt31', '#[#]', this, index);
+ }
+
+ Uint8ClampedList sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source =
+ JS('NativeUint8ClampedList', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeUint8ClampedList _create1(arg) =>
+ JS('NativeUint8ClampedList', 'new Uint8ClampedArray(#)', arg);
+
+ static NativeUint8ClampedList _create2(arg1, arg2) =>
+ JS('NativeUint8ClampedList', 'new Uint8ClampedArray(#, #)', arg1, arg2);
+
+ static NativeUint8ClampedList _create3(arg1, arg2, arg3) => JS(
+ 'NativeUint8ClampedList',
+ 'new Uint8ClampedArray(#, #, #)',
+ arg1,
+ arg2,
+ arg3);
+}
+
+// On some browsers Uint8ClampedArray is a subtype of Uint8Array. Marking
+// Uint8List as !nonleaf ensures that the native dispatch correctly handles
+// the potential for Uint8ClampedArray to 'accidentally' pick up the
+// dispatch record for Uint8List.
+@Native('Uint8Array,!nonleaf')
+class NativeUint8List extends NativeTypedArrayOfInt implements Uint8List {
+ factory NativeUint8List(int length) => _create1(_checkLength(length));
+
+ factory NativeUint8List.fromList(List<int> elements) =>
+ _create1(_ensureNativeList(elements));
+
+ factory NativeUint8List.view(
+ ByteBuffer buffer, int offsetInBytes, int length) {
+ _checkViewArguments(buffer, offsetInBytes, length);
+ return length == null
+ ? _create2(buffer, offsetInBytes)
+ : _create3(buffer, offsetInBytes, length);
+ }
+
+ Type get runtimeType => Uint8List;
+
+ int get length => JS('JSUInt32', '#.length', this);
+
+ int operator [](int index) {
+ _checkValidIndex(index, this, this.length);
+ return JS('JSUInt31', '#[#]', this, index);
+ }
+
+ Uint8List sublist(int start, [int end]) {
+ end = _checkValidRange(start, end, this.length);
+ var source = JS('NativeUint8List', '#.subarray(#, #)', this, start, end);
+ return _create1(source);
+ }
+
+ static NativeUint8List _create1(arg) =>
+ JS('NativeUint8List', 'new Uint8Array(#)', arg);
+
+ static NativeUint8List _create2(arg1, arg2) =>
+ JS('NativeUint8List', 'new Uint8Array(#, #)', arg1, arg2);
+
+ static NativeUint8List _create3(arg1, arg2, arg3) =>
+ JS('NativeUint8List', 'new Uint8Array(#, #, #)', arg1, arg2, arg3);
+}
+
+/// Implementation of Dart Float32x4 immutable value type and operations.
+/// Float32x4 stores 4 32-bit floating point values in "lanes".
+/// The lanes are "x", "y", "z", and "w" respectively.
+class NativeFloat32x4 implements Float32x4 {
+ final double x;
+ final double y;
+ final double z;
+ final double w;
+
+ static final NativeFloat32List _list = new NativeFloat32List(4);
+ static final Uint32List _uint32view = _list.buffer.asUint32List();
+
+ static _truncate(x) {
+ _list[0] = x;
+ return _list[0];
+ }
+
+ NativeFloat32x4(double x, double y, double z, double w)
+ : this.x = _truncate(x),
+ this.y = _truncate(y),
+ this.z = _truncate(z),
+ this.w = _truncate(w) {
+ // We would prefer to check for `double` but in dart2js we can't see the
+ // difference anyway.
+ if (x is! num) throw new ArgumentError(x);
+ if (y is! num) throw new ArgumentError(y);
+ if (z is! num) throw new ArgumentError(z);
+ if (w is! num) throw new ArgumentError(w);
+ }
+
+ NativeFloat32x4.splat(double v) : this(v, v, v, v);
+ NativeFloat32x4.zero() : this._truncated(0.0, 0.0, 0.0, 0.0);
+
+ /// Returns a bit-wise copy of [i] as a Float32x4.
+ factory NativeFloat32x4.fromInt32x4Bits(Int32x4 i) {
+ _uint32view[0] = i.x;
+ _uint32view[1] = i.y;
+ _uint32view[2] = i.z;
+ _uint32view[3] = i.w;
+ return new NativeFloat32x4._truncated(
+ _list[0], _list[1], _list[2], _list[3]);
+ }
+
+ NativeFloat32x4.fromFloat64x2(Float64x2 v)
+ : this._truncated(_truncate(v.x), _truncate(v.y), 0.0, 0.0);
+
+ /// Creates a new NativeFloat32x4.
+ ///
+ /// Does not verify if the given arguments are non-null.
+ NativeFloat32x4._doubles(double x, double y, double z, double w)
+ : this.x = _truncate(x),
+ this.y = _truncate(y),
+ this.z = _truncate(z),
+ this.w = _truncate(w);
+
+ /// Creates a new NativeFloat32x4.
+ ///
+ /// The constructor does not truncate the arguments. They must already be in
+ /// the correct range. It does not verify the type of the given arguments,
+ /// either.
+ NativeFloat32x4._truncated(this.x, this.y, this.z, this.w);
+
+ String toString() {
+ return '[$x, $y, $z, $w]';
+ }
+
+ /// Addition operator.
+ Float32x4 operator +(Float32x4 other) {
+ double _x = x + other.x;
+ double _y = y + other.y;
+ double _z = z + other.z;
+ double _w = w + other.w;
+ return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Negate operator.
+ Float32x4 operator -() {
+ return new NativeFloat32x4._truncated(-x, -y, -z, -w);
+ }
+
+ /// Subtraction operator.
+ Float32x4 operator -(Float32x4 other) {
+ double _x = x - other.x;
+ double _y = y - other.y;
+ double _z = z - other.z;
+ double _w = w - other.w;
+ return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Multiplication operator.
+ Float32x4 operator *(Float32x4 other) {
+ double _x = x * other.x;
+ double _y = y * other.y;
+ double _z = z * other.z;
+ double _w = w * other.w;
+ return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Division operator.
+ Float32x4 operator /(Float32x4 other) {
+ double _x = x / other.x;
+ double _y = y / other.y;
+ double _z = z / other.z;
+ double _w = w / other.w;
+ return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Relational less than.
+ Int32x4 lessThan(Float32x4 other) {
+ bool _cx = x < other.x;
+ bool _cy = y < other.y;
+ bool _cz = z < other.z;
+ bool _cw = w < other.w;
+ return new NativeInt32x4._truncated(
+ _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+ }
+
+ /// Relational less than or equal.
+ Int32x4 lessThanOrEqual(Float32x4 other) {
+ bool _cx = x <= other.x;
+ bool _cy = y <= other.y;
+ bool _cz = z <= other.z;
+ bool _cw = w <= other.w;
+ return new NativeInt32x4._truncated(
+ _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+ }
+
+ /// Relational greater than.
+ Int32x4 greaterThan(Float32x4 other) {
+ bool _cx = x > other.x;
+ bool _cy = y > other.y;
+ bool _cz = z > other.z;
+ bool _cw = w > other.w;
+ return new NativeInt32x4._truncated(
+ _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+ }
+
+ /// Relational greater than or equal.
+ Int32x4 greaterThanOrEqual(Float32x4 other) {
+ bool _cx = x >= other.x;
+ bool _cy = y >= other.y;
+ bool _cz = z >= other.z;
+ bool _cw = w >= other.w;
+ return new NativeInt32x4._truncated(
+ _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+ }
+
+ /// Relational equal.
+ Int32x4 equal(Float32x4 other) {
+ bool _cx = x == other.x;
+ bool _cy = y == other.y;
+ bool _cz = z == other.z;
+ bool _cw = w == other.w;
+ return new NativeInt32x4._truncated(
+ _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+ }
+
+ /// Relational not-equal.
+ Int32x4 notEqual(Float32x4 other) {
+ bool _cx = x != other.x;
+ bool _cy = y != other.y;
+ bool _cz = z != other.z;
+ bool _cw = w != other.w;
+ return new NativeInt32x4._truncated(
+ _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
+ }
+
+ /// Returns a copy of [this] each lane being scaled by [s].
+ Float32x4 scale(double s) {
+ double _x = s * x;
+ double _y = s * y;
+ double _z = s * z;
+ double _w = s * w;
+ return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Returns the absolute value of this [Float32x4].
+ Float32x4 abs() {
+ double _x = x.abs();
+ double _y = y.abs();
+ double _z = z.abs();
+ double _w = w.abs();
+ return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
+ Float32x4 clamp(Float32x4 lowerLimit, Float32x4 upperLimit) {
+ double _lx = lowerLimit.x;
+ double _ly = lowerLimit.y;
+ double _lz = lowerLimit.z;
+ double _lw = lowerLimit.w;
+ double _ux = upperLimit.x;
+ double _uy = upperLimit.y;
+ double _uz = upperLimit.z;
+ double _uw = upperLimit.w;
+ double _x = x;
+ double _y = y;
+ double _z = z;
+ double _w = w;
+ // MAX(MIN(self, upper), lower).
+ _x = _x > _ux ? _ux : _x;
+ _y = _y > _uy ? _uy : _y;
+ _z = _z > _uz ? _uz : _z;
+ _w = _w > _uw ? _uw : _w;
+ _x = _x < _lx ? _lx : _x;
+ _y = _y < _ly ? _ly : _y;
+ _z = _z < _lz ? _lz : _z;
+ _w = _w < _lw ? _lw : _w;
+ return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Extract the sign bit from each lane return them in the first 4 bits.
+ int get signMask {
+ var view = _uint32view;
+ var mx, my, mz, mw;
+ _list[0] = x;
+ _list[1] = y;
+ _list[2] = z;
+ _list[3] = w;
+ // This is correct because dart2js uses the unsigned right shift.
+ mx = (view[0] & 0x80000000) >> 31;
+ my = (view[1] & 0x80000000) >> 30;
+ mz = (view[2] & 0x80000000) >> 29;
+ mw = (view[3] & 0x80000000) >> 28;
+ return mx | my | mz | mw;
+ }
+
+ /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
+ Float32x4 shuffle(int mask) {
+ if ((mask < 0) || (mask > 255)) {
+ throw new RangeError.range(mask, 0, 255, 'mask');
+ }
+ _list[0] = x;
+ _list[1] = y;
+ _list[2] = z;
+ _list[3] = w;
+
+ double _x = _list[mask & 0x3];
+ double _y = _list[(mask >> 2) & 0x3];
+ double _z = _list[(mask >> 4) & 0x3];
+ double _w = _list[(mask >> 6) & 0x3];
+ return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Shuffle the lane values in [this] and [other]. The returned
+ /// Float32x4 will have XY lanes from [this] and ZW lanes from [other].
+ /// Uses the same [mask] as [shuffle].
+ Float32x4 shuffleMix(Float32x4 other, int mask) {
+ if ((mask < 0) || (mask > 255)) {
+ throw new RangeError.range(mask, 0, 255, 'mask');
+ }
+ _list[0] = x;
+ _list[1] = y;
+ _list[2] = z;
+ _list[3] = w;
+ double _x = _list[mask & 0x3];
+ double _y = _list[(mask >> 2) & 0x3];
+
+ _list[0] = other.x;
+ _list[1] = other.y;
+ _list[2] = other.z;
+ _list[3] = other.w;
+ double _z = _list[(mask >> 4) & 0x3];
+ double _w = _list[(mask >> 6) & 0x3];
+ return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Copy [this] and replace the [x] lane.
+ Float32x4 withX(double newX) {
+ return new NativeFloat32x4._truncated(_truncate(newX), y, z, w);
+ }
+
+ /// Copy [this] and replace the [y] lane.
+ Float32x4 withY(double newY) {
+ return new NativeFloat32x4._truncated(x, _truncate(newY), z, w);
+ }
+
+ /// Copy [this] and replace the [z] lane.
+ Float32x4 withZ(double newZ) {
+ return new NativeFloat32x4._truncated(x, y, _truncate(newZ), w);
+ }
+
+ /// Copy [this] and replace the [w] lane.
+ Float32x4 withW(double newW) {
+ return new NativeFloat32x4._truncated(x, y, z, _truncate(newW));
+ }
+
+ /// Returns the lane-wise minimum value in [this] or [other].
+ Float32x4 min(Float32x4 other) {
+ double _x = x < other.x ? x : other.x;
+ double _y = y < other.y ? y : other.y;
+ double _z = z < other.z ? z : other.z;
+ double _w = w < other.w ? w : other.w;
+ return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Returns the lane-wise maximum value in [this] or [other].
+ Float32x4 max(Float32x4 other) {
+ double _x = x > other.x ? x : other.x;
+ double _y = y > other.y ? y : other.y;
+ double _z = z > other.z ? z : other.z;
+ double _w = w > other.w ? w : other.w;
+ return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Returns the square root of [this].
+ Float32x4 sqrt() {
+ double _x = Math.sqrt(x);
+ double _y = Math.sqrt(y);
+ double _z = Math.sqrt(z);
+ double _w = Math.sqrt(w);
+ return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Returns the reciprocal of [this].
+ Float32x4 reciprocal() {
+ double _x = 1.0 / x;
+ double _y = 1.0 / y;
+ double _z = 1.0 / z;
+ double _w = 1.0 / w;
+ return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+
+ /// Returns the square root of the reciprocal of [this].
+ Float32x4 reciprocalSqrt() {
+ double _x = Math.sqrt(1.0 / x);
+ double _y = Math.sqrt(1.0 / y);
+ double _z = Math.sqrt(1.0 / z);
+ double _w = Math.sqrt(1.0 / w);
+ return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+ }
+}
+
+/// Interface of Dart Int32x4 and operations.
+/// Int32x4 stores 4 32-bit bit-masks in "lanes".
+/// The lanes are "x", "y", "z", and "w" respectively.
+class NativeInt32x4 implements Int32x4 {
+ final int x;
+ final int y;
+ final int z;
+ final int w;
+
+ static final _list = new NativeInt32List(4);
+
+ static _truncate(x) {
+ _list[0] = x;
+ return _list[0];
+ }
+
+ NativeInt32x4(int x, int y, int z, int w)
+ : this.x = _truncate(x),
+ this.y = _truncate(y),
+ this.z = _truncate(z),
+ this.w = _truncate(w) {
+ if (x != this.x && x is! int) throw new ArgumentError(x);
+ if (y != this.y && y is! int) throw new ArgumentError(y);
+ if (z != this.z && z is! int) throw new ArgumentError(z);
+ if (w != this.w && w is! int) throw new ArgumentError(w);
+ }
+
+ NativeInt32x4.bool(bool x, bool y, bool z, bool w)
+ : this.x = x ? -1 : 0,
+ this.y = y ? -1 : 0,
+ this.z = z ? -1 : 0,
+ this.w = w ? -1 : 0;
+
+ /// Returns a bit-wise copy of [f] as a Int32x4.
+ factory NativeInt32x4.fromFloat32x4Bits(Float32x4 f) {
+ NativeFloat32List floatList = NativeFloat32x4._list;
+ floatList[0] = f.x;
+ floatList[1] = f.y;
+ floatList[2] = f.z;
+ floatList[3] = f.w;
+ NativeInt32List view = floatList.buffer.asInt32List();
+ return new NativeInt32x4._truncated(view[0], view[1], view[2], view[3]);
+ }
+
+ NativeInt32x4._truncated(this.x, this.y, this.z, this.w);
+
+ String toString() => '[$x, $y, $z, $w]';
+
+ /// The bit-wise or operator.
+ Int32x4 operator |(Int32x4 other) {
+ // Dart2js uses unsigned results for bit-operations.
+ // We use "JS" to fall back to the signed versions.
+ return new NativeInt32x4._truncated(
+ JS('int', '# | #', x, other.x),
+ JS('int', '# | #', y, other.y),
+ JS('int', '# | #', z, other.z),
+ JS('int', '# | #', w, other.w));
+ }
+
+ /// The bit-wise and operator.
+ Int32x4 operator &(Int32x4 other) {
+ // Dart2js uses unsigned results for bit-operations.
+ // We use "JS" to fall back to the signed versions.
+ return new NativeInt32x4._truncated(
+ JS('int', '# & #', x, other.x),
+ JS('int', '# & #', y, other.y),
+ JS('int', '# & #', z, other.z),
+ JS('int', '# & #', w, other.w));
+ }
+
+ /// The bit-wise xor operator.
+ Int32x4 operator ^(Int32x4 other) {
+ // Dart2js uses unsigned results for bit-operations.
+ // We use "JS" to fall back to the signed versions.
+ return new NativeInt32x4._truncated(
+ JS('int', '# ^ #', x, other.x),
+ JS('int', '# ^ #', y, other.y),
+ JS('int', '# ^ #', z, other.z),
+ JS('int', '# ^ #', w, other.w));
+ }
+
+ Int32x4 operator +(Int32x4 other) {
+ // Avoid going through the typed array by "| 0" the result.
+ return new NativeInt32x4._truncated(
+ JS('int', '(# + #) | 0', x, other.x),
+ JS('int', '(# + #) | 0', y, other.y),
+ JS('int', '(# + #) | 0', z, other.z),
+ JS('int', '(# + #) | 0', w, other.w));
+ }
+
+ Int32x4 operator -(Int32x4 other) {
+ // Avoid going through the typed array by "| 0" the result.
+ return new NativeInt32x4._truncated(
+ JS('int', '(# - #) | 0', x, other.x),
+ JS('int', '(# - #) | 0', y, other.y),
+ JS('int', '(# - #) | 0', z, other.z),
+ JS('int', '(# - #) | 0', w, other.w));
+ }
+
+ Int32x4 operator -() {
+ // Avoid going through the typed array by "| 0" the result.
+ return new NativeInt32x4._truncated(
+ JS('int', '(-#) | 0', x),
+ JS('int', '(-#) | 0', y),
+ JS('int', '(-#) | 0', z),
+ JS('int', '(-#) | 0', w));
+ }
+
+ /// Extract the top bit from each lane return them in the first 4 bits.
+ int get signMask {
+ int mx = (x & 0x80000000) >> 31;
+ int my = (y & 0x80000000) >> 31;
+ int mz = (z & 0x80000000) >> 31;
+ int mw = (w & 0x80000000) >> 31;
+ return mx | my << 1 | mz << 2 | mw << 3;
+ }
+
+ /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
+ Int32x4 shuffle(int mask) {
+ if ((mask < 0) || (mask > 255)) {
+ throw new RangeError.range(mask, 0, 255, 'mask');
+ }
+ _list[0] = x;
+ _list[1] = y;
+ _list[2] = z;
+ _list[3] = w;
+ int _x = _list[mask & 0x3];
+ int _y = _list[(mask >> 2) & 0x3];
+ int _z = _list[(mask >> 4) & 0x3];
+ int _w = _list[(mask >> 6) & 0x3];
+ return new NativeInt32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Shuffle the lane values in [this] and [other]. The returned
+ /// Int32x4 will have XY lanes from [this] and ZW lanes from [other].
+ /// Uses the same [mask] as [shuffle].
+ Int32x4 shuffleMix(Int32x4 other, int mask) {
+ if ((mask < 0) || (mask > 255)) {
+ throw new RangeError.range(mask, 0, 255, 'mask');
+ }
+ _list[0] = x;
+ _list[1] = y;
+ _list[2] = z;
+ _list[3] = w;
+ int _x = _list[mask & 0x3];
+ int _y = _list[(mask >> 2) & 0x3];
+
+ _list[0] = other.x;
+ _list[1] = other.y;
+ _list[2] = other.z;
+ _list[3] = other.w;
+ int _z = _list[(mask >> 4) & 0x3];
+ int _w = _list[(mask >> 6) & 0x3];
+ return new NativeInt32x4._truncated(_x, _y, _z, _w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new x value.
+ Int32x4 withX(int x) {
+ int _x = _truncate(x);
+ return new NativeInt32x4._truncated(_x, y, z, w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new y value.
+ Int32x4 withY(int y) {
+ int _y = _truncate(y);
+ return new NativeInt32x4._truncated(x, _y, z, w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new z value.
+ Int32x4 withZ(int z) {
+ int _z = _truncate(z);
+ return new NativeInt32x4._truncated(x, y, _z, w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new w value.
+ Int32x4 withW(int w) {
+ int _w = _truncate(w);
+ return new NativeInt32x4._truncated(x, y, z, _w);
+ }
+
+ /// Extracted x value. Returns `false` for 0, `true` for any other value.
+ bool get flagX => x != 0;
+
+ /// Extracted y value. Returns `false` for 0, `true` for any other value.
+ bool get flagY => y != 0;
+
+ /// Extracted z value. Returns `false` for 0, `true` for any other value.
+ bool get flagZ => z != 0;
+
+ /// Extracted w value. Returns `false` for 0, `true` for any other value.
+ bool get flagW => w != 0;
+
+ /// Returns a new [Int32x4] copied from [this] with a new x value.
+ Int32x4 withFlagX(bool flagX) {
+ int _x = flagX ? -1 : 0;
+ return new NativeInt32x4._truncated(_x, y, z, w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new y value.
+ Int32x4 withFlagY(bool flagY) {
+ int _y = flagY ? -1 : 0;
+ return new NativeInt32x4._truncated(x, _y, z, w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new z value.
+ Int32x4 withFlagZ(bool flagZ) {
+ int _z = flagZ ? -1 : 0;
+ return new NativeInt32x4._truncated(x, y, _z, w);
+ }
+
+ /// Returns a new [Int32x4] copied from [this] with a new w value.
+ Int32x4 withFlagW(bool flagW) {
+ int _w = flagW ? -1 : 0;
+ return new NativeInt32x4._truncated(x, y, z, _w);
+ }
+
+ /// Merge [trueValue] and [falseValue] based on [this]' bit mask:
+ /// Select bit from [trueValue] when bit in [this] is on.
+ /// Select bit from [falseValue] when bit in [this] is off.
+ Float32x4 select(Float32x4 trueValue, Float32x4 falseValue) {
+ var floatList = NativeFloat32x4._list;
+ var intView = NativeFloat32x4._uint32view;
+
+ floatList[0] = trueValue.x;
+ floatList[1] = trueValue.y;
+ floatList[2] = trueValue.z;
+ floatList[3] = trueValue.w;
+ int stx = intView[0];
+ int sty = intView[1];
+ int stz = intView[2];
+ int stw = intView[3];
+
+ floatList[0] = falseValue.x;
+ floatList[1] = falseValue.y;
+ floatList[2] = falseValue.z;
+ floatList[3] = falseValue.w;
+ int sfx = intView[0];
+ int sfy = intView[1];
+ int sfz = intView[2];
+ int sfw = intView[3];
+ int _x = (x & stx) | (~x & sfx);
+ int _y = (y & sty) | (~y & sfy);
+ int _z = (z & stz) | (~z & sfz);
+ int _w = (w & stw) | (~w & sfw);
+ intView[0] = _x;
+ intView[1] = _y;
+ intView[2] = _z;
+ intView[3] = _w;
+ return new NativeFloat32x4._truncated(
+ floatList[0], floatList[1], floatList[2], floatList[3]);
+ }
+}
+
+class NativeFloat64x2 implements Float64x2 {
+ final double x;
+ final double y;
+
+ static NativeFloat64List _list = new NativeFloat64List(2);
+ static NativeUint32List _uint32View = _list.buffer.asUint32List();
+
+ NativeFloat64x2(this.x, this.y) {
+ if (x is! num) throw new ArgumentError(x);
+ if (y is! num) throw new ArgumentError(y);
+ }
+
+ NativeFloat64x2.splat(double v) : this(v, v);
+
+ NativeFloat64x2.zero() : this.splat(0.0);
+
+ NativeFloat64x2.fromFloat32x4(Float32x4 v) : this(v.x, v.y);
+
+ /// Arguments [x] and [y] must be doubles.
+ NativeFloat64x2._doubles(this.x, this.y);
+
+ String toString() => '[$x, $y]';
+
+ /// Addition operator.
+ Float64x2 operator +(Float64x2 other) {
+ return new NativeFloat64x2._doubles(x + other.x, y + other.y);
+ }
+
+ /// Negate operator.
+ Float64x2 operator -() {
+ return new NativeFloat64x2._doubles(-x, -y);
+ }
+
+ /// Subtraction operator.
+ Float64x2 operator -(Float64x2 other) {
+ return new NativeFloat64x2._doubles(x - other.x, y - other.y);
+ }
+
+ /// Multiplication operator.
+ Float64x2 operator *(Float64x2 other) {
+ return new NativeFloat64x2._doubles(x * other.x, y * other.y);
+ }
+
+ /// Division operator.
+ Float64x2 operator /(Float64x2 other) {
+ return new NativeFloat64x2._doubles(x / other.x, y / other.y);
+ }
+
+ /// Returns a copy of [this] each lane being scaled by [s].
+ Float64x2 scale(double s) {
+ return new NativeFloat64x2._doubles(x * s, y * s);
+ }
+
+ /// Returns the absolute value of this [Float64x2].
+ Float64x2 abs() {
+ return new NativeFloat64x2._doubles(x.abs(), y.abs());
+ }
+
+ /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
+ Float64x2 clamp(Float64x2 lowerLimit, Float64x2 upperLimit) {
+ double _lx = lowerLimit.x;
+ double _ly = lowerLimit.y;
+ double _ux = upperLimit.x;
+ double _uy = upperLimit.y;
+ double _x = x;
+ double _y = y;
+ // MAX(MIN(self, upper), lower).
+ _x = _x > _ux ? _ux : _x;
+ _y = _y > _uy ? _uy : _y;
+ _x = _x < _lx ? _lx : _x;
+ _y = _y < _ly ? _ly : _y;
+ return new NativeFloat64x2._doubles(_x, _y);
+ }
+
+ /// Extract the sign bits from each lane return them in the first 2 bits.
+ int get signMask {
+ var view = _uint32View;
+ _list[0] = x;
+ _list[1] = y;
+ var mx = (view[1] & 0x80000000) >> 31;
+ var my = (view[3] & 0x80000000) >> 31;
+ return mx | my << 1;
+ }
+
+ /// Returns a new [Float64x2] copied from [this] with a new x value.
+ Float64x2 withX(double x) {
+ if (x is! num) throw new ArgumentError(x);
+ return new NativeFloat64x2._doubles(x, y);
+ }
+
+ /// Returns a new [Float64x2] copied from [this] with a new y value.
+ Float64x2 withY(double y) {
+ if (y is! num) throw new ArgumentError(y);
+ return new NativeFloat64x2._doubles(x, y);
+ }
+
+ /// Returns the lane-wise minimum value in [this] or [other].
+ Float64x2 min(Float64x2 other) {
+ return new NativeFloat64x2._doubles(
+ x < other.x ? x : other.x, y < other.y ? y : other.y);
+ }
+
+ /// Returns the lane-wise maximum value in [this] or [other].
+ Float64x2 max(Float64x2 other) {
+ return new NativeFloat64x2._doubles(
+ x > other.x ? x : other.x, y > other.y ? y : other.y);
+ }
+
+ /// Returns the lane-wise square root of [this].
+ Float64x2 sqrt() {
+ return new NativeFloat64x2._doubles(Math.sqrt(x), Math.sqrt(y));
+ }
+}
+
+/// Checks that the value is a Uint32. If not, it's not valid as an array
+/// index or offset. Also ensures that the value is non-negative.
+bool _isInvalidArrayIndex(int index) {
+ return (JS('bool', '(# >>> 0 !== #)', index, index));
+}
+
+/// Checks that [index] is a valid index into [list] which has length [length].
+///
+/// That is, [index] is an integer in the range `0..length - 1`.
+void _checkValidIndex(int index, List list, int length) {
+ if (_isInvalidArrayIndex(index) || JS('int', '#', index) >= length) {
+ throw diagnoseIndexError(list, index);
+ }
+}
+
+/// Checks that [start] and [end] form a range of a list of length [length].
+///
+/// That is: `start` and `end` are integers with `0 <= start <= end <= length`.
+/// If `end` is `null` in which case it is considered to be `length`
+///
+/// Returns the actual value of `end`, which is `length` if `end` is `null`, and
+/// the original value of `end` otherwise.
+int _checkValidRange(int start, int end, int length) {
+ if (_isInvalidArrayIndex(start) || // Ensures start is non-negative int.
+ ((end == null)
+ ? start > length
+ : (_isInvalidArrayIndex(end) || start > end || end > length))) {
+ throw diagnoseRangeError(start, end, length);
+ }
+ if (end == null) return length;
+ return end;
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/README b/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/README
new file mode 100644
index 0000000..4465012
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/README
@@ -0,0 +1,17 @@
+The files in this directory polyfill some of the functionality that browsers
+provide. When running command-line JS evaluators it is frequently necessary to
+execute the preambles before executing the output of dart2js.
+
+=Usage=
+- d8:
+ d8 <sdk>/lib/_internal/js_runtime/lib/preambles/d8.js <output>.js
+
+- jsshell:
+ jsshell -f <sdk>/lib/_internal/js_runtime/lib/preambles/d8.js -f <output>.js
+
+- node.js:
+ The d8 preamble file works for most programs.
+
+ Unfortunately we are not aware of any easy way to provide multiple input files
+ to node. It seems to be necessary to concatenate the d8 preamble and the
+ dart2js output.
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/d8.js b/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/d8.js
new file mode 100644
index 0000000..0174d95
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/d8.js
@@ -0,0 +1,348 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Javascript preamble, that lets the output of dart2js run on V8's d8 shell.
+
+// Node wraps files and provides them with a different `this`. The global
+// `this` can be accessed through `global`.
+
+var self = this;
+if (typeof global != "undefined") self = global; // Node.js.
+
+(function(self) {
+ // Using strict mode to avoid accidentally defining global variables.
+ "use strict"; // Should be first statement of this function.
+
+ // Location (Uri.base)
+ var baseUri = 'org-dartlang-d8-preamble:///mock/uri/base/';
+ if (typeof process != "undefined" &&
+ typeof process.cwd == "function") {
+ // Node.js.
+ baseUri = 'file://' + process.cwd() + '/';
+ }
+ self.location = { href: baseUri };
+
+ // Event loop.
+
+ // Task queue as cyclic list queue.
+ var taskQueue = new Array(8); // Length is power of 2.
+ var head = 0;
+ var tail = 0;
+ var mask = taskQueue.length - 1;
+ function addTask(elem) {
+ taskQueue[head] = elem;
+ head = (head + 1) & mask;
+ if (head == tail) _growTaskQueue();
+ }
+ function removeTask() {
+ if (head == tail) return;
+ var result = taskQueue[tail];
+ taskQueue[tail] = undefined;
+ tail = (tail + 1) & mask;
+ return result;
+ }
+ function _growTaskQueue() {
+ // head == tail.
+ var length = taskQueue.length;
+ var split = head;
+ taskQueue.length = length * 2;
+ if (split * 2 < length) { // split < length / 2
+ for (var i = 0; i < split; i++) {
+ taskQueue[length + i] = taskQueue[i];
+ taskQueue[i] = undefined;
+ }
+ head += length;
+ } else {
+ for (var i = split; i < length; i++) {
+ taskQueue[length + i] = taskQueue[i];
+ taskQueue[i] = undefined;
+ }
+ tail += length;
+ }
+ mask = taskQueue.length - 1;
+ }
+
+ // Mapping from timer id to timer function.
+ // The timer id is written on the function as .$timerId.
+ // That field is cleared when the timer is cancelled, but it is not returned
+ // from the queue until its time comes.
+ var timerIds = {};
+ var timerIdCounter = 1; // Counter used to assign ids.
+
+ // Zero-timer queue as simple array queue using push/shift.
+ var zeroTimerQueue = [];
+
+ function addTimer(f, ms) {
+ var id = timerIdCounter++;
+ f.$timerId = id;
+ timerIds[id] = f;
+ if (ms == 0 && !isNextTimerDue()) {
+ zeroTimerQueue.push(f);
+ } else {
+ addDelayedTimer(f, ms);
+ }
+ return id;
+ }
+
+ function nextZeroTimer() {
+ while (zeroTimerQueue.length > 0) {
+ var action = zeroTimerQueue.shift();
+ if (action.$timerId !== undefined) return action;
+ }
+ }
+
+ function nextEvent() {
+ var action = removeTask();
+ if (action) {
+ return action;
+ }
+ do {
+ action = nextZeroTimer();
+ if (action) break;
+ var nextList = nextDelayedTimerQueue();
+ if (!nextList) {
+ return;
+ }
+ var newTime = nextList.shift();
+ advanceTimeTo(newTime);
+ zeroTimerQueue = nextList;
+ } while (true)
+ var id = action.$timerId;
+ clearTimerId(action, id);
+ return action;
+ }
+
+ // Mocking time.
+ var timeOffset = 0;
+ var now = function() {
+ // Install the mock Date object only once.
+ // Following calls to "now" will just use the new (mocked) Date.now
+ // method directly.
+ installMockDate();
+ now = Date.now;
+ return Date.now();
+ };
+ var originalDate = Date;
+ var originalNow = originalDate.now;
+ function advanceTimeTo(time) {
+ var now = originalNow();
+ if (timeOffset < time - now) {
+ timeOffset = time - now;
+ }
+ }
+ function installMockDate() {
+ var NewDate = function Date(Y, M, D, h, m, s, ms) {
+ if (this instanceof Date) {
+ // Assume a construct call.
+ switch (arguments.length) {
+ case 0: return new originalDate(originalNow() + timeOffset);
+ case 1: return new originalDate(Y);
+ case 2: return new originalDate(Y, M);
+ case 3: return new originalDate(Y, M, D);
+ case 4: return new originalDate(Y, M, D, h);
+ case 5: return new originalDate(Y, M, D, h, m);
+ case 6: return new originalDate(Y, M, D, h, m, s);
+ default: return new originalDate(Y, M, D, h, m, s, ms);
+ }
+ }
+ return new originalDate(originalNow() + timeOffset).toString();
+ };
+ NewDate.UTC = originalDate.UTC;
+ NewDate.parse = originalDate.parse;
+ NewDate.now = function now() { return originalNow() + timeOffset; };
+ NewDate.prototype = originalDate.prototype;
+ originalDate.prototype.constructor = NewDate;
+ Date = NewDate;
+ }
+
+ // Heap priority queue with key index.
+ // Each entry is list of [timeout, callback1 ... callbackn].
+ var timerHeap = [];
+ var timerIndex = {};
+ function addDelayedTimer(f, ms) {
+ var timeout = now() + ms;
+ var timerList = timerIndex[timeout];
+ if (timerList == null) {
+ timerList = [timeout, f];
+ timerIndex[timeout] = timerList;
+ var index = timerHeap.length;
+ timerHeap.length += 1;
+ bubbleUp(index, timeout, timerList);
+ } else {
+ timerList.push(f);
+ }
+ }
+
+ function isNextTimerDue() {
+ if (timerHeap.length == 0) return false;
+ var head = timerHeap[0];
+ return head[0] < originalNow() + timeOffset;
+ }
+
+ function nextDelayedTimerQueue() {
+ if (timerHeap.length == 0) return null;
+ var result = timerHeap[0];
+ var last = timerHeap.pop();
+ if (timerHeap.length > 0) {
+ bubbleDown(0, last[0], last);
+ }
+ return result;
+ }
+
+ function bubbleUp(index, key, value) {
+ while (index != 0) {
+ var parentIndex = (index - 1) >> 1;
+ var parent = timerHeap[parentIndex];
+ var parentKey = parent[0];
+ if (key > parentKey) break;
+ timerHeap[index] = parent;
+ index = parentIndex;
+ }
+ timerHeap[index] = value;
+ }
+
+ function bubbleDown(index, key, value) {
+ while (true) {
+ var leftChildIndex = index * 2 + 1;
+ if (leftChildIndex >= timerHeap.length) break;
+ var minChildIndex = leftChildIndex;
+ var minChild = timerHeap[leftChildIndex];
+ var minChildKey = minChild[0];
+ var rightChildIndex = leftChildIndex + 1;
+ if (rightChildIndex < timerHeap.length) {
+ var rightChild = timerHeap[rightChildIndex];
+ var rightKey = rightChild[0];
+ if (rightKey < minChildKey) {
+ minChildIndex = rightChildIndex;
+ minChild = rightChild;
+ minChildKey = rightKey;
+ }
+ }
+ if (minChildKey > key) break;
+ timerHeap[index] = minChild;
+ index = minChildIndex;
+ }
+ timerHeap[index] = value;
+ }
+
+ function addInterval(f, ms) {
+ var id = timerIdCounter++;
+ function repeat() {
+ // Reactivate with the same id.
+ repeat.$timerId = id;
+ timerIds[id] = repeat;
+ addDelayedTimer(repeat, ms);
+ f();
+ }
+ repeat.$timerId = id;
+ timerIds[id] = repeat;
+ addDelayedTimer(repeat, ms);
+ return id;
+ }
+
+ function cancelTimer(id) {
+ var f = timerIds[id];
+ if (f == null) return;
+ clearTimerId(f, id);
+ }
+
+ function clearTimerId(f, id) {
+ f.$timerId = undefined;
+ delete timerIds[id];
+ }
+
+ function eventLoop(action) {
+ while (action) {
+ try {
+ action();
+ } catch (e) {
+ if (typeof onerror == "function") {
+ onerror(e, null, -1);
+ } else {
+ throw e;
+ }
+ }
+ action = nextEvent();
+ }
+ }
+
+ // Global properties. "self" refers to the global object, so adding a
+ // property to "self" defines a global variable.
+ self.self = self;
+ self.dartMainRunner = function(main, args) {
+ // Initialize.
+ var action = function() { main(args); }
+ eventLoop(action);
+ };
+ self.setTimeout = addTimer;
+ self.clearTimeout = cancelTimer;
+ self.setInterval = addInterval;
+ self.clearInterval = cancelTimer;
+ self.scheduleImmediate = addTask;
+
+ function computeCurrentScript() {
+ try {
+ throw new Error();
+ } catch(e) {
+ var stack = e.stack;
+ // The V8 stack looks like:
+ // at computeCurrentScript (preambles/d8.js:286:13)
+ // at Object.currentScript (preambles/d8.js:308:31)
+ // at init.currentScript (/tmp/foo.js:308:19)
+ // at /tmp/foo.js:320:7
+ // at /tmp/foo.js:331:4
+ // Sometimes the 'init.currentScript' line is in the format without the
+ // function name, so match with or without parentheses.
+
+ // vvvvvvvvvvvv Optional prefix up to '('.
+ var re = /^ *at (?:[^(]*\()?(.*):[0-9]*:[0-9]*\)?$/mg
+ // Optional ')' at end ^^^
+
+ var lastMatch = null;
+ do {
+ var match = re.exec(stack);
+ if (match != null) lastMatch = match;
+ } while (match != null);
+ return lastMatch[1];
+ }
+ }
+
+ // Adding a 'document' is dangerous since it invalidates the 'typeof document'
+ // test to see if we are running in the browser. It means that the runtime
+ // needs to do more precise checks.
+ // Note that we can't run "currentScript" right away, since that would give
+ // us the location of the preamble file. Instead we wait for the first access
+ // which should happen just before invoking main. At this point we are in
+ // the main file and setting the currentScript property is correct.
+ var cachedCurrentScript = null;
+ self.document = { get currentScript() {
+ if (cachedCurrentScript == null) {
+ cachedCurrentScript = {src: computeCurrentScript()};
+ }
+ return cachedCurrentScript;
+ }
+ };
+
+ // Support for deferred loading.
+ self.dartDeferredLibraryLoader = function(uri, successCallback, errorCallback) {
+ try {
+ load(uri);
+ successCallback();
+ } catch (error) {
+ errorCallback(error);
+ }
+ };
+
+ // Mock cryptographically secure random by using plain random.
+ self.crypto = {getRandomValues: function(array) {
+ for (var i = 0; i < array.length; i++) {
+ array[i] = Math.random() * 256;
+ }
+ }};
+
+ // D8 Workers are not sufficiently compatible with browser Workers
+ // so pretend they don't exist.
+ // TODO(30217): Try to use D8's worker.
+ delete self.Worker;
+})(self);
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/jsshell.js b/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/jsshell.js
new file mode 100644
index 0000000..a6b41c4
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/preambles/jsshell.js
@@ -0,0 +1,340 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Javascript preamble, that lets the output of dart2js run on JSShell.
+
+(function(self) {
+ // Using strict mode to avoid accidentally defining global variables.
+ "use strict"; // Should be first statement of this function.
+
+ // Location (Uri.base)
+
+ var workingDirectory = os.getenv("PWD");
+
+ // Global properties. "self" refers to the global object, so adding a
+ // property to "self" defines a global variable.
+ self.self = self;
+
+ self.location = { href: "file://" + workingDirectory + "/" };
+
+ // Event loop.
+
+ // Task queue as cyclic list queue.
+ var taskQueue = new Array(8); // Length is power of 2.
+ var head = 0;
+ var tail = 0;
+ var mask = taskQueue.length - 1;
+ function addTask(elem) {
+ taskQueue[head] = elem;
+ head = (head + 1) & mask;
+ if (head == tail) _growTaskQueue();
+ }
+ function removeTask() {
+ if (head == tail) return;
+ var result = taskQueue[tail];
+ taskQueue[tail] = undefined;
+ tail = (tail + 1) & mask;
+ return result;
+ }
+ function _growTaskQueue() {
+ // head == tail.
+ var length = taskQueue.length;
+ var split = head;
+ taskQueue.length = length * 2;
+ if (split * 2 < length) { // split < length / 2
+ for (var i = 0; i < split; i++) {
+ taskQueue[length + i] = taskQueue[i];
+ taskQueue[i] = undefined;
+ }
+ head += length;
+ } else {
+ for (var i = split; i < length; i++) {
+ taskQueue[length + i] = taskQueue[i];
+ taskQueue[i] = undefined;
+ }
+ tail += length;
+ }
+ mask = taskQueue.length - 1;
+ }
+
+ // Mapping from timer id to timer function.
+ // The timer id is written on the function as .$timerId.
+ // That field is cleared when the timer is cancelled, but it is not returned
+ // from the queue until its time comes.
+ var timerIds = {};
+ var timerIdCounter = 1; // Counter used to assign ids.
+
+ // Zero-timer queue as simple array queue using push/shift.
+ var zeroTimerQueue = [];
+
+ function addTimer(f, ms) {
+ var id = timerIdCounter++;
+ f.$timerId = id;
+ timerIds[id] = f;
+ if (ms == 0 && !isNextTimerDue()) {
+ zeroTimerQueue.push(f);
+ } else {
+ addDelayedTimer(f, ms);
+ }
+ return id;
+ }
+
+ function nextZeroTimer() {
+ while (zeroTimerQueue.length > 0) {
+ var action = zeroTimerQueue.shift();
+ if (action.$timerId !== undefined) return action;
+ }
+ }
+
+ function nextEvent() {
+ var action = removeTask();
+ if (action) {
+ return action;
+ }
+ do {
+ action = nextZeroTimer();
+ if (action) break;
+ var nextList = nextDelayedTimerQueue();
+ if (!nextList) {
+ return;
+ }
+ var newTime = nextList.shift();
+ advanceTimeTo(newTime);
+ zeroTimerQueue = nextList;
+ } while (true)
+ var id = action.$timerId;
+ clearTimerId(action, id);
+ return action;
+ }
+
+ // Mocking time.
+ var timeOffset = 0;
+ var now = function() {
+ // Install the mock Date object only once.
+ // Following calls to "now" will just use the new (mocked) Date.now
+ // method directly.
+ installMockDate();
+ now = Date.now;
+ return Date.now();
+ };
+ var originalDate = Date;
+ var originalNow = originalDate.now;
+ function advanceTimeTo(time) {
+ var now = originalNow();
+ if (timeOffset < time - now) {
+ timeOffset = time - now;
+ }
+ }
+ function installMockDate() {
+ var NewDate = function Date(Y, M, D, h, m, s, ms) {
+ if (this instanceof Date) {
+ // Assume a construct call.
+ switch (arguments.length) {
+ case 0: return new originalDate(originalNow() + timeOffset);
+ case 1: return new originalDate(Y);
+ case 2: return new originalDate(Y, M);
+ case 3: return new originalDate(Y, M, D);
+ case 4: return new originalDate(Y, M, D, h);
+ case 5: return new originalDate(Y, M, D, h, m);
+ case 6: return new originalDate(Y, M, D, h, m, s);
+ default: return new originalDate(Y, M, D, h, m, s, ms);
+ }
+ }
+ return new originalDate(originalNow() + timeOffset).toString();
+ };
+ NewDate.UTC = originalDate.UTC;
+ NewDate.parse = originalDate.parse;
+ NewDate.now = function now() { return originalNow() + timeOffset; };
+ NewDate.prototype = originalDate.prototype;
+ originalDate.prototype.constructor = NewDate;
+ Date = NewDate;
+ }
+
+ // Heap priority queue with key index.
+ // Each entry is list of [timeout, callback1 ... callbackn].
+ var timerHeap = [];
+ var timerIndex = {};
+ function addDelayedTimer(f, ms) {
+ var timeout = now() + ms;
+ var timerList = timerIndex[timeout];
+ if (timerList == null) {
+ timerList = [timeout, f];
+ timerIndex[timeout] = timerList;
+ var index = timerHeap.length;
+ timerHeap.length += 1;
+ bubbleUp(index, timeout, timerList);
+ } else {
+ timerList.push(f);
+ }
+ }
+
+ function isNextTimerDue() {
+ if (timerHeap.length == 0) return false;
+ var head = timerHeap[0];
+ return head[0] < originalNow() + timeOffset;
+ }
+
+ function nextDelayedTimerQueue() {
+ if (timerHeap.length == 0) return null;
+ var result = timerHeap[0];
+ var last = timerHeap.pop();
+ if (timerHeap.length > 0) {
+ bubbleDown(0, last[0], last);
+ }
+ return result;
+ }
+
+ function bubbleUp(index, key, value) {
+ while (index != 0) {
+ var parentIndex = (index - 1) >> 1;
+ var parent = timerHeap[parentIndex];
+ var parentKey = parent[0];
+ if (key > parentKey) break;
+ timerHeap[index] = parent;
+ index = parentIndex;
+ }
+ timerHeap[index] = value;
+ }
+
+ function bubbleDown(index, key, value) {
+ while (true) {
+ var leftChildIndex = index * 2 + 1;
+ if (leftChildIndex >= timerHeap.length) break;
+ var minChildIndex = leftChildIndex;
+ var minChild = timerHeap[leftChildIndex];
+ var minChildKey = minChild[0];
+ var rightChildIndex = leftChildIndex + 1;
+ if (rightChildIndex < timerHeap.length) {
+ var rightChild = timerHeap[rightChildIndex];
+ var rightKey = rightChild[0];
+ if (rightKey < minChildKey) {
+ minChildIndex = rightChildIndex;
+ minChild = rightChild;
+ minChildKey = rightKey;
+ }
+ }
+ if (minChildKey > key) break;
+ timerHeap[index] = minChild;
+ index = minChildIndex;
+ }
+ timerHeap[index] = value;
+ }
+
+ function addInterval(f, ms) {
+ var id = timerIdCounter++;
+ function repeat() {
+ // Reactivate with the same id.
+ repeat.$timerId = id;
+ timerIds[id] = repeat;
+ addDelayedTimer(repeat, ms);
+ f();
+ }
+ repeat.$timerId = id;
+ timerIds[id] = repeat;
+ addDelayedTimer(repeat, ms);
+ return id;
+ }
+
+ function cancelTimer(id) {
+ var f = timerIds[id];
+ if (f == null) return;
+ clearTimerId(f, id);
+ }
+
+ function clearTimerId(f, id) {
+ f.$timerId = undefined;
+ delete timerIds[id];
+ }
+
+ function eventLoop(action) {
+ while (action) {
+ try {
+ action();
+ } catch (e) {
+ if (typeof onerror == "function") {
+ onerror(e, null, -1);
+ } else {
+ throw e;
+ }
+ }
+ action = nextEvent();
+ }
+ }
+
+ self.dartMainRunner = function(main, args) {
+ // Initialize.
+ var action = function() { main(args); }
+ eventLoop(action);
+ };
+ self.setTimeout = addTimer;
+ self.clearTimeout = cancelTimer;
+ self.setInterval = addInterval;
+ self.clearInterval = cancelTimer;
+ self.scheduleImmediate = addTask;
+
+ function computeCurrentScript() {
+ try {
+ throw new Error();
+ } catch(e) {
+ var stack = e.stack;
+ print(stack);
+ // The jsshell stack looks like:
+ // computeCurrentScript@...preambles/jsshell.js:23:13
+ // self.document.currentScript@...preambles/jsshell.js:53:37
+ // @/tmp/foo.js:308:1
+ // @/tmp/foo.js:303:1
+ // @/tmp/foo.js:5:1
+ var re = new RegExp("^.*@(.*):[0-9]*:[0-9]*$", "mg");
+ var lastMatch = null;
+ do {
+ var match = re.exec(stack);
+ if (match != null) lastMatch = match;
+ } while (match != null);
+ return lastMatch[1];
+ }
+ }
+
+ // Adding a 'document' is dangerous since it invalidates the 'typeof document'
+ // test to see if we are running in the browser. It means that the runtime
+ // needs to do more precise checks.
+ // Note that we can't run "currentScript" right away, since that would give
+ // us the location of the preamble file. Instead we wait for the first access
+ // which should happen just before invoking main. At this point we are in
+ // the main file and setting the currentScript property is correct.
+ // Note that we cannot use `thisFileName()`, since that would give us the
+ // preamble and not the script file.
+ var cachedCurrentScript = null;
+ self.document = { get currentScript() {
+ if (cachedCurrentScript == null) {
+ cachedCurrentScript = {src: computeCurrentScript()};
+ }
+ return cachedCurrentScript;
+ }
+ };
+
+ // Support for deferred loading.
+ self.dartDeferredLibraryLoader = function(uri, successCallback, errorCallback) {
+ try {
+ load(uri);
+ successCallback();
+ } catch (error) {
+ errorCallback(error);
+ }
+ };
+
+ // Mock cryptographically secure random by using plain random.
+ self.crypto = {getRandomValues: function(array) {
+ for (var i = 0; i < array.length; i++) {
+ array[i] = Math.random() * 256;
+ }
+ }};
+})(this)
+
+var getKeys = function(obj){
+ var keys = [];
+ for(var key in obj){
+ keys.push(key);
+ }
+ return keys;
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/regexp_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/regexp_helper.dart
new file mode 100644
index 0000000..3dacc06
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/regexp_helper.dart
@@ -0,0 +1,295 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _js_helper;
+
+// Helper method used by internal libraries.
+regExpGetNative(JSSyntaxRegExp regexp) => regexp._nativeRegExp;
+
+/// Returns a native version of the RegExp with the global flag set.
+///
+/// The RegExp's `lastIndex` property is zero when it is returned.
+///
+/// The returned regexp is shared, and its `lastIndex` property may be
+/// modified by other uses, so the returned regexp must be used immediately
+/// when it's returned, with no user-provided code run in between.
+regExpGetGlobalNative(JSSyntaxRegExp regexp) {
+ var nativeRegexp = regexp._nativeGlobalVersion;
+ JS('void', '#.lastIndex = 0', nativeRegexp);
+ return nativeRegexp;
+}
+
+/// Computes the number of captures in a regexp.
+///
+/// This currently involves creating a new RegExp object with a different
+/// source and running it against the empty string (the last part is usually
+/// fast).
+///
+/// The JSSyntaxRegExp could cache the result, and set the cache any time
+/// it finds a match.
+int regExpCaptureCount(JSSyntaxRegExp regexp) {
+ var nativeAnchoredRegExp = regexp._nativeAnchoredVersion;
+ var match = JS('JSExtendableArray', '#.exec("")', nativeAnchoredRegExp);
+ // The native-anchored regexp always have one capture more than the original,
+ // and always matches the empty string.
+ return match.length - 2;
+}
+
+class JSSyntaxRegExp implements RegExp {
+ final String pattern;
+ final _nativeRegExp;
+ var _nativeGlobalRegExp;
+ var _nativeAnchoredRegExp;
+
+ String toString() =>
+ 'RegExp/$pattern/' + JS('String', '#.flags', _nativeRegExp);
+
+ JSSyntaxRegExp(String source,
+ {bool multiLine: false,
+ bool caseSensitive: true,
+ bool unicode: false,
+ bool dotAll: false})
+ : this.pattern = source,
+ this._nativeRegExp = makeNative(
+ source, multiLine, caseSensitive, unicode, dotAll, false);
+
+ get _nativeGlobalVersion {
+ if (_nativeGlobalRegExp != null) return _nativeGlobalRegExp;
+ return _nativeGlobalRegExp = makeNative(
+ pattern, _isMultiLine, _isCaseSensitive, _isUnicode, _isDotAll, true);
+ }
+
+ get _nativeAnchoredVersion {
+ if (_nativeAnchoredRegExp != null) return _nativeAnchoredRegExp;
+ // An "anchored version" of a regexp is created by adding "|()" to the
+ // source. This means that the regexp always matches at the first position
+ // that it tries, and you can see if the original regexp matched, or it
+ // was the added zero-width match that matched, by looking at the last
+ // capture. If it is a String, the match participated, otherwise it didn't.
+ return _nativeAnchoredRegExp = makeNative('$pattern|()', _isMultiLine,
+ _isCaseSensitive, _isUnicode, _isDotAll, true);
+ }
+
+ bool get _isMultiLine => JS('bool', '#.multiline', _nativeRegExp);
+ bool get _isCaseSensitive => JS('bool', '!#.ignoreCase', _nativeRegExp);
+ bool get _isUnicode => JS('bool', '#.unicode', _nativeRegExp);
+ bool get _isDotAll => JS('bool', '#.dotAll', _nativeRegExp);
+
+ static makeNative(String source, bool multiLine, bool caseSensitive,
+ bool unicode, bool dotAll, bool global) {
+ checkString(source);
+ String m = multiLine == true ? 'm' : '';
+ String i = caseSensitive == true ? '' : 'i';
+ String u = unicode ? 'u' : '';
+ String s = dotAll ? 's' : '';
+ String g = global ? 'g' : '';
+ // We're using the JavaScript's try catch instead of the Dart one to avoid
+ // dragging in Dart runtime support just because of using RegExp.
+ var regexp = JS(
+ '',
+ r'''
+ (function(source, modifiers) {
+ try {
+ return new RegExp(source, modifiers);
+ } catch (e) {
+ return e;
+ }
+ })(#, # + # + # + # + #)''',
+ source,
+ m,
+ i,
+ u,
+ s,
+ g);
+ if (JS('bool', '# instanceof RegExp', regexp)) return regexp;
+ // The returned value is the JavaScript exception. Turn it into a
+ // Dart exception.
+ String errorMessage = JS('String', r'String(#)', regexp);
+ throw new FormatException('Illegal RegExp pattern ($errorMessage)', source);
+ }
+
+ RegExpMatch firstMatch(String string) {
+ List m = JS('JSExtendableArray|Null', r'#.exec(#)', _nativeRegExp,
+ checkString(string));
+ if (m == null) return null;
+ return new _MatchImplementation(this, m);
+ }
+
+ bool hasMatch(String string) {
+ return JS('bool', r'#.test(#)', _nativeRegExp, checkString(string));
+ }
+
+ String stringMatch(String string) {
+ var match = firstMatch(string);
+ if (match != null) return match.group(0);
+ return null;
+ }
+
+ Iterable<RegExpMatch> allMatches(String string, [int start = 0]) {
+ checkString(string);
+ checkInt(start);
+ if (start < 0 || start > string.length) {
+ throw new RangeError.range(start, 0, string.length);
+ }
+ return new _AllMatchesIterable(this, string, start);
+ }
+
+ RegExpMatch _execGlobal(String string, int start) {
+ Object regexp = _nativeGlobalVersion;
+ JS('void', '#.lastIndex = #', regexp, start);
+ List match = JS('JSExtendableArray|Null', '#.exec(#)', regexp, string);
+ if (match == null) return null;
+ return new _MatchImplementation(this, match);
+ }
+
+ RegExpMatch _execAnchored(String string, int start) {
+ Object regexp = _nativeAnchoredVersion;
+ JS('void', '#.lastIndex = #', regexp, start);
+ List match = JS('JSExtendableArray|Null', '#.exec(#)', regexp, string);
+ if (match == null) return null;
+ // If the last capture group participated, the original regexp did not
+ // match at the start position.
+ if (match.removeLast() != null) return null;
+ return new _MatchImplementation(this, match);
+ }
+
+ RegExpMatch matchAsPrefix(String string, [int start = 0]) {
+ if (start < 0 || start > string.length) {
+ throw new RangeError.range(start, 0, string.length);
+ }
+ return _execAnchored(string, start);
+ }
+
+ bool get isMultiLine => _isMultiLine;
+ bool get isCaseSensitive => _isCaseSensitive;
+ bool get isUnicode => _isUnicode;
+ bool get isDotAll => _isDotAll;
+}
+
+class _MatchImplementation implements RegExpMatch {
+ final Pattern pattern;
+ // Contains a JS RegExp match object.
+ // It is an Array of String values with extra 'index' and 'input' properties.
+ // If there were named capture groups, there will also be an extra 'groups'
+ // property containing an object with capture group names as keys and
+ // matched strings as values.
+ // We didn't force it to be JSArray<String>, so it is JSArray<dynamic>, but
+ // containing String or `undefined` values.
+ final JSArray _match;
+
+ _MatchImplementation(this.pattern, this._match) {
+ assert(JS('var', '#.input', _match) is String);
+ assert(JS('var', '#.index', _match) is int);
+ }
+
+ String get input => JS('String', '#.input', _match);
+
+ int get start =>
+ JS('returns:int;depends:none;effects:none;gvn:true', '#.index', _match);
+
+ int get end =>
+ start +
+ JS('returns:int;depends:none;effects:none;gvn:true', '#[0].length',
+ _match);
+
+ // The JS below changes the static type to avoid an implicit cast.
+ // TODO(sra): Find a nicer way to do this, e.g. unsafeCast.
+ String group(int index) => JS('String|Null', '#', _match[index]);
+
+ String operator [](int index) => group(index);
+
+ int get groupCount => _match.length - 1;
+
+ List<String> groups(List<int> groups) {
+ List<String> out = [];
+ for (int i in groups) {
+ out.add(group(i));
+ }
+ return out;
+ }
+
+ String namedGroup(String name) {
+ var groups = JS('Object', '#.groups', _match);
+ if (groups != null) {
+ var result = JS('String|Null', '#[#]', groups, name);
+ if (result != null || JS('bool', '# in #', name, groups)) {
+ return result;
+ }
+ }
+ throw ArgumentError.value(name, "name", "Not a capture group name");
+ }
+
+ Iterable<String> get groupNames {
+ var groups = JS('Object', '#.groups', _match);
+ if (groups != null) {
+ var keys = new JSArray<String>.markGrowable(
+ JS('returns:JSExtendableArray;new:true', 'Object.keys(#)', groups));
+ return SubListIterable(keys, 0, null);
+ }
+ return Iterable.empty();
+ }
+}
+
+class _AllMatchesIterable extends IterableBase<RegExpMatch> {
+ final JSSyntaxRegExp _re;
+ final String _string;
+ final int _start;
+
+ _AllMatchesIterable(this._re, this._string, this._start);
+
+ Iterator<RegExpMatch> get iterator =>
+ new _AllMatchesIterator(_re, _string, _start);
+}
+
+class _AllMatchesIterator implements Iterator<RegExpMatch> {
+ final JSSyntaxRegExp _regExp;
+ String _string;
+ int _nextIndex;
+ RegExpMatch _current;
+
+ _AllMatchesIterator(this._regExp, this._string, this._nextIndex);
+
+ RegExpMatch get current => _current;
+
+ static bool _isLeadSurrogate(int c) {
+ return c >= 0xd800 && c <= 0xdbff;
+ }
+
+ static bool _isTrailSurrogate(int c) {
+ return c >= 0xdc00 && c <= 0xdfff;
+ }
+
+ bool moveNext() {
+ if (_string == null) return false;
+ if (_nextIndex <= _string.length) {
+ var match = _regExp._execGlobal(_string, _nextIndex);
+ if (match != null) {
+ _current = match;
+ int nextIndex = match.end;
+ if (match.start == nextIndex) {
+ // Zero-width match. Advance by one more, unless the regexp
+ // is in unicode mode and it would put us within a surrogate
+ // pair. In that case, advance past the code point as a whole.
+ if (_regExp.isUnicode &&
+ _nextIndex + 1 < _string.length &&
+ _isLeadSurrogate(_string.codeUnitAt(_nextIndex)) &&
+ _isTrailSurrogate(_string.codeUnitAt(_nextIndex + 1))) {
+ nextIndex++;
+ }
+ nextIndex++;
+ }
+ _nextIndex = nextIndex;
+ return true;
+ }
+ }
+ _current = null;
+ _string = null; // Marks iteration as ended.
+ return false;
+ }
+}
+
+/// Find the first match of [regExp] in [string] at or after [start].
+RegExpMatch firstMatchAfter(JSSyntaxRegExp regExp, String string, int start) {
+ return regExp._execGlobal(string, start);
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
new file mode 100644
index 0000000..f7ca527
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
@@ -0,0 +1,2492 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This library contains support for runtime type information.
+library rti;
+
+import 'dart:_foreign_helper'
+ show
+ getInterceptor,
+ getJSArrayInteropRti,
+ JS,
+ JS_BUILTIN,
+ JS_EMBEDDED_GLOBAL,
+ JS_GET_FLAG,
+ JS_GET_NAME,
+ JS_STRING_CONCAT,
+ RAW_DART_FUNCTION_REF;
+
+import 'dart:_interceptors' show JSArray, JSUnmodifiableArray;
+
+import 'dart:_js_names' show unmangleGlobalNameIfPreservedAnyways;
+
+import 'dart:_js_embedded_names'
+ show JsBuiltin, JsGetName, RtiUniverseFieldNames, RTI_UNIVERSE, TYPES;
+
+import 'dart:_recipe_syntax';
+
+/// An Rti object represents both a type (e.g `Map<int, String>`) and a type
+/// environment (`Map<int, String>` binds `Map.K=int` and `Map.V=String`).
+///
+/// There is a single [Rti] class to help reduce polymorphism in the JavaScript
+/// runtime. The class has a default constructor and no final fields so it can
+/// be created before much of the runtime exists.
+///
+/// The fields are declared in an order that gets shorter minified names for the
+/// more commonly used fields. (TODO: we should exploit the fact that an Rti
+/// instance never appears in a dynamic context, so does not need field names to
+/// be distinct from dynamic selectors).
+///
+class Rti {
+ /// JavaScript method for 'as' check. The method is called from generated code,
+ /// e.g. `o as T` generates something like `rtiForT._as(o)`.
+ @pragma('dart2js:noElision')
+ dynamic _as;
+
+ /// JavaScript method for type check. The method is called from generated
+ /// code, e.g. parameter check for `T param` generates something like
+ /// `rtiForT._check(param)`.
+ @pragma('dart2js:noElision')
+ dynamic _check;
+
+ /// JavaScript method for 'is' test. The method is called from generated
+ /// code, e.g. `o is T` generates something like `rtiForT._is(o)`.
+ @pragma('dart2js:noElision')
+ dynamic _is;
+
+ static void _setAsCheckFunction(Rti rti, fn) {
+ rti._as = fn;
+ }
+
+ static void _setTypeCheckFunction(Rti rti, fn) {
+ rti._check = fn;
+ }
+
+ static void _setIsTestFunction(Rti rti, fn) {
+ rti._is = fn;
+ }
+
+ @pragma('dart2js:tryInline')
+ static bool _isCheck(Rti rti, object) {
+ return JS(
+ 'bool', '#.#(#)', rti, JS_GET_NAME(JsGetName.RTI_FIELD_IS), object);
+ }
+
+ /// Method called from generated code to evaluate a type environment recipe in
+ /// `this` type environment.
+ Rti _eval(recipe) {
+ // TODO(sra): Clone the fast-path of _Universe.evalInEnvironment to here.
+ return _rtiEval(this, _Utils.asString(recipe));
+ }
+
+ /// Method called from generated code to extend `this` type environment (an
+ /// interface or binding Rti) with function type arguments (a singleton
+ /// argument or tuple of arguments).
+ Rti _bind(typeOrTuple) => _rtiBind(this, _castToRti(typeOrTuple));
+
+ /// Method called from generated code to extend `this` type (as a singleton
+ /// type environment) with function type arguments (a singleton argument or
+ /// tuple of arguments).
+ Rti _bind1(Rti typeOrTuple) => _rtiBind1(this, typeOrTuple);
+
+ // Precomputed derived types. These fields are used to hold derived types that
+ // are computed eagerly.
+ // TODO(sra): Implement precomputed type optimizations.
+ dynamic _precomputed1;
+ dynamic _precomputed2;
+ dynamic _precomputed3;
+ dynamic _precomputed4;
+
+ // The Type object corresponding to this Rti.
+ Object _cachedRuntimeType;
+ static _Type _getCachedRuntimeType(Rti rti) =>
+ JS('_Type|Null', '#', rti._cachedRuntimeType);
+ static void _setCachedRuntimeType(Rti rti, _Type type) {
+ rti._cachedRuntimeType = type;
+ }
+
+ /// The kind of Rti `this` is, one of the kindXXX constants below.
+ ///
+ /// We don't use an enum since we need to create Rti objects very early.
+ ///
+ /// The zero initializer ensures dart2js type analysis considers [_kind] is
+ /// non-nullable.
+ Object /*int*/ _kind = 0;
+
+ static int _getKind(Rti rti) => _Utils.asInt(rti._kind);
+ static void _setKind(Rti rti, int kind) {
+ rti._kind = kind;
+ }
+
+ // Terminal terms.
+ static const kindNever = 1;
+ static const kindDynamic = 2;
+ static const kindVoid = 3; // TODO(sra): Use `dynamic` instead?
+ static const kindAny = 4; // Dart1-style 'dynamic' for JS-interop.
+ // Unary terms.
+ static const kindStar = 5;
+ static const kindQuestion = 6;
+ static const kindFutureOr = 7;
+ // More complex terms.
+ static const kindInterface = 8;
+ // A vector of type parameters from enclosing functions and closures.
+ static const kindBinding = 9;
+ static const kindFunction = 10;
+ static const kindGenericFunction = 11;
+ static const kindGenericFunctionParameter = 12;
+
+ static bool _isUnionOfFunctionType(Rti rti) {
+ int kind = Rti._getKind(rti);
+ if (kind == kindStar || kind == kindQuestion || kind == kindFutureOr) {
+ return _isUnionOfFunctionType(_castToRti(_getPrimary(rti)));
+ }
+ return kind == kindFunction || kind == kindGenericFunction;
+ }
+
+ /// Primary data associated with type.
+ ///
+ /// - Minified name of interface for interface types.
+ /// - Underlying type for unary terms.
+ /// - Class part of a type environment inside a generic class, or `null` for
+ /// type tuple.
+ /// - Return type of a function type.
+ /// - Underlying function type for a generic function.
+ /// - de Bruijn index for a generic function parameter.
+ dynamic _primary;
+
+ static Object _getPrimary(Rti rti) => rti._primary;
+ static void _setPrimary(Rti rti, value) {
+ rti._primary = value;
+ }
+
+ /// Additional data associated with type.
+ ///
+ /// - The type arguments of an interface type.
+ /// - The type arguments from enclosing functions and closures for a
+ /// kindBinding.
+ /// - The [_FunctionParameters] of a function type.
+ /// - The type parameter bounds of a generic function.
+ dynamic _rest;
+
+ static Object _getRest(Rti rti) => rti._rest;
+ static void _setRest(Rti rti, value) {
+ rti._rest = value;
+ }
+
+ static String _getInterfaceName(Rti rti) {
+ assert(_getKind(rti) == kindInterface);
+ return _Utils.asString(_getPrimary(rti));
+ }
+
+ static JSArray _getInterfaceTypeArguments(Rti rti) {
+ // The array is a plain JavaScript Array, otherwise we would need the type
+ // `JSArray<Rti>` to exist before we could create the type `JSArray<Rti>`.
+ assert(_getKind(rti) == kindInterface);
+ return JS('JSUnmodifiableArray', '#', _getRest(rti));
+ }
+
+ static Rti _getBindingBase(Rti rti) {
+ assert(_getKind(rti) == kindBinding);
+ return _castToRti(_getPrimary(rti));
+ }
+
+ static JSArray _getBindingArguments(Rti rti) {
+ assert(_getKind(rti) == kindBinding);
+ return JS('JSUnmodifiableArray', '#', _getRest(rti));
+ }
+
+ static Rti _getStarArgument(Rti rti) {
+ assert(_getKind(rti) == kindStar);
+ return _castToRti(_getPrimary(rti));
+ }
+
+ static Rti _getQuestionArgument(Rti rti) {
+ assert(_getKind(rti) == kindQuestion);
+ return _castToRti(_getPrimary(rti));
+ }
+
+ static Rti _getFutureOrArgument(Rti rti) {
+ assert(_getKind(rti) == kindFutureOr);
+ return _castToRti(_getPrimary(rti));
+ }
+
+ static Rti _getReturnType(Rti rti) {
+ assert(_getKind(rti) == kindFunction);
+ return _castToRti(_getPrimary(rti));
+ }
+
+ static _FunctionParameters _getFunctionParameters(Rti rti) {
+ assert(_getKind(rti) == kindFunction);
+ return JS('_FunctionParameters', '#', _getRest(rti));
+ }
+
+ static Rti _getGenericFunctionBase(Rti rti) {
+ assert(_getKind(rti) == kindGenericFunction);
+ return _castToRti(_getPrimary(rti));
+ }
+
+ static JSArray _getGenericFunctionBounds(Rti rti) {
+ assert(_getKind(rti) == kindGenericFunction);
+ return JS('JSUnmodifiableArray', '#', _getRest(rti));
+ }
+
+ static int _getGenericFunctionParameterIndex(Rti rti) {
+ assert(_getKind(rti) == kindGenericFunctionParameter);
+ return _Utils.asInt(_getPrimary(rti));
+ }
+
+ /// On [Rti]s that are type environments*, derived types are cached on the
+ /// environment to ensure fast canonicalization. Ground-term types (i.e. not
+ /// dependent on class or function type parameters) are cached in the
+ /// universe. This field starts as `null` and the cache is created on demand.
+ ///
+ /// *Any Rti can be a type environment, since we use the type for a function
+ /// type environment. The ambiguity between 'generic class is the environment'
+ /// and 'generic class is a singleton type argument' is resolved by using
+ /// different indexing in the recipe.
+ Object _evalCache;
+
+ static Object _getEvalCache(Rti rti) => rti._evalCache;
+ static void _setEvalCache(Rti rti, value) {
+ rti._evalCache = value;
+ }
+
+ /// On [Rti]s that are type environments*, extended environments are cached on
+ /// the base environment to ensure fast canonicalization.
+ ///
+ /// This field starts as `null` and the cache is created on demand.
+ ///
+ /// *This is valid only on kindInterface and kindBinding Rtis. The ambiguity
+ /// between 'generic class is the base environment' and 'generic class is a
+ /// singleton type argument' is resolved [TBD] (either (1) a bind1 cache, or
+ /// (2)using `env._eval("@<0>")._bind(args)` in place of `env._bind1(args)`).
+ ///
+ /// On [Rti]s that are generic function types, results of instantiation are
+ /// cached on the generic function type to ensure fast repeated
+ /// instantiations.
+ Object _bindCache;
+
+ static Object _getBindCache(Rti rti) => rti._bindCache;
+ static void _setBindCache(Rti rti, value) {
+ rti._bindCache = value;
+ }
+
+ static Rti allocate() {
+ return new Rti();
+ }
+
+ Object _canonicalRecipe;
+
+ static String _getCanonicalRecipe(Rti rti) {
+ Object s = rti._canonicalRecipe;
+ assert(_Utils.isString(s), 'Missing canonical recipe');
+ return _Utils.asString(s);
+ }
+
+ static void _setCanonicalRecipe(Rti rti, String s) {
+ rti._canonicalRecipe = s;
+ }
+}
+
+class _FunctionParameters {
+ // TODO(fishythefish): Support required named parameters.
+
+ static _FunctionParameters allocate() => _FunctionParameters();
+
+ Object _requiredPositional;
+ static JSArray _getRequiredPositional(_FunctionParameters parameters) =>
+ JS('JSUnmodifiableArray', '#', parameters._requiredPositional);
+ static void _setRequiredPositional(
+ _FunctionParameters parameters, Object requiredPositional) {
+ parameters._requiredPositional = requiredPositional;
+ }
+
+ Object _optionalPositional;
+ static JSArray _getOptionalPositional(_FunctionParameters parameters) =>
+ JS('JSUnmodifiableArray', '#', parameters._optionalPositional);
+ static void _setOptionalPositional(
+ _FunctionParameters parameters, Object optionalPositional) {
+ parameters._optionalPositional = optionalPositional;
+ }
+
+ /// These are alternating name/type pairs; that is, the optional named
+ /// parameters of the function
+ ///
+ /// void foo({int bar, double baz})
+ ///
+ /// would be encoded as ["bar", int, "baz", double], where the even indices are
+ /// the name [String]s and the odd indices are the type [Rti]s.
+ ///
+ /// Invariant: These pairs are sorted by name in lexicographically ascending order.
+ Object _optionalNamed;
+ static JSArray _getOptionalNamed(_FunctionParameters parameters) =>
+ JS('JSUnmodifiableArray', '#', parameters._optionalNamed);
+ static void _setOptionalNamed(
+ _FunctionParameters parameters, Object optionalNamed) {
+ parameters._optionalNamed = optionalNamed;
+ }
+}
+
+Object _theUniverse() => JS_EMBEDDED_GLOBAL('', RTI_UNIVERSE);
+
+Rti _rtiEval(Rti environment, String recipe) {
+ return _Universe.evalInEnvironment(_theUniverse(), environment, recipe);
+}
+
+Rti _rtiBind1(Rti environment, Rti types) {
+ return _Universe.bind1(_theUniverse(), environment, types);
+}
+
+Rti _rtiBind(Rti environment, Rti types) {
+ return _Universe.bind(_theUniverse(), environment, types);
+}
+
+/// Evaluate a ground-term type.
+/// Called from generated code.
+Rti findType(String recipe) {
+ return _Universe.eval(_theUniverse(), recipe);
+}
+
+/// Evaluate a type recipe in the environment of an instance.
+Rti evalInInstance(instance, String recipe) {
+ return _rtiEval(instanceType(instance), recipe);
+}
+
+/// Returns [genericFunctionRti] with type parameters bound to those specified
+/// by [instantiationRti].
+///
+/// [genericFunctionRti] must be an rti representation with a number of generic
+/// type parameters matching the number of types provided by [instantiationRti].
+///
+/// Called from generated code.
+@pragma('dart2js:noInline')
+Rti instantiatedGenericFunctionType(
+ Rti genericFunctionRti, Rti instantiationRti) {
+ var bounds = Rti._getGenericFunctionBounds(genericFunctionRti);
+ var typeArguments = Rti._getInterfaceTypeArguments(instantiationRti);
+ assert(_Utils.arrayLength(bounds) == _Utils.arrayLength(typeArguments));
+
+ var cache = Rti._getBindCache(genericFunctionRti);
+ if (cache == null) {
+ cache = JS('', 'new Map()');
+ Rti._setBindCache(genericFunctionRti, cache);
+ }
+ String key = Rti._getCanonicalRecipe(instantiationRti);
+ var probe = _Utils.mapGet(cache, key);
+ if (probe != null) return _castToRti(probe);
+ Rti rti = _instantiate(_theUniverse(),
+ Rti._getGenericFunctionBase(genericFunctionRti), typeArguments, 0);
+ _Utils.mapSet(cache, key, rti);
+ return rti;
+}
+
+/// Substitutes [typeArguments] for generic function parameters in [rti].
+///
+/// Generic function parameters are de Bruijn indices counting up through the
+/// parameters' scopes to index into [typeArguments].
+///
+/// [depth] is the number of subsequent generic function parameters that are in
+/// scope. This is subtracted off the de Bruijn index for the type parameter to
+/// arrive at an potential index into [typeArguments].
+Rti _instantiate(universe, Rti rti, Object typeArguments, int depth) {
+ int kind = Rti._getKind(rti);
+ switch (kind) {
+ case Rti.kindNever:
+ case Rti.kindDynamic:
+ case Rti.kindVoid:
+ case Rti.kindAny:
+ return rti;
+ case Rti.kindStar:
+ Rti baseType = _castToRti(Rti._getPrimary(rti));
+ Rti instantiatedBaseType =
+ _instantiate(universe, baseType, typeArguments, depth);
+ if (_Utils.isIdentical(instantiatedBaseType, baseType)) return rti;
+ return _Universe._lookupStarRti(universe, instantiatedBaseType);
+ case Rti.kindQuestion:
+ Rti baseType = _castToRti(Rti._getPrimary(rti));
+ Rti instantiatedBaseType =
+ _instantiate(universe, baseType, typeArguments, depth);
+ if (_Utils.isIdentical(instantiatedBaseType, baseType)) return rti;
+ return _Universe._lookupQuestionRti(universe, instantiatedBaseType);
+ case Rti.kindFutureOr:
+ Rti baseType = _castToRti(Rti._getPrimary(rti));
+ Rti instantiatedBaseType =
+ _instantiate(universe, baseType, typeArguments, depth);
+ if (_Utils.isIdentical(instantiatedBaseType, baseType)) return rti;
+ return _Universe._lookupFutureOrRti(universe, instantiatedBaseType);
+ case Rti.kindInterface:
+ Object interfaceTypeArguments = Rti._getInterfaceTypeArguments(rti);
+ Object instantiatedInterfaceTypeArguments = _instantiateArray(
+ universe, interfaceTypeArguments, typeArguments, depth);
+ if (_Utils.isIdentical(
+ instantiatedInterfaceTypeArguments, interfaceTypeArguments))
+ return rti;
+ return _Universe._lookupInterfaceRti(universe, Rti._getInterfaceName(rti),
+ instantiatedInterfaceTypeArguments);
+ case Rti.kindBinding:
+ Rti base = Rti._getBindingBase(rti);
+ Rti instantiatedBase = _instantiate(universe, base, typeArguments, depth);
+ Object arguments = Rti._getBindingArguments(rti);
+ Object instantiatedArguments =
+ _instantiateArray(universe, arguments, typeArguments, depth);
+ if (_Utils.isIdentical(instantiatedBase, base) &&
+ _Utils.isIdentical(instantiatedArguments, arguments)) return rti;
+ return _Universe._lookupBindingRti(
+ universe, instantiatedBase, instantiatedArguments);
+ case Rti.kindFunction:
+ Rti returnType = Rti._getReturnType(rti);
+ Rti instantiatedReturnType =
+ _instantiate(universe, returnType, typeArguments, depth);
+ _FunctionParameters functionParameters = Rti._getFunctionParameters(rti);
+ _FunctionParameters instantiatedFunctionParameters =
+ _instantiateFunctionParameters(
+ universe, functionParameters, typeArguments, depth);
+ if (_Utils.isIdentical(instantiatedReturnType, returnType) &&
+ _Utils.isIdentical(
+ instantiatedFunctionParameters, functionParameters)) return rti;
+ return _Universe._lookupFunctionRti(
+ universe, instantiatedReturnType, instantiatedFunctionParameters);
+ case Rti.kindGenericFunction:
+ Object bounds = Rti._getGenericFunctionBounds(rti);
+ depth += _Utils.arrayLength(bounds);
+ Object instantiatedBounds =
+ _instantiateArray(universe, bounds, typeArguments, depth);
+ Rti base = Rti._getGenericFunctionBase(rti);
+ Rti instantiatedBase = _instantiate(universe, base, typeArguments, depth);
+ if (_Utils.isIdentical(instantiatedBounds, bounds) &&
+ _Utils.isIdentical(instantiatedBase, base)) return rti;
+ return _Universe._lookupGenericFunctionRti(
+ universe, instantiatedBase, instantiatedBounds);
+ case Rti.kindGenericFunctionParameter:
+ int index = Rti._getGenericFunctionParameterIndex(rti);
+ if (index < depth) return null;
+ return _castToRti(_Utils.arrayAt(typeArguments, index - depth));
+ default:
+ throw AssertionError(
+ 'Attempted to instantiate unexpected RTI kind $kind');
+ }
+}
+
+Object _instantiateArray(
+ universe, Object rtiArray, Object typeArguments, int depth) {
+ bool changed = false;
+ int length = _Utils.arrayLength(rtiArray);
+ Object result = JS('', '[]');
+ for (int i = 0; i < length; i++) {
+ Rti rti = _castToRti(_Utils.arrayAt(rtiArray, i));
+ Rti instantiatedRti = _instantiate(universe, rti, typeArguments, depth);
+ if (!_Utils.isIdentical(instantiatedRti, rti)) {
+ changed = true;
+ }
+ _Utils.arrayPush(result, instantiatedRti);
+ }
+ return changed ? result : rtiArray;
+}
+
+Object _instantiateNamed(
+ universe, Object namedArray, Object typeArguments, int depth) {
+ bool changed = false;
+ int length = _Utils.arrayLength(namedArray);
+ assert(length.isEven);
+ Object result = JS('', '[]');
+ for (int i = 0; i < length; i += 2) {
+ String name = _Utils.asString(_Utils.arrayAt(namedArray, i));
+ Rti rti = _castToRti(_Utils.arrayAt(namedArray, i + 1));
+ Rti instantiatedRti = _instantiate(universe, rti, typeArguments, depth);
+ if (!_Utils.isIdentical(instantiatedRti, rti)) {
+ changed = true;
+ }
+ _Utils.arrayPush(result, name);
+ _Utils.arrayPush(result, instantiatedRti);
+ }
+ return changed ? result : namedArray;
+}
+
+// TODO(fishythefish): Support required named parameters.
+_FunctionParameters _instantiateFunctionParameters(universe,
+ _FunctionParameters functionParameters, Object typeArguments, int depth) {
+ Object requiredPositional =
+ _FunctionParameters._getRequiredPositional(functionParameters);
+ Object instantiatedRequiredPositional =
+ _instantiateArray(universe, requiredPositional, typeArguments, depth);
+ Object optionalPositional =
+ _FunctionParameters._getOptionalPositional(functionParameters);
+ Object instantiatedOptionalPositional =
+ _instantiateArray(universe, optionalPositional, typeArguments, depth);
+ Object optionalNamed =
+ _FunctionParameters._getOptionalNamed(functionParameters);
+ Object instantiatedOptionalNamed =
+ _instantiateNamed(universe, optionalNamed, typeArguments, depth);
+ if (_Utils.isIdentical(instantiatedRequiredPositional, requiredPositional) &&
+ _Utils.isIdentical(instantiatedOptionalPositional, optionalPositional) &&
+ _Utils.isIdentical(instantiatedOptionalNamed, optionalNamed))
+ return functionParameters;
+ _FunctionParameters result = _FunctionParameters.allocate();
+ _FunctionParameters._setRequiredPositional(
+ result, instantiatedRequiredPositional);
+ _FunctionParameters._setOptionalPositional(
+ result, instantiatedOptionalPositional);
+ _FunctionParameters._setOptionalNamed(result, instantiatedOptionalNamed);
+ return result;
+}
+
+bool _isClosure(object) => _Utils.instanceOf(object,
+ JS_BUILTIN('depends:none;effects:none;', JsBuiltin.dartClosureConstructor));
+
+/// Returns the structural function [Rti] of [closure].
+/// Called from generated code.
+Rti closureFunctionType(closure) {
+ var signatureName = JS_GET_NAME(JsGetName.SIGNATURE_NAME);
+ var signature = JS('', '#[#]', closure, signatureName);
+ if (signature != null) {
+ if (JS('bool', 'typeof # == "number"', signature)) {
+ return getTypeFromTypesTable(_Utils.asInt(signature));
+ }
+ return _castToRti(JS('', '#[#]()', closure, signatureName));
+ }
+ return null;
+}
+
+// Subclasses of Closure are synthetic classes. The synthetic classes all
+// extend a 'normal' class (Closure, BoundClosure, StaticClosure), so make
+// them appear to be the superclass.
+// TODO(sra): Can this be done less expensively, e.g. by putting $ti on the
+// prototype of Closure/BoundClosure/StaticClosure classes?
+Rti _closureInterfaceType(closure) {
+ var rti = JS('', r'#[#]', closure, JS_GET_NAME(JsGetName.RTI_NAME));
+ return rti != null
+ ? _castToRti(rti)
+ : _instanceTypeFromConstructor(
+ JS('', '#.__proto__.__proto__.constructor', closure));
+}
+
+/// Returns the Rti type of [object]. Closures have both an interface type
+/// (Closures implement `Function`) and a structural function type. Uses
+/// [testRti] to choose the appropriate type.
+///
+/// Called from generated code.
+Rti instanceOrFunctionType(object, Rti testRti) {
+ if (Rti._isUnionOfFunctionType(testRti)) {
+ if (_isClosure(object)) {
+ // If [testRti] is e.g. `FutureOr<Action>` (where `Action` is some
+ // function type), we don't need to worry about the `Future<Action>`
+ // branch because closures can't be `Future`s.
+ Rti rti = closureFunctionType(object);
+ if (rti != null) return rti;
+ }
+ }
+ return instanceType(object);
+}
+
+/// Returns the Rti type of [object].
+/// Called from generated code.
+Rti instanceType(object) {
+ if (_isClosure(object)) return _closureInterfaceType(object);
+ return _nonClosureInstanceType(object);
+}
+
+Rti _nonClosureInstanceType(object) {
+ // TODO(sra): Add specializations of this method. One possible way is to
+ // arrange that the interceptor has a _getType method that is injected into
+ // DartObject, Interceptor and JSArray. Then this method can be replaced-by
+ // `getInterceptor(o)._getType(o)`, allowing interceptor optimizations to
+ // select the specialization.
+
+ if (_Utils.instanceOf(
+ object,
+ JS_BUILTIN(
+ 'depends:none;effects:none;', JsBuiltin.dartObjectConstructor))) {
+ return _instanceType(object);
+ }
+
+ if (_Utils.isArray(object)) {
+ return _arrayInstanceType(object);
+ }
+
+ var interceptor = getInterceptor(object);
+ return _instanceTypeFromConstructor(JS('', '#.constructor', interceptor));
+}
+
+/// Returns the Rti type of JavaScript Array [object].
+/// Called from generated code.
+Rti _arrayInstanceType(object) {
+ // TODO(sra): Do we need to protect against an Array passed between two Dart
+ // programs loaded into the same JavaScript isolate (e.g. via JS-interop).
+ // FWIW, the legacy rti has this problem too. Perhaps JSArrays should use a
+ // program-local `symbol` for the type field.
+ var rti = JS('', r'#[#]', object, JS_GET_NAME(JsGetName.RTI_NAME));
+ return rti != null ? _castToRti(rti) : _castToRti(getJSArrayInteropRti());
+}
+
+/// Returns the Rti type of user-defined class [object].
+/// [object] must not be an intercepted class or a closure.
+/// Called from generated code.
+Rti _instanceType(object) {
+ var rti = JS('', r'#[#]', object, JS_GET_NAME(JsGetName.RTI_NAME));
+ return rti != null
+ ? _castToRti(rti)
+ : _instanceTypeFromConstructor(JS('', '#.constructor', object));
+}
+
+String instanceTypeName(object) {
+ Rti rti = instanceType(object);
+ return _rtiToString(rti, null);
+}
+
+Rti _instanceTypeFromConstructor(constructor) {
+ // TODO(sra): Cache Rti on constructor.
+ return findType(JS('String', '#.name', constructor));
+}
+
+/// Returns the structural function type of [object], or `null` if the object is
+/// not a closure.
+Rti _instanceFunctionType(object) =>
+ _isClosure(object) ? closureFunctionType(object) : null;
+
+/// Returns Rti from types table. The types table is initialized with recipe
+/// strings.
+Rti getTypeFromTypesTable(/*int*/ _index) {
+ int index = _Utils.asInt(_index);
+ var table = JS_EMBEDDED_GLOBAL('', TYPES);
+ var type = _Utils.arrayAt(table, index);
+ if (_Utils.isString(type)) {
+ Rti rti = findType(_Utils.asString(type));
+ _Utils.arraySetAt(table, index, rti);
+ return rti;
+ }
+ return _castToRti(type);
+}
+
+Type getRuntimeType(object) {
+ Rti rti = _instanceFunctionType(object) ?? _nonClosureInstanceType(object);
+ return createRuntimeType(rti);
+}
+
+/// Called from generated code.
+Type createRuntimeType(Rti rti) {
+ _Type type = Rti._getCachedRuntimeType(rti);
+ if (type != null) return type;
+ // TODO(https://github.com/dart-lang/language/issues/428) For NNBD transition,
+ // canonicalization may be needed. It might be possible to generate a
+ // star-free recipe from the canonical recipe and evaluate that.
+ type = _Type(rti);
+ Rti._setCachedRuntimeType(rti, type);
+ return type;
+}
+
+/// Called from generated code in the constant pool.
+Type typeLiteral(String recipe) {
+ return createRuntimeType(findType(recipe));
+}
+
+/// Implementation of [Type] based on Rti.
+class _Type implements Type {
+ final Rti _rti;
+ int _hashCode;
+
+ _Type(this._rti);
+
+ int get hashCode => _hashCode ??= Rti._getCanonicalRecipe(_rti).hashCode;
+
+ @pragma('dart2js:noInline')
+ bool operator ==(other) {
+ return (other is _Type) && identical(_rti, other._rti);
+ }
+
+ @override
+ String toString() => _rtiToString(_rti, null);
+}
+
+/// Called from generated code.
+bool _generalIsTestImplementation(object) {
+ // This static method is installed on an Rti object as a JavaScript instance
+ // method. The Rti object is 'this'.
+ Rti testRti = _castToRti(JS('', 'this'));
+ Rti objectRti = instanceOrFunctionType(object, testRti);
+ return isSubtype(_theUniverse(), objectRti, testRti);
+}
+
+/// Called from generated code.
+_generalAsCheckImplementation(object) {
+ if (object == null) return object;
+ // This static method is installed on an Rti object as a JavaScript instance
+ // method. The Rti object is 'this'.
+ Rti testRti = _castToRti(JS('', 'this'));
+ if (Rti._isCheck(testRti, object)) return object;
+
+ Rti objectRti = instanceOrFunctionType(object, testRti);
+ String message =
+ _Error.compose(object, objectRti, _rtiToString(testRti, null));
+ throw _CastError.fromMessage(message);
+}
+
+/// Called from generated code.
+_generalTypeCheckImplementation(object) {
+ if (object == null) return object;
+ // This static method is installed on an Rti object as a JavaScript instance
+ // method. The Rti object is 'this'.
+ Rti testRti = _castToRti(JS('', 'this'));
+ if (Rti._isCheck(testRti, object)) return object;
+
+ Rti objectRti = instanceOrFunctionType(object, testRti);
+ String message =
+ _Error.compose(object, objectRti, _rtiToString(testRti, null));
+ throw _TypeError.fromMessage(message);
+}
+
+/// Called from generated code.
+checkTypeBound(Rti type, Rti bound, variable) {
+ if (isSubtype(_theUniverse(), type, bound)) return type;
+ String message = "Type '${_rtiToString(type, null)}'"
+ " is not a subtype of type '${_rtiToString(bound, null)}'"
+ " of '${_Utils.asString(variable)}'";
+ throw _TypeError.fromMessage(message);
+}
+
+/// Base class to _CastError and _TypeError.
+class _Error extends Error {
+ final String _message;
+ _Error(this._message);
+
+ static String compose(object, objectRti, checkedTypeDescription) {
+ String objectDescription = Error.safeToString(object);
+ objectRti ??= instanceType(object);
+ String objectTypeDescription = _rtiToString(objectRti, null);
+ return "${objectDescription}:"
+ " type '${objectTypeDescription}'"
+ " is not a subtype of type '${checkedTypeDescription}'";
+ }
+
+ @override
+ String toString() => _message;
+}
+
+class _CastError extends _Error implements CastError {
+ _CastError.fromMessage(String message) : super('CastError: $message');
+
+ factory _CastError.forType(object, String type) {
+ return _CastError.fromMessage(_Error.compose(object, null, type));
+ }
+}
+
+class _TypeError extends _Error implements TypeError {
+ _TypeError.fromMessage(String message) : super('TypeError: $message');
+
+ factory _TypeError.forType(object, String type) {
+ return _TypeError.fromMessage(_Error.compose(object, null, type));
+ }
+
+ @override
+ String get message => _message;
+}
+
+// Specializations.
+//
+// Specializations can be placed on Rti objects as the _as, _check and _is
+// 'methods'. They can also be called directly called from generated code.
+
+/// Specialization for 'is bool'.
+/// Called from generated code.
+bool _isBool(object) {
+ return true == object || false == object;
+}
+
+/// Specialization for 'as bool?'.
+/// Called from generated code.
+bool /*?*/ _asBoolNullable(object) {
+ if (_isBool(object)) return _Utils.asBool(object);
+ if (object == null) return object;
+ throw _CastError.forType(object, 'bool');
+}
+
+/// Specialization for check on 'bool?'.
+/// Called from generated code.
+bool /*?*/ _checkBoolNullable(object) {
+ if (_isBool(object)) return _Utils.asBool(object);
+ if (object == null) return object;
+ throw _TypeError.forType(object, 'bool');
+}
+
+/// Specialization for 'as double?'.
+/// Called from generated code.
+double /*?*/ _asDoubleNullable(object) {
+ if (_isNum(object)) return _Utils.asDouble(object);
+ if (object == null) return object;
+ throw _CastError.forType(object, 'double');
+}
+
+/// Specialization for check on 'double?'.
+/// Called from generated code.
+double /*?*/ _checkDoubleNullable(object) {
+ if (_isNum(object)) return _Utils.asDouble(object);
+ if (object == null) return object;
+ throw _TypeError.forType(object, 'double');
+}
+
+/// Specialization for 'is int'.
+/// Called from generated code.
+bool _isInt(object) {
+ return JS('bool', 'typeof # == "number"', object) &&
+ JS('bool', 'Math.floor(#) === #', object, object);
+}
+
+/// Specialization for 'as int?'.
+/// Called from generated code.
+int /*?*/ _asIntNullable(object) {
+ if (_isInt(object)) return _Utils.asInt(object);
+ if (object == null) return object;
+ throw _CastError.forType(object, 'int');
+}
+
+/// Specialization for check on 'int?'.
+/// Called from generated code.
+int /*?*/ _checkIntNullable(object) {
+ if (_isInt(object)) return _Utils.asInt(object);
+ if (object == null) return object;
+ throw _TypeError.forType(object, 'int');
+}
+
+/// Specialization for 'is num' and 'is double'.
+/// Called from generated code.
+bool _isNum(object) {
+ return JS('bool', 'typeof # == "number"', object);
+}
+
+/// Specialization for 'as num?'.
+/// Called from generated code.
+num /*?*/ _asNumNullable(object) {
+ if (_isNum(object)) return _Utils.asNum(object);
+ if (object == null) return object;
+ throw _CastError.forType(object, 'num');
+}
+
+/// Specialization for check on 'num?'.
+/// Called from generated code.
+num /*?*/ _checkNumNullable(object) {
+ if (_isNum(object)) return _Utils.asNum(object);
+ if (object == null) return object;
+ throw _TypeError.forType(object, 'num');
+}
+
+/// Specialization for 'is String'.
+/// Called from generated code.
+bool _isString(object) {
+ return JS('bool', 'typeof # == "string"', object);
+}
+
+/// Specialization for 'as String?'.
+/// Called from generated code.
+String /*?*/ _asStringNullable(object) {
+ if (_isString(object)) return _Utils.asString(object);
+ if (object == null) return object;
+ throw _CastError.forType(object, 'String');
+}
+
+/// Specialization for check on 'String?'.
+/// Called from generated code.
+String /*?*/ _checkStringNullable(object) {
+ if (_isString(object)) return _Utils.asString(object);
+ if (object == null) return object;
+ throw _TypeError.forType(object, 'String');
+}
+
+String _rtiArrayToString(Object array, List<String> genericContext) {
+ String s = '', sep = '';
+ for (int i = 0; i < _Utils.arrayLength(array); i++) {
+ s += sep +
+ _rtiToString(_castToRti(_Utils.arrayAt(array, i)), genericContext);
+ sep = ', ';
+ }
+ return s;
+}
+
+String _functionRtiToString(Rti functionType, List<String> genericContext,
+ {Object bounds = null}) {
+ String typeParametersText = '';
+ int outerContextLength;
+
+ if (bounds != null) {
+ int boundsLength = _Utils.arrayLength(bounds);
+ if (genericContext == null) {
+ genericContext = <String>[];
+ } else {
+ outerContextLength = genericContext.length;
+ }
+ int offset = genericContext.length;
+ for (int i = boundsLength; i > 0; i--) {
+ genericContext.add('T${offset + i}');
+ }
+
+ String typeSep = '';
+ typeParametersText = '<';
+ for (int i = 0; i < boundsLength; i++) {
+ typeParametersText += typeSep;
+ typeParametersText += genericContext[genericContext.length - 1 - i];
+ Rti boundRti = _castToRti(_Utils.arrayAt(bounds, i));
+ if (!isTopType(boundRti)) {
+ typeParametersText +=
+ ' extends ' + _rtiToString(boundRti, genericContext);
+ }
+ typeSep = ', ';
+ }
+ typeParametersText += '>';
+ }
+
+ // TODO(fishythefish): Support required named parameters.
+ Rti returnType = Rti._getReturnType(functionType);
+ _FunctionParameters parameters = Rti._getFunctionParameters(functionType);
+ var requiredPositional =
+ _FunctionParameters._getRequiredPositional(parameters);
+ int requiredPositionalLength = _Utils.arrayLength(requiredPositional);
+ var optionalPositional =
+ _FunctionParameters._getOptionalPositional(parameters);
+ int optionalPositionalLength = _Utils.arrayLength(optionalPositional);
+ var optionalNamed = _FunctionParameters._getOptionalNamed(parameters);
+ int optionalNamedLength = _Utils.arrayLength(optionalNamed);
+ assert(optionalPositionalLength == 0 || optionalNamedLength == 0);
+
+ String returnTypeText = _rtiToString(returnType, genericContext);
+
+ String argumentsText = '';
+ String sep = '';
+ for (int i = 0; i < requiredPositionalLength; i++) {
+ argumentsText += sep +
+ _rtiToString(
+ _castToRti(_Utils.arrayAt(requiredPositional, i)), genericContext);
+ sep = ', ';
+ }
+
+ if (optionalPositionalLength > 0) {
+ argumentsText += sep + '[';
+ sep = '';
+ for (int i = 0; i < optionalPositionalLength; i++) {
+ argumentsText += sep +
+ _rtiToString(_castToRti(_Utils.arrayAt(optionalPositional, i)),
+ genericContext);
+ sep = ', ';
+ }
+ argumentsText += ']';
+ }
+
+ if (optionalNamedLength > 0) {
+ argumentsText += sep + '{';
+ sep = '';
+ for (int i = 0; i < optionalNamedLength; i += 2) {
+ argumentsText += sep +
+ _rtiToString(_castToRti(_Utils.arrayAt(optionalNamed, i + 1)),
+ genericContext) +
+ ' ' +
+ _Utils.asString(_Utils.arrayAt(optionalNamed, i));
+ sep = ', ';
+ }
+ argumentsText += '}';
+ }
+
+ if (outerContextLength != null) {
+ // Pop all of the generic type parameters.
+ JS('', '#.length = #', genericContext, outerContextLength);
+ }
+
+ // TODO(fishythefish): Below is the same format as the VM. Change to:
+ //
+ // return '${returnTypeText} Function${typeParametersText}(${argumentsText})';
+ //
+ return '${typeParametersText}(${argumentsText}) => ${returnTypeText}';
+}
+
+String _rtiToString(Rti rti, List<String> genericContext) {
+ int kind = Rti._getKind(rti);
+
+ if (kind == Rti.kindDynamic) return 'dynamic';
+ if (kind == Rti.kindVoid) return 'void';
+ if (kind == Rti.kindNever) return 'Never';
+ if (kind == Rti.kindAny) return 'any';
+
+ if (kind == Rti.kindStar) {
+ Rti starArgument = Rti._getStarArgument(rti);
+ return '${_rtiToString(starArgument, genericContext)}*';
+ }
+
+ if (kind == Rti.kindQuestion) {
+ Rti questionArgument = Rti._getQuestionArgument(rti);
+ return '${_rtiToString(questionArgument, genericContext)}?';
+ }
+
+ if (kind == Rti.kindFutureOr) {
+ Rti futureOrArgument = Rti._getFutureOrArgument(rti);
+ return 'FutureOr<${_rtiToString(futureOrArgument, genericContext)}>';
+ }
+
+ if (kind == Rti.kindInterface) {
+ String name = Rti._getInterfaceName(rti);
+ name = _unminifyOrTag(name);
+ var arguments = Rti._getInterfaceTypeArguments(rti);
+ if (arguments.length != 0) {
+ name += '<' + _rtiArrayToString(arguments, genericContext) + '>';
+ }
+ return name;
+ }
+
+ if (kind == Rti.kindFunction) {
+ return _functionRtiToString(rti, genericContext);
+ }
+
+ if (kind == Rti.kindGenericFunction) {
+ Rti baseFunctionType = Rti._getGenericFunctionBase(rti);
+ Object bounds = Rti._getGenericFunctionBounds(rti);
+ return _functionRtiToString(baseFunctionType, genericContext,
+ bounds: bounds);
+ }
+
+ if (kind == Rti.kindGenericFunctionParameter) {
+ int index = Rti._getGenericFunctionParameterIndex(rti);
+ return genericContext[genericContext.length - 1 - index];
+ }
+
+ return '?';
+}
+
+String _unminifyOrTag(String rawClassName) {
+ String preserved = unmangleGlobalNameIfPreservedAnyways(rawClassName);
+ if (preserved != null) return preserved;
+ return JS_GET_FLAG('MINIFIED') ? 'minified:$rawClassName' : rawClassName;
+}
+
+String _rtiArrayToDebugString(Object array) {
+ String s = '[', sep = '';
+ for (int i = 0; i < _Utils.arrayLength(array); i++) {
+ s += sep + _rtiToDebugString(_castToRti(_Utils.arrayAt(array, i)));
+ sep = ', ';
+ }
+ return s + ']';
+}
+
+String functionParametersToString(_FunctionParameters parameters) {
+ // TODO(fishythefish): Support required named parameters.
+ String s = '(', sep = '';
+ var requiredPositional =
+ _FunctionParameters._getRequiredPositional(parameters);
+ int requiredPositionalLength = _Utils.arrayLength(requiredPositional);
+ var optionalPositional =
+ _FunctionParameters._getOptionalPositional(parameters);
+ int optionalPositionalLength = _Utils.arrayLength(optionalPositional);
+ var optionalNamed = _FunctionParameters._getOptionalNamed(parameters);
+ int optionalNamedLength = _Utils.arrayLength(optionalNamed);
+ assert(optionalPositionalLength == 0 || optionalNamedLength == 0);
+
+ for (int i = 0; i < requiredPositionalLength; i++) {
+ s += sep +
+ _rtiToDebugString(_castToRti(_Utils.arrayAt(requiredPositional, i)));
+ sep = ', ';
+ }
+
+ if (optionalPositionalLength > 0) {
+ s += sep + '[';
+ sep = '';
+ for (int i = 0; i < optionalPositionalLength; i++) {
+ s += sep +
+ _rtiToDebugString(_castToRti(_Utils.arrayAt(optionalPositional, i)));
+ sep = ', ';
+ }
+ s += ']';
+ }
+
+ if (optionalNamedLength > 0) {
+ s += sep + '{';
+ sep = '';
+ for (int i = 0; i < optionalNamedLength; i += 2) {
+ s += sep +
+ _rtiToDebugString(_castToRti(_Utils.arrayAt(optionalNamed, i + 1))) +
+ ' ' +
+ _Utils.asString(_Utils.arrayAt(optionalNamed, i));
+ sep = ', ';
+ }
+ s += '}';
+ }
+
+ return s + ')';
+}
+
+String _rtiToDebugString(Rti rti) {
+ int kind = Rti._getKind(rti);
+
+ if (kind == Rti.kindDynamic) return 'dynamic';
+ if (kind == Rti.kindVoid) return 'void';
+ if (kind == Rti.kindNever) return 'Never';
+ if (kind == Rti.kindAny) return 'any';
+
+ if (kind == Rti.kindStar) {
+ Rti starArgument = Rti._getStarArgument(rti);
+ return 'star(${_rtiToDebugString(starArgument)})';
+ }
+
+ if (kind == Rti.kindQuestion) {
+ Rti questionArgument = Rti._getQuestionArgument(rti);
+ return 'question(${_rtiToDebugString(questionArgument)})';
+ }
+
+ if (kind == Rti.kindFutureOr) {
+ Rti futureOrArgument = Rti._getFutureOrArgument(rti);
+ return 'FutureOr(${_rtiToDebugString(futureOrArgument)})';
+ }
+
+ if (kind == Rti.kindInterface) {
+ String name = Rti._getInterfaceName(rti);
+ var arguments = Rti._getInterfaceTypeArguments(rti);
+ if (_Utils.arrayLength(arguments) == 0) {
+ return 'interface("$name")';
+ } else {
+ return 'interface("$name", ${_rtiArrayToDebugString(arguments)})';
+ }
+ }
+
+ if (kind == Rti.kindBinding) {
+ Rti base = Rti._getBindingBase(rti);
+ var arguments = Rti._getBindingArguments(rti);
+ return 'binding(${_rtiToDebugString(base)}, ${_rtiArrayToDebugString(arguments)})';
+ }
+
+ if (kind == Rti.kindFunction) {
+ Rti returnType = Rti._getReturnType(rti);
+ _FunctionParameters parameters = Rti._getFunctionParameters(rti);
+ return 'function(${_rtiToDebugString(returnType)}, ${functionParametersToString(parameters)})';
+ }
+
+ if (kind == Rti.kindGenericFunction) {
+ Rti baseFunctionType = Rti._getGenericFunctionBase(rti);
+ Object bounds = Rti._getGenericFunctionBounds(rti);
+ return 'genericFunction(${_rtiToDebugString(baseFunctionType)}, ${_rtiArrayToDebugString(bounds)})';
+ }
+
+ if (kind == Rti.kindGenericFunctionParameter) {
+ int index = Rti._getGenericFunctionParameterIndex(rti);
+ return 'genericFunctionParameter($index)';
+ }
+
+ return 'other(kind=$kind)';
+}
+
+/// Class of static methods for the universe of Rti objects.
+///
+/// The universe is the manager object for the Rti instances.
+///
+/// The universe itself is allocated at startup before any types or Dart objects
+/// can be created, so it does not have a Dart type.
+class _Universe {
+ _Universe._() {
+ throw UnimplementedError('_Universe is static methods only');
+ }
+
+ @pragma('dart2js:noInline')
+ static Object create() {
+ // This needs to be kept in sync with `FragmentEmitter.createRtiUniverse` in
+ // `fragment_emitter.dart`.
+ return JS(
+ '',
+ '{'
+ '#: new Map(),'
+ '#: {},'
+ '#: [],' // shared empty array.
+ '}',
+ RtiUniverseFieldNames.evalCache,
+ RtiUniverseFieldNames.typeRules,
+ RtiUniverseFieldNames.sharedEmptyArray);
+ }
+
+ // Field accessors.
+
+ static evalCache(universe) =>
+ JS('', '#.#', universe, RtiUniverseFieldNames.evalCache);
+
+ static Object typeRules(universe) =>
+ JS('', '#.#', universe, RtiUniverseFieldNames.typeRules);
+
+ static Object findRule(universe, String targetType) =>
+ JS('', '#.#', typeRules(universe), targetType);
+
+ static void addRules(universe, rules) {
+ // TODO(fishythefish): Use `Object.assign()` when IE11 is deprecated.
+ var keys = JS('JSArray', 'Object.keys(#)', rules);
+ int length = _Utils.arrayLength(keys);
+ Object ruleset = typeRules(universe);
+ for (int i = 0; i < length; i++) {
+ String targetType = _Utils.asString(_Utils.arrayAt(keys, i));
+ JS('', '#[#] = #[#]', ruleset, targetType, rules, targetType);
+ }
+ }
+
+ static Object sharedEmptyArray(universe) =>
+ JS('JSArray', '#.#', universe, RtiUniverseFieldNames.sharedEmptyArray);
+
+ /// Evaluates [recipe] in the global environment.
+ static Rti eval(Object universe, String recipe) {
+ var cache = evalCache(universe);
+ var probe = _cacheGet(cache, recipe);
+ if (probe != null) return _castToRti(probe);
+ Rti rti = _parseRecipe(universe, null, recipe);
+ _cacheSet(cache, recipe, rti);
+ return rti;
+ }
+
+ static Rti evalInEnvironment(
+ Object universe, Rti environment, String recipe) {
+ var cache = Rti._getEvalCache(environment);
+ if (cache == null) {
+ cache = JS('', 'new Map()');
+ Rti._setEvalCache(environment, cache);
+ }
+ var probe = _cacheGet(cache, recipe);
+ if (probe != null) return _castToRti(probe);
+ Rti rti = _parseRecipe(universe, environment, recipe);
+ _cacheSet(cache, recipe, rti);
+ return rti;
+ }
+
+ static Rti bind(Object universe, Rti environment, Rti argumentsRti) {
+ var cache = Rti._getBindCache(environment);
+ if (cache == null) {
+ cache = JS('', 'new Map()');
+ Rti._setBindCache(environment, cache);
+ }
+ String argumentsRecipe = Rti._getCanonicalRecipe(argumentsRti);
+ var probe = _cacheGet(cache, argumentsRecipe);
+ if (probe != null) return _castToRti(probe);
+ var argumentsArray;
+ if (Rti._getKind(argumentsRti) == Rti.kindBinding) {
+ argumentsArray = Rti._getBindingArguments(argumentsRti);
+ } else {
+ argumentsArray = JS('', '[#]', argumentsRti);
+ }
+ Rti rti = _lookupBindingRti(universe, environment, argumentsArray);
+ _cacheSet(cache, argumentsRecipe, rti);
+ return rti;
+ }
+
+ static Rti bind1(Object universe, Rti environment, Rti argumentsRti) {
+ throw UnimplementedError('_Universe.bind1');
+ }
+
+ static Rti evalTypeVariable(Object universe, Rti environment, String name) {
+ if (Rti._getKind(environment) == Rti.kindBinding) {
+ environment = Rti._getBindingBase(environment);
+ }
+
+ assert(Rti._getKind(environment) == Rti.kindInterface);
+ String interfaceName = Rti._getInterfaceName(environment);
+ Object rule = _Universe.findRule(universe, interfaceName);
+ assert(rule != null);
+ String recipe = TypeRule.lookupTypeVariable(rule, name);
+ return _Universe.evalInEnvironment(universe, environment, recipe);
+ }
+
+ static _cacheGet(cache, key) => JS('', '#.get(#)', cache, key);
+ static void _cacheSet(cache, key, value) {
+ JS('', '#.set(#, #)', cache, key, value);
+ }
+
+ static Rti _parseRecipe(Object universe, Object environment, String recipe) {
+ Object parser = _Parser.create(universe, environment, recipe);
+ Rti rti = _Parser.parse(parser);
+ if (rti != null) return rti;
+ throw UnimplementedError('_Universe._parseRecipe("$recipe")');
+ }
+
+ static Rti _finishRti(Object universe, Rti rti) {
+ // Enter fresh Rti in global table under it's canonical recipe.
+ String key = Rti._getCanonicalRecipe(rti);
+ _cacheSet(evalCache(universe), key, rti);
+
+ // Set up methods to perform type tests.
+
+ // TODO(sra): Find better way to install specializations. Perhaps the
+ // installed version should replace itself with the specialization.
+ var checkFn = RAW_DART_FUNCTION_REF(_generalTypeCheckImplementation);
+ var asFn = RAW_DART_FUNCTION_REF(_generalAsCheckImplementation);
+ var isFn = RAW_DART_FUNCTION_REF(_generalIsTestImplementation);
+
+ if (JS_GET_NAME(JsGetName.INT_RECIPE) == key) {
+ isFn = RAW_DART_FUNCTION_REF(_isInt);
+ } else if (JS_GET_NAME(JsGetName.DOUBLE_RECIPE) == key) {
+ isFn = RAW_DART_FUNCTION_REF(_isNum);
+ } else if (JS_GET_NAME(JsGetName.NUM_RECIPE) == key) {
+ isFn = RAW_DART_FUNCTION_REF(_isNum);
+ } else if (JS_GET_NAME(JsGetName.STRING_RECIPE) == key) {
+ isFn = RAW_DART_FUNCTION_REF(_isString);
+ } else if (JS_GET_NAME(JsGetName.BOOL_RECIPE) == key) {
+ isFn = RAW_DART_FUNCTION_REF(_isBool);
+ }
+
+ Rti._setAsCheckFunction(rti, asFn);
+ Rti._setTypeCheckFunction(rti, checkFn);
+ Rti._setIsTestFunction(rti, isFn);
+ return rti;
+ }
+
+ // For each kind of Rti there are three methods:
+ //
+ // * `lookupXXX` which takes the component parts and returns an existing Rti
+ // object if it exists.
+ // * `canonicalRecipeOfXXX` that returns the compositional canonical recipe
+ // for the proposed type.
+ // * `createXXX` to create the type if it does not exist.
+
+ static String _canonicalRecipeOfDynamic() => Recipe.pushDynamicString;
+ static String _canonicalRecipeOfVoid() => Recipe.pushVoidString;
+ static String _canonicalRecipeOfNever() =>
+ Recipe.pushNeverExtensionString + Recipe.extensionOpString;
+ static String _canonicalRecipeOfAny() =>
+ Recipe.pushAnyExtensionString + Recipe.extensionOpString;
+
+ static String _canonicalRecipeOfStar(Rti baseType) =>
+ Rti._getCanonicalRecipe(baseType) + Recipe.wrapStarString;
+ static String _canonicalRecipeOfQuestion(Rti baseType) =>
+ Rti._getCanonicalRecipe(baseType) + Recipe.wrapQuestionString;
+ static String _canonicalRecipeOfFutureOr(Rti baseType) =>
+ Rti._getCanonicalRecipe(baseType) + Recipe.wrapFutureOrString;
+
+ static String _canonicalRecipeOfGenericFunctionParameter(int index) =>
+ '$index' + Recipe.genericFunctionTypeParameterIndexString;
+
+ static Rti _lookupDynamicRti(universe) {
+ return _lookupTerminalRti(
+ universe, Rti.kindDynamic, _canonicalRecipeOfDynamic());
+ }
+
+ static Rti _lookupVoidRti(universe) {
+ return _lookupTerminalRti(universe, Rti.kindVoid, _canonicalRecipeOfVoid());
+ }
+
+ static Rti _lookupNeverRti(universe) {
+ return _lookupTerminalRti(
+ universe, Rti.kindNever, _canonicalRecipeOfNever());
+ }
+
+ static Rti _lookupAnyRti(universe) {
+ return _lookupTerminalRti(universe, Rti.kindAny, _canonicalRecipeOfAny());
+ }
+
+ static Rti _lookupTerminalRti(universe, int kind, String canonicalRecipe) {
+ var cache = evalCache(universe);
+ var probe = _cacheGet(cache, canonicalRecipe);
+ if (probe != null) return _castToRti(probe);
+ return _createTerminalRti(universe, kind, canonicalRecipe);
+ }
+
+ static Rti _createTerminalRti(universe, int kind, String canonicalRecipe) {
+ Rti rti = Rti.allocate();
+ Rti._setKind(rti, kind);
+ Rti._setCanonicalRecipe(rti, canonicalRecipe);
+ return _finishRti(universe, rti);
+ }
+
+ static Rti _lookupStarRti(universe, Rti baseType) => _lookupUnaryRti(
+ universe, Rti.kindStar, baseType, _canonicalRecipeOfStar(baseType));
+
+ static Rti _lookupQuestionRti(universe, Rti baseType) => _lookupUnaryRti(
+ universe,
+ Rti.kindQuestion,
+ baseType,
+ _canonicalRecipeOfQuestion(baseType));
+
+ static Rti _lookupFutureOrRti(universe, Rti baseType) => _lookupUnaryRti(
+ universe,
+ Rti.kindFutureOr,
+ baseType,
+ _canonicalRecipeOfFutureOr(baseType));
+
+ static Rti _lookupUnaryRti(
+ universe, int kind, Rti baseType, String canonicalRecipe) {
+ var cache = evalCache(universe);
+ var probe = _cacheGet(cache, canonicalRecipe);
+ if (probe != null) return _castToRti(probe);
+ return _createUnaryRti(universe, kind, baseType, canonicalRecipe);
+ }
+
+ static Rti _createUnaryRti(
+ universe, int kind, Rti baseType, String canonicalRecipe) {
+ Rti rti = Rti.allocate();
+ Rti._setKind(rti, kind);
+ Rti._setPrimary(rti, baseType);
+ Rti._setCanonicalRecipe(rti, canonicalRecipe);
+ return _finishRti(universe, rti);
+ }
+
+ static Rti _lookupGenericFunctionParameterRti(universe, int index) {
+ String canonicalRecipe = _canonicalRecipeOfGenericFunctionParameter(index);
+ var cache = evalCache(universe);
+ var probe = _cacheGet(cache, canonicalRecipe);
+ if (probe != null) return _castToRti(probe);
+ return _createGenericFunctionParameterRti(universe, index, canonicalRecipe);
+ }
+
+ static Rti _createGenericFunctionParameterRti(
+ universe, int index, String canonicalRecipe) {
+ Rti rti = Rti.allocate();
+ Rti._setKind(rti, Rti.kindGenericFunctionParameter);
+ Rti._setPrimary(rti, index);
+ Rti._setCanonicalRecipe(rti, canonicalRecipe);
+ return _finishRti(universe, rti);
+ }
+
+ static String _canonicalRecipeJoin(Object arguments) {
+ String s = '', sep = '';
+ int length = _Utils.arrayLength(arguments);
+ for (int i = 0; i < length; i++) {
+ Rti argument = _castToRti(_Utils.arrayAt(arguments, i));
+ String subrecipe = Rti._getCanonicalRecipe(argument);
+ s += sep + subrecipe;
+ sep = Recipe.separatorString;
+ }
+ return s;
+ }
+
+ static String _canonicalRecipeJoinNamed(Object arguments) {
+ String s = '', sep = '';
+ int length = _Utils.arrayLength(arguments);
+ assert(length.isEven);
+ for (int i = 0; i < length; i += 2) {
+ String name = _Utils.asString(_Utils.arrayAt(arguments, i));
+ Rti type = _castToRti(_Utils.arrayAt(arguments, i + 1));
+ String subrecipe = Rti._getCanonicalRecipe(type);
+ s += sep + name + Recipe.nameSeparatorString + subrecipe;
+ sep = Recipe.separatorString;
+ }
+ return s;
+ }
+
+ static String _canonicalRecipeOfInterface(String name, Object arguments) {
+ assert(_Utils.isString(name));
+ String s = _Utils.asString(name);
+ int length = _Utils.arrayLength(arguments);
+ if (length != 0) {
+ s += Recipe.startTypeArgumentsString +
+ _canonicalRecipeJoin(arguments) +
+ Recipe.endTypeArgumentsString;
+ }
+ return s;
+ }
+
+ static Rti _lookupInterfaceRti(
+ Object universe, String name, Object arguments) {
+ String key = _canonicalRecipeOfInterface(name, arguments);
+ var cache = evalCache(universe);
+ var probe = _cacheGet(cache, key);
+ if (probe != null) return _castToRti(probe);
+ return _createInterfaceRti(universe, name, arguments, key);
+ }
+
+ static Rti _createInterfaceRti(
+ Object universe, String name, Object typeArguments, String key) {
+ Rti rti = Rti.allocate();
+ Rti._setKind(rti, Rti.kindInterface);
+ Rti._setPrimary(rti, name);
+ Rti._setRest(rti, typeArguments);
+ Rti._setCanonicalRecipe(rti, key);
+ return _finishRti(universe, rti);
+ }
+
+ static String _canonicalRecipeOfBinding(Rti base, Object arguments) {
+ String s = Rti._getCanonicalRecipe(base);
+ s += Recipe
+ .toTypeString; // TODO(sra): Omit when base encoding is Rti without ToType.
+ s += Recipe.startTypeArgumentsString +
+ _canonicalRecipeJoin(arguments) +
+ Recipe.endTypeArgumentsString;
+ return s;
+ }
+
+ /// [arguments] becomes owned by the created Rti.
+ static Rti _lookupBindingRti(Object universe, Rti base, Object arguments) {
+ Rti newBase = base;
+ Object newArguments = arguments;
+ if (Rti._getKind(base) == Rti.kindBinding) {
+ newBase = Rti._getBindingBase(base);
+ newArguments =
+ _Utils.arrayConcat(Rti._getBindingArguments(base), arguments);
+ }
+ String key = _canonicalRecipeOfBinding(newBase, newArguments);
+ var cache = evalCache(universe);
+ var probe = _cacheGet(cache, key);
+ if (probe != null) return _castToRti(probe);
+ return _createBindingRti(universe, newBase, newArguments, key);
+ }
+
+ static Rti _createBindingRti(
+ Object universe, Rti base, Object arguments, String key) {
+ Rti rti = Rti.allocate();
+ Rti._setKind(rti, Rti.kindBinding);
+ Rti._setPrimary(rti, base);
+ Rti._setRest(rti, arguments);
+ Rti._setCanonicalRecipe(rti, key);
+ return _finishRti(universe, rti);
+ }
+
+ static String _canonicalRecipeOfFunction(
+ Rti returnType, _FunctionParameters parameters) =>
+ Rti._getCanonicalRecipe(returnType) +
+ _canonicalRecipeOfFunctionParameters(parameters);
+
+ // TODO(fishythefish): Support required named parameters.
+ static String _canonicalRecipeOfFunctionParameters(
+ _FunctionParameters parameters) {
+ var requiredPositional =
+ _FunctionParameters._getRequiredPositional(parameters);
+ int requiredPositionalLength = _Utils.arrayLength(requiredPositional);
+ var optionalPositional =
+ _FunctionParameters._getOptionalPositional(parameters);
+ int optionalPositionalLength = _Utils.arrayLength(optionalPositional);
+ var optionalNamed = _FunctionParameters._getOptionalNamed(parameters);
+ int optionalNamedLength = _Utils.arrayLength(optionalNamed);
+ assert(optionalPositionalLength == 0 || optionalNamedLength == 0);
+
+ String recipe = Recipe.startFunctionArgumentsString +
+ _canonicalRecipeJoin(requiredPositional);
+
+ if (optionalPositionalLength > 0) {
+ String sep = requiredPositionalLength > 0 ? Recipe.separatorString : '';
+ recipe += sep +
+ Recipe.startOptionalGroupString +
+ _canonicalRecipeJoin(optionalPositional) +
+ Recipe.endOptionalGroupString;
+ }
+
+ if (optionalNamedLength > 0) {
+ String sep = requiredPositionalLength > 0 ? Recipe.separatorString : '';
+ recipe += sep +
+ Recipe.startNamedGroupString +
+ _canonicalRecipeJoinNamed(optionalNamed) +
+ Recipe.endNamedGroupString;
+ }
+
+ return recipe + Recipe.endFunctionArgumentsString;
+ }
+
+ static Rti _lookupFunctionRti(
+ Object universe, Rti returnType, _FunctionParameters parameters) {
+ String key = _canonicalRecipeOfFunction(returnType, parameters);
+ var cache = evalCache(universe);
+ var probe = _cacheGet(cache, key);
+ if (probe != null) return _castToRti(probe);
+ return _createFunctionRti(universe, returnType, parameters, key);
+ }
+
+ static Rti _createFunctionRti(Object universe, Rti returnType,
+ _FunctionParameters parameters, String canonicalRecipe) {
+ Rti rti = Rti.allocate();
+ Rti._setKind(rti, Rti.kindFunction);
+ Rti._setPrimary(rti, returnType);
+ Rti._setRest(rti, parameters);
+ Rti._setCanonicalRecipe(rti, canonicalRecipe);
+ return _finishRti(universe, rti);
+ }
+
+ static String _canonicalRecipeOfGenericFunction(
+ Rti baseFunctionType, Object bounds) =>
+ Rti._getCanonicalRecipe(baseFunctionType) +
+ Recipe.startTypeArgumentsString +
+ _canonicalRecipeJoin(bounds) +
+ Recipe.endTypeArgumentsString;
+
+ static Rti _lookupGenericFunctionRti(
+ Object universe, Rti baseFunctionType, Object bounds) {
+ String key = _canonicalRecipeOfGenericFunction(baseFunctionType, bounds);
+ var cache = evalCache(universe);
+ var probe = _cacheGet(cache, key);
+ if (probe != null) return _castToRti(probe);
+ return _createGenericFunctionRti(universe, baseFunctionType, bounds, key);
+ }
+
+ static Rti _createGenericFunctionRti(Object universe, Rti baseFunctionType,
+ Object bounds, String canonicalRecipe) {
+ Rti rti = Rti.allocate();
+ Rti._setKind(rti, Rti.kindGenericFunction);
+ Rti._setPrimary(rti, baseFunctionType);
+ Rti._setRest(rti, bounds);
+ Rti._setCanonicalRecipe(rti, canonicalRecipe);
+ return _finishRti(universe, rti);
+ }
+}
+
+/// Class of static methods implementing recipe parser.
+///
+/// The recipe is a sequence of operations on a stack machine. The operations
+/// are described below using the format
+///
+/// operation: stack elements before --- stack elements after
+///
+/// integer: --- integer-value
+///
+/// identifier: --- string-value
+///
+/// identifier-with-one-period: --- type-variable-value
+///
+/// Period may be in any position, including first and last e.g. `.x`.
+///
+/// ',': ---
+///
+/// Ignored. Used to separate elements.
+///
+/// ';': item --- ToType(item)
+///
+/// Used to separate elements.
+///
+/// '@': --- dynamicType
+///
+/// '~': --- voidType
+///
+/// '?': type --- type?
+///
+/// '&': 0 --- NeverType
+/// '&': 1 --- anyType
+///
+/// Escape op-code with small integer values for encoding rare operations.
+///
+/// '<': --- position
+///
+/// Saves (pushes) position register, sets position register to end of stack.
+///
+/// '>': name saved-position type ... type --- name<type, ..., type>
+/// '>': type saved-position type ... type --- binding(type, type, ..., type)
+///
+/// When first element is a String: Creates interface type from string 'name'
+/// and the types pushed since the position register was last set. The types
+/// are converted with a ToType operation. Restores position register to
+/// previous saved value.
+///
+/// When first element is an Rti: Creates binding Rti wrapping the first
+/// element. Binding Rtis are flattened: if the first element is a binding
+/// Rti, the new binding Rti has the concatentation of the first element
+/// bindings and new type.
+///
+///
+/// The ToType operation coerces an item to an Rti. This saves encoding looking
+/// up simple interface names and indexed variables.
+///
+/// ToType(string): Creates an interface Rti for the non-generic class.
+/// ToType(integer): Indexes into the environment.
+/// ToType(Rti): Same Rti
+///
+///
+/// Notes on enviroments and indexing.
+///
+/// To avoid creating a binding Rti for a single function type parameter, the
+/// type is passed without creating a 1-tuple object. This means that the
+/// interface Rti for, say, `Map<num,dynamic>` serves as two environments with
+/// different shapes. It is a class environment (K=num, V=dynamic) and a simple
+/// 1-tuple environment. This is supported by index '0' refering to the whole
+/// type, and '1 and '2' refering to K and V positionally:
+///
+/// interface("Map", [num,dynamic])
+/// 0 1 2
+///
+/// Thus the type expression `List<K>` encodes as `List<1>` and in this
+/// environment evaluates to `List<num>`. `List<Map<K,V>>` could be encoded as
+/// either `List<0>` or `List<Map<1,2>>` (and in this environment evaluates to
+/// `List<Map<num,dynamic>>`).
+///
+/// When `Map<num,dynamic>` is combined with a binding `<int,bool>` (e.g. inside
+/// the instance method `Map<K,V>.cast<RK,RV>()`), '0' refers to the base object
+/// of the binding, and then the numbering counts the bindings followed by the
+/// class parameters.
+///
+/// binding(interface("Map", [num,dynamic]), [int, bool])
+/// 0 3 4 1 2
+///
+/// Any environment can be reconstructed via a recipe. The above enviroment for
+/// method `cast` can be constructed as the ground term
+/// `Map<num,dynamic><int,bool>`, or (somewhat pointlessly) reconstructed via
+/// `0<1,2>` or `Map<3,4><1,2>`. The ability to construct an environment
+/// directly rather than via `bind` calls is used in folding sequences of `eval`
+/// and `bind` calls.
+///
+/// While a single type parameter is passed as the type, multiple type
+/// parameters are passed as a tuple. Tuples are encoded as a binding with an
+/// ignored base. `dynamic` can be used as the base, giving an encoding like
+/// `@<int,bool>`.
+///
+/// Bindings flatten, so `@<int><bool><num>` is the same as `@<int,bool,num>`.
+///
+/// The base of a binding does not have to have type parameters. Consider
+/// `CodeUnits`, which mixes in `ListMixin<int>`. The environment inside of
+/// `ListMixin.fold` (from the call `x.codeUnits.fold<bool>(...)`) would be
+///
+/// binding(interface("CodeUnits", []), [bool])
+///
+/// This can be encoded as `CodeUnits;<bool>` (note the `;` to force ToType to
+/// avoid creating an interface type Rti with a single class type
+/// argument). Metadata about the supertypes is used to resolve the recipe
+/// `ListMixin.E` to `int`.
+
+class _Parser {
+ _Parser._() {
+ throw UnimplementedError('_Parser is static methods only');
+ }
+
+ /// Creates a parser object for parsing a recipe against an environment in a
+ /// universe.
+ ///
+ /// Marked as no-inline so the object literal is not cloned by inlining.
+ @pragma('dart2js:noInline')
+ static Object create(Object universe, Object environment, String recipe) {
+ return JS(
+ '',
+ '{'
+ 'u:#,' // universe
+ 'e:#,' // environment
+ 'r:#,' // recipe
+ 's:[],' // stack
+ 'p:0,' // position of sequence start.
+ '}',
+ universe,
+ environment,
+ recipe);
+ }
+
+ // Field accessors for the parser.
+ static Object universe(Object parser) => JS('', '#.u', parser);
+ static Rti environment(Object parser) => JS('Rti', '#.e', parser);
+ static String recipe(Object parser) => JS('String', '#.r', parser);
+ static Object stack(Object parser) => JS('', '#.s', parser);
+ static int position(Object parser) => JS('int', '#.p', parser);
+ static void setPosition(Object parser, int p) {
+ JS('', '#.p = #', parser, p);
+ }
+
+ static int charCodeAt(String s, int i) => JS('int', '#.charCodeAt(#)', s, i);
+ static void push(Object stack, Object value) {
+ JS('', '#.push(#)', stack, value);
+ }
+
+ static Object pop(Object stack) => JS('', '#.pop()', stack);
+
+ static Rti parse(Object parser) {
+ String source = _Parser.recipe(parser);
+ Object stack = _Parser.stack(parser);
+ int i = 0;
+ while (i < source.length) {
+ int ch = charCodeAt(source, i);
+ if (Recipe.isDigit(ch)) {
+ i = handleDigit(i + 1, ch, source, stack);
+ } else if (Recipe.isIdentifierStart(ch)) {
+ i = handleIdentifer(parser, i, source, stack, false);
+ } else if (ch == Recipe.period) {
+ i = handleIdentifer(parser, i, source, stack, true);
+ } else {
+ i++;
+ switch (ch) {
+ case Recipe.separator:
+ break;
+
+ case Recipe.nameSeparator:
+ break;
+
+ case Recipe.toType:
+ push(stack,
+ toType(universe(parser), environment(parser), pop(stack)));
+ break;
+
+ case Recipe.genericFunctionTypeParameterIndex:
+ push(stack,
+ toGenericFunctionParameter(universe(parser), pop(stack)));
+ break;
+
+ case Recipe.pushDynamic:
+ push(stack, _Universe._lookupDynamicRti(universe(parser)));
+ break;
+
+ case Recipe.pushVoid:
+ push(stack, _Universe._lookupVoidRti(universe(parser)));
+ break;
+
+ case Recipe.startTypeArguments:
+ pushStackFrame(parser, stack);
+ break;
+
+ case Recipe.endTypeArguments:
+ handleTypeArguments(parser, stack);
+ break;
+
+ case Recipe.extensionOp:
+ handleExtendedOperations(parser, stack);
+ break;
+
+ case Recipe.wrapStar:
+ Object u = universe(parser);
+ push(
+ stack,
+ _Universe._lookupStarRti(
+ u, toType(u, environment(parser), pop(stack))));
+ break;
+
+ case Recipe.wrapQuestion:
+ Object u = universe(parser);
+ push(
+ stack,
+ _Universe._lookupQuestionRti(
+ u, toType(u, environment(parser), pop(stack))));
+ break;
+
+ case Recipe.wrapFutureOr:
+ Object u = universe(parser);
+ push(
+ stack,
+ _Universe._lookupFutureOrRti(
+ u, toType(u, environment(parser), pop(stack))));
+ break;
+
+ case Recipe.startFunctionArguments:
+ pushStackFrame(parser, stack);
+ break;
+
+ case Recipe.endFunctionArguments:
+ handleFunctionArguments(parser, stack);
+ break;
+
+ case Recipe.startOptionalGroup:
+ pushStackFrame(parser, stack);
+ break;
+
+ case Recipe.endOptionalGroup:
+ handleOptionalGroup(parser, stack);
+ break;
+
+ case Recipe.startNamedGroup:
+ pushStackFrame(parser, stack);
+ break;
+
+ case Recipe.endNamedGroup:
+ handleNamedGroup(parser, stack);
+ break;
+
+ default:
+ JS('', 'throw "Bad character " + #', ch);
+ }
+ }
+ }
+ Object item = pop(stack);
+ return toType(universe(parser), environment(parser), item);
+ }
+
+ static void pushStackFrame(Object parser, Object stack) {
+ push(stack, position(parser));
+ setPosition(parser, _Utils.arrayLength(stack));
+ }
+
+ static int handleDigit(int i, int digit, String source, Object stack) {
+ int value = Recipe.digitValue(digit);
+ for (; i < source.length; i++) {
+ int ch = charCodeAt(source, i);
+ if (!Recipe.isDigit(ch)) break;
+ value = value * 10 + Recipe.digitValue(ch);
+ }
+ push(stack, value);
+ return i;
+ }
+
+ static int handleIdentifer(
+ Object parser, int start, String source, Object stack, bool hasPeriod) {
+ int i = start + 1;
+ for (; i < source.length; i++) {
+ int ch = charCodeAt(source, i);
+ if (ch == Recipe.period) {
+ if (hasPeriod) break;
+ hasPeriod = true;
+ } else if (Recipe.isIdentifierStart(ch) || Recipe.isDigit(ch)) {
+ // Accept.
+ } else {
+ break;
+ }
+ }
+ String string = _Utils.substring(source, start, i);
+ if (hasPeriod) {
+ push(
+ stack,
+ _Universe.evalTypeVariable(
+ universe(parser), environment(parser), string));
+ } else {
+ push(stack, string);
+ }
+ return i;
+ }
+
+ static void handleTypeArguments(Object parser, Object stack) {
+ Object universe = _Parser.universe(parser);
+ Object arguments = collectArray(parser, stack);
+ Object head = pop(stack);
+ if (_Utils.isString(head)) {
+ String name = _Utils.asString(head);
+ push(stack, _Universe._lookupInterfaceRti(universe, name, arguments));
+ } else {
+ Rti base = toType(universe, environment(parser), head);
+ switch (Rti._getKind(base)) {
+ case Rti.kindFunction:
+ push(stack,
+ _Universe._lookupGenericFunctionRti(universe, base, arguments));
+ break;
+
+ default:
+ push(stack, _Universe._lookupBindingRti(universe, base, arguments));
+ break;
+ }
+ }
+ }
+
+ static const int optionalPositionalSentinel = -1;
+ static const int optionalNamedSentinel = -2;
+
+ static void handleFunctionArguments(Object parser, Object stack) {
+ Object universe = _Parser.universe(parser);
+ _FunctionParameters parameters = _FunctionParameters.allocate();
+ var optionalPositional = _Universe.sharedEmptyArray(universe);
+ var optionalNamed = _Universe.sharedEmptyArray(universe);
+
+ Object head = pop(stack);
+ if (_Utils.isNum(head)) {
+ int sentinel = _Utils.asInt(head);
+ switch (sentinel) {
+ case optionalPositionalSentinel:
+ optionalPositional = pop(stack);
+ break;
+
+ case optionalNamedSentinel:
+ optionalNamed = pop(stack);
+ break;
+
+ default:
+ push(stack, head);
+ break;
+ }
+ } else {
+ push(stack, head);
+ }
+
+ _FunctionParameters._setRequiredPositional(
+ parameters, collectArray(parser, stack));
+ _FunctionParameters._setOptionalPositional(parameters, optionalPositional);
+ _FunctionParameters._setOptionalNamed(parameters, optionalNamed);
+ Rti returnType = toType(universe, environment(parser), pop(stack));
+ push(stack, _Universe._lookupFunctionRti(universe, returnType, parameters));
+ }
+
+ static void handleOptionalGroup(Object parser, Object stack) {
+ Object parameters = collectArray(parser, stack);
+ push(stack, parameters);
+ push(stack, optionalPositionalSentinel);
+ }
+
+ static void handleNamedGroup(Object parser, Object stack) {
+ Object parameters = collectNamed(parser, stack);
+ push(stack, parameters);
+ push(stack, optionalNamedSentinel);
+ }
+
+ static void handleExtendedOperations(Object parser, Object stack) {
+ Object top = pop(stack);
+ if (0 == top) {
+ push(stack, _Universe._lookupNeverRti(universe(parser)));
+ return;
+ }
+ if (1 == top) {
+ push(stack, _Universe._lookupAnyRti(universe(parser)));
+ return;
+ }
+ throw AssertionError('Unexpected extended operation $top');
+ }
+
+ static Object collectArray(Object parser, Object stack) {
+ var array = _Utils.arraySplice(stack, position(parser));
+ toTypes(_Parser.universe(parser), environment(parser), array);
+ setPosition(parser, _Utils.asInt(pop(stack)));
+ return array;
+ }
+
+ static Object collectNamed(Object parser, Object stack) {
+ var array = _Utils.arraySplice(stack, position(parser));
+ toTypesNamed(_Parser.universe(parser), environment(parser), array);
+ setPosition(parser, _Utils.asInt(pop(stack)));
+ return array;
+ }
+
+ /// Coerce a stack item into an Rti object. Strings are converted to interface
+ /// types, integers are looked up in the type environment.
+ static Rti toType(Object universe, Rti environment, Object item) {
+ if (_Utils.isString(item)) {
+ String name = _Utils.asString(item);
+ // TODO(sra): Compile this out for minified code.
+ if ('dynamic' == name) {
+ return _Universe._lookupDynamicRti(universe);
+ }
+ return _Universe._lookupInterfaceRti(
+ universe, name, _Universe.sharedEmptyArray(universe));
+ } else if (_Utils.isNum(item)) {
+ return _Parser.indexToType(universe, environment, _Utils.asInt(item));
+ } else {
+ return _castToRti(item);
+ }
+ }
+
+ static void toTypes(Object universe, Rti environment, Object items) {
+ int length = _Utils.arrayLength(items);
+ for (int i = 0; i < length; i++) {
+ var item = _Utils.arrayAt(items, i);
+ Rti type = toType(universe, environment, item);
+ _Utils.arraySetAt(items, i, type);
+ }
+ }
+
+ static void toTypesNamed(Object universe, Rti environment, Object items) {
+ int length = _Utils.arrayLength(items);
+ assert(length.isEven);
+ for (int i = 1; i < length; i += 2) {
+ var item = _Utils.arrayAt(items, i);
+ Rti type = toType(universe, environment, item);
+ _Utils.arraySetAt(items, i, type);
+ }
+ }
+
+ static Rti indexToType(Object universe, Rti environment, int index) {
+ int kind = Rti._getKind(environment);
+ if (kind == Rti.kindBinding) {
+ if (index == 0) return Rti._getBindingBase(environment);
+ var typeArguments = Rti._getBindingArguments(environment);
+ int len = _Utils.arrayLength(typeArguments);
+ if (index <= len) {
+ return _castToRti(_Utils.arrayAt(typeArguments, index - 1));
+ }
+ // Is index into interface Rti in base.
+ index -= len;
+ environment = Rti._getBindingBase(environment);
+ kind = Rti._getKind(environment);
+ } else {
+ if (index == 0) return environment;
+ }
+ if (kind != Rti.kindInterface) {
+ throw AssertionError('Indexed base must be an interface type');
+ }
+ var typeArguments = Rti._getInterfaceTypeArguments(environment);
+ int len = _Utils.arrayLength(typeArguments);
+ if (index <= len) {
+ return _castToRti(_Utils.arrayAt(typeArguments, index - 1));
+ }
+ throw AssertionError('Bad index $index for $environment');
+ }
+
+ static Rti toGenericFunctionParameter(Object universe, Object item) {
+ assert(_Utils.isNum(item));
+ return _Universe._lookupGenericFunctionParameterRti(
+ universe, _Utils.asInt(item));
+ }
+}
+
+/// Represents the set of supertypes and type variable bindings for a given
+/// target type. The target type itself is not stored on the [TypeRule].
+class TypeRule {
+ TypeRule._() {
+ throw UnimplementedError("TypeRule is static methods only.");
+ }
+
+ static String lookupTypeVariable(rule, String typeVariable) =>
+ JS('', '#.#', rule, typeVariable);
+
+ static JSArray lookupSupertype(rule, String supertype) =>
+ JS('', '#.#', rule, supertype);
+}
+
+// -------- Subtype tests ------------------------------------------------------
+
+// Future entry point from compiled code.
+bool isSubtype(universe, Rti s, Rti t) {
+ return _isSubtype(universe, s, null, t, null);
+}
+
+bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
+ // TODO(fishythefish): Update for NNBD. See
+ // https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md#rules
+
+ // Subtyping is reflexive.
+ if (_Utils.isIdentical(s, t)) return true;
+
+ if (isTopType(t)) return true;
+
+ if (isJsInteropType(s)) return true;
+
+ if (isTopType(s)) {
+ if (isGenericFunctionTypeParameter(t)) return false;
+ if (isFutureOrType(t)) {
+ // [t] is FutureOr<T>. Check [s] <: T.
+ Rti tTypeArgument = Rti._getFutureOrArgument(t);
+ return _isSubtype(universe, s, sEnv, tTypeArgument, tEnv);
+ }
+ return false;
+ }
+
+ // Generic function type parameters must match exactly, which would have
+ // exited earlier.
+ if (isGenericFunctionTypeParameter(s)) return false;
+ if (isGenericFunctionTypeParameter(t)) return false;
+
+ if (isNullType(s)) return true;
+
+ if (isFutureOrType(t)) {
+ // [t] is FutureOr<T>.
+ Rti tTypeArgument = Rti._getFutureOrArgument(t);
+ if (isFutureOrType(s)) {
+ // [s] is FutureOr<S>. Check S <: T.
+ Rti sTypeArgument = Rti._getFutureOrArgument(s);
+ return _isSubtype(universe, sTypeArgument, sEnv, tTypeArgument, tEnv);
+ } else if (_isSubtype(universe, s, sEnv, tTypeArgument, tEnv)) {
+ // `true` because [s] <: T.
+ return true;
+ } else {
+ // Check [s] <: Future<T>.
+ String futureClass = JS_GET_NAME(JsGetName.FUTURE_CLASS_TYPE_NAME);
+ var argumentsArray = JS('', '[#]', tTypeArgument);
+ return _isSubtypeOfInterface(
+ universe, s, sEnv, futureClass, argumentsArray, tEnv);
+ }
+ }
+
+ if (isGenericFunctionKind(t)) {
+ return _isGenericFunctionSubtype(universe, s, sEnv, t, tEnv);
+ }
+
+ if (isFunctionKind(t)) {
+ return _isFunctionSubtype(universe, s, sEnv, t, tEnv);
+ }
+
+ if (isFunctionKind(s) || isGenericFunctionKind(s)) {
+ return isFunctionType(t);
+ }
+
+ assert(Rti._getKind(t) == Rti.kindInterface);
+ String tName = Rti._getInterfaceName(t);
+ var tArgs = Rti._getInterfaceTypeArguments(t);
+
+ return _isSubtypeOfInterface(universe, s, sEnv, tName, tArgs, tEnv);
+}
+
+bool _isGenericFunctionSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
+ assert(isGenericFunctionKind(t));
+ if (!isGenericFunctionKind(s)) return false;
+
+ var sBounds = Rti._getGenericFunctionBounds(s);
+ var tBounds = Rti._getGenericFunctionBounds(t);
+ if (!typesEqual(sBounds, tBounds)) return false;
+ // TODO(fishythefish): Extend [sEnv] and [tEnv] with bindings for the [s]
+ // and [t] type parameters to enable checking the bound against
+ // non-type-parameter terms.
+
+ return _isFunctionSubtype(universe, Rti._getGenericFunctionBase(s), sEnv,
+ Rti._getGenericFunctionBase(t), tEnv);
+}
+
+// TODO(fishythefish): Support required named parameters.
+bool _isFunctionSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
+ assert(isFunctionKind(t));
+ if (!isFunctionKind(s)) return false;
+
+ Rti sReturnType = Rti._getReturnType(s);
+ Rti tReturnType = Rti._getReturnType(t);
+ if (!_isSubtype(universe, sReturnType, sEnv, tReturnType, tEnv)) return false;
+
+ _FunctionParameters sParameters = Rti._getFunctionParameters(s);
+ _FunctionParameters tParameters = Rti._getFunctionParameters(t);
+
+ var sRequiredPositional =
+ _FunctionParameters._getRequiredPositional(sParameters);
+ var tRequiredPositional =
+ _FunctionParameters._getRequiredPositional(tParameters);
+ int sRequiredPositionalLength = _Utils.arrayLength(sRequiredPositional);
+ int tRequiredPositionalLength = _Utils.arrayLength(tRequiredPositional);
+ if (sRequiredPositionalLength > tRequiredPositionalLength) return false;
+ int requiredPositionalDelta =
+ tRequiredPositionalLength - sRequiredPositionalLength;
+
+ var sOptionalPositional =
+ _FunctionParameters._getOptionalPositional(sParameters);
+ var tOptionalPositional =
+ _FunctionParameters._getOptionalPositional(tParameters);
+ int sOptionalPositionalLength = _Utils.arrayLength(sOptionalPositional);
+ int tOptionalPositionalLength = _Utils.arrayLength(tOptionalPositional);
+ if (sRequiredPositionalLength + sOptionalPositionalLength <
+ tRequiredPositionalLength + tOptionalPositionalLength) return false;
+
+ for (int i = 0; i < sRequiredPositionalLength; i++) {
+ Rti sParameter = _castToRti(_Utils.arrayAt(sRequiredPositional, i));
+ Rti tParameter = _castToRti(_Utils.arrayAt(tRequiredPositional, i));
+ if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv)) return false;
+ }
+
+ for (int i = 0; i < requiredPositionalDelta; i++) {
+ Rti sParameter = _castToRti(_Utils.arrayAt(sOptionalPositional, i));
+ Rti tParameter = _castToRti(
+ _Utils.arrayAt(tRequiredPositional, sRequiredPositionalLength + i));
+ if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv)) return false;
+ }
+
+ for (int i = 0; i < tOptionalPositionalLength; i++) {
+ Rti sParameter = _castToRti(
+ _Utils.arrayAt(sOptionalPositional, requiredPositionalDelta + i));
+ Rti tParameter = _castToRti(_Utils.arrayAt(tOptionalPositional, i));
+ if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv)) return false;
+ }
+
+ var sOptionalNamed = _FunctionParameters._getOptionalNamed(sParameters);
+ var tOptionalNamed = _FunctionParameters._getOptionalNamed(tParameters);
+ int sOptionalNamedLength = _Utils.arrayLength(sOptionalNamed);
+ int tOptionalNamedLength = _Utils.arrayLength(tOptionalNamed);
+
+ for (int i = 0, j = 0; j < tOptionalNamedLength; j += 2) {
+ String sName;
+ String tName = _Utils.asString(_Utils.arrayAt(tOptionalNamed, j));
+ do {
+ if (i >= sOptionalNamedLength) return false;
+ sName = _Utils.asString(_Utils.arrayAt(sOptionalNamed, i));
+ i += 2;
+ } while (_Utils.stringLessThan(sName, tName));
+ if (_Utils.stringLessThan(tName, sName)) return false;
+ Rti sType = _castToRti(_Utils.arrayAt(sOptionalNamed, i - 1));
+ Rti tType = _castToRti(_Utils.arrayAt(tOptionalNamed, j + 1));
+ if (!_isSubtype(universe, tType, tEnv, sType, sEnv)) return false;
+ }
+
+ return true;
+}
+
+bool _isSubtypeOfInterface(
+ universe, Rti s, sEnv, String tName, Object tArgs, tEnv) {
+ assert(Rti._getKind(s) == Rti.kindInterface);
+ String sName = Rti._getInterfaceName(s);
+
+ if (sName == tName) {
+ var sArgs = Rti._getInterfaceTypeArguments(s);
+ int length = _Utils.arrayLength(sArgs);
+ assert(length == _Utils.arrayLength(tArgs));
+ for (int i = 0; i < length; i++) {
+ Rti sArg = _castToRti(_Utils.arrayAt(sArgs, i));
+ Rti tArg = _castToRti(_Utils.arrayAt(tArgs, i));
+ if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv)) return false;
+ }
+ return true;
+ }
+
+ Object rule = _Universe.findRule(universe, sName);
+ if (rule == null) return false;
+ var supertypeArgs = TypeRule.lookupSupertype(rule, tName);
+ if (supertypeArgs == null) return false;
+ int length = _Utils.arrayLength(supertypeArgs);
+ assert(length == _Utils.arrayLength(tArgs));
+ for (int i = 0; i < length; i++) {
+ String recipe = _Utils.asString(_Utils.arrayAt(supertypeArgs, i));
+ Rti supertypeArg = _Universe.evalInEnvironment(universe, s, recipe);
+ Rti tArg = _castToRti(_Utils.arrayAt(tArgs, i));
+ if (!_isSubtype(universe, supertypeArg, sEnv, tArg, tEnv)) return false;
+ }
+
+ return true;
+}
+
+/// Types are equal if they are structurally equal up to renaming of bound type
+/// variables and equating all top types.
+///
+/// We ignore renaming of bound type variables because we operate on de Bruijn
+/// indices, not names.
+bool typeEqual(Rti s, Rti t) {
+ if (_Utils.isIdentical(s, t)) return true;
+
+ if (isTopType(s)) return isTopType(t);
+
+ int sKind = Rti._getKind(s);
+ int tKind = Rti._getKind(t);
+ if (sKind != tKind) return false;
+
+ switch (sKind) {
+ case Rti.kindStar:
+ case Rti.kindQuestion:
+ case Rti.kindFutureOr:
+ return typeEqual(
+ _castToRti(Rti._getPrimary(s)), _castToRti(Rti._getPrimary(t)));
+
+ case Rti.kindInterface:
+ if (Rti._getInterfaceName(s) != Rti._getInterfaceName(t)) return false;
+ return typesEqual(
+ Rti._getInterfaceTypeArguments(s), Rti._getInterfaceTypeArguments(t));
+
+ case Rti.kindBinding:
+ return typeEqual(Rti._getBindingBase(s), Rti._getBindingBase(t)) &&
+ typesEqual(Rti._getBindingArguments(s), Rti._getBindingArguments(t));
+
+ case Rti.kindFunction:
+ return typeEqual(Rti._getReturnType(s), Rti._getReturnType(t)) &&
+ functionParametersEqual(
+ Rti._getFunctionParameters(s), Rti._getFunctionParameters(t));
+
+ case Rti.kindGenericFunction:
+ return typeEqual(
+ Rti._getGenericFunctionBase(s), Rti._getGenericFunctionBase(t)) &&
+ typesEqual(Rti._getGenericFunctionBounds(s),
+ Rti._getGenericFunctionBounds(t));
+
+ default:
+ return false;
+ }
+}
+
+bool typesEqual(Object sArray, Object tArray) {
+ int sLength = _Utils.arrayLength(sArray);
+ int tLength = _Utils.arrayLength(tArray);
+ if (sLength != tLength) return false;
+ for (int i = 0; i < sLength; i++) {
+ if (!typeEqual(_castToRti(_Utils.arrayAt(sArray, i)),
+ _castToRti(_Utils.arrayAt(tArray, i)))) return false;
+ }
+ return true;
+}
+
+bool namedTypesEqual(Object sArray, Object tArray) {
+ int sLength = _Utils.arrayLength(sArray);
+ int tLength = _Utils.arrayLength(tArray);
+ assert(sLength.isEven);
+ assert(tLength.isEven);
+ if (sLength != tLength) return false;
+ for (int i = 0; i < sLength; i += 2) {
+ if (_Utils.asString(_Utils.arrayAt(sArray, i)) !=
+ _Utils.asString(_Utils.arrayAt(tArray, i))) return false;
+ if (!typeEqual(_castToRti(_Utils.arrayAt(sArray, i + 1)),
+ _castToRti(_Utils.arrayAt(tArray, i + 1)))) return false;
+ }
+ return true;
+}
+
+// TODO(fishythefish): Support required named parameters.
+bool functionParametersEqual(
+ _FunctionParameters sParameters, _FunctionParameters tParameters) =>
+ typesEqual(_FunctionParameters._getRequiredPositional(sParameters),
+ _FunctionParameters._getRequiredPositional(tParameters)) &&
+ typesEqual(_FunctionParameters._getOptionalPositional(sParameters),
+ _FunctionParameters._getOptionalPositional(tParameters)) &&
+ namedTypesEqual(_FunctionParameters._getOptionalNamed(sParameters),
+ _FunctionParameters._getOptionalNamed(tParameters));
+
+bool isTopType(Rti t) =>
+ isDynamicType(t) || isVoidType(t) || isObjectType(t) || isJsInteropType(t);
+
+bool isDynamicType(Rti t) => Rti._getKind(t) == Rti.kindDynamic;
+bool isVoidType(Rti t) => Rti._getKind(t) == Rti.kindVoid;
+bool isJsInteropType(Rti t) => Rti._getKind(t) == Rti.kindAny;
+
+bool isFutureOrType(Rti t) => Rti._getKind(t) == Rti.kindFutureOr;
+
+bool isFunctionKind(Rti t) => Rti._getKind(t) == Rti.kindFunction;
+bool isGenericFunctionKind(Rti t) => Rti._getKind(t) == Rti.kindGenericFunction;
+
+bool isGenericFunctionTypeParameter(Rti t) =>
+ Rti._getKind(t) == Rti.kindGenericFunctionParameter;
+
+bool isObjectType(Rti t) =>
+ Rti._getKind(t) == Rti.kindInterface &&
+ Rti._getInterfaceName(t) == JS_GET_NAME(JsGetName.OBJECT_CLASS_TYPE_NAME);
+
+// TODO(fishythefish): Which representation should we use for NNBD?
+// Do we also need to check for `Never?`, etc.?
+bool isNullType(Rti t) =>
+ Rti._getKind(t) == Rti.kindInterface &&
+ Rti._getInterfaceName(t) == JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME);
+
+bool isFunctionType(Rti t) =>
+ Rti._getKind(t) == Rti.kindInterface &&
+ Rti._getInterfaceName(t) == JS_GET_NAME(JsGetName.FUNCTION_CLASS_TYPE_NAME);
+
+/// Unchecked cast to Rti.
+Rti _castToRti(s) => JS('Rti', '#', s);
+
+///
+class _Utils {
+ static bool asBool(Object o) => JS('bool', '#', o);
+ static double asDouble(Object o) => JS('double', '#', o);
+ static int asInt(Object o) => JS('int', '#', o);
+ static num asNum(Object o) => JS('num', '#', o);
+ static String asString(Object o) => JS('String', '#', o);
+
+ static bool isString(Object o) => JS('bool', 'typeof # == "string"', o);
+ static bool isNum(Object o) => JS('bool', 'typeof # == "number"', o);
+
+ static bool instanceOf(Object o, Object constructor) =>
+ JS('bool', '# instanceof #', o, constructor);
+
+ static bool isIdentical(s, t) => JS('bool', '# === #', s, t);
+
+ static bool isArray(Object o) => JS('bool', 'Array.isArray(#)', o);
+
+ static int arrayLength(Object array) => JS('int', '#.length', array);
+
+ static Object arrayAt(Object array, int i) => JS('', '#[#]', array, i);
+
+ static void arraySetAt(Object array, int i, Object value) {
+ JS('', '#[#] = #', array, i, value);
+ }
+
+ static JSArray arrayShallowCopy(Object array) =>
+ JS('JSArray', '#.slice()', array);
+
+ static JSArray arraySplice(Object array, int position) =>
+ JS('JSArray', '#.splice(#)', array, position);
+
+ static JSArray arrayConcat(Object a1, Object a2) =>
+ JS('JSArray', '#.concat(#)', a1, a2);
+
+ static void arrayPush(Object array, Object value) {
+ JS('', '#.push(#)', array, value);
+ }
+
+ static String substring(String s, int start, int end) =>
+ JS('String', '#.substring(#, #)', s, start, end);
+
+ static bool stringLessThan(String s1, String s2) =>
+ JS('bool', '# < #', s1, s2);
+
+ static mapGet(cache, key) => JS('', '#.get(#)', cache, key);
+
+ static void mapSet(cache, key, value) {
+ JS('', '#.set(#, #)', cache, key, value);
+ }
+}
+// -------- Entry points for testing -------------------------------------------
+
+String testingCanonicalRecipe(rti) {
+ return Rti._getCanonicalRecipe(rti);
+}
+
+String testingRtiToString(rti) {
+ return _rtiToString(_castToRti(rti), null);
+}
+
+String testingRtiToDebugString(rti) {
+ return _rtiToDebugString(_castToRti(rti));
+}
+
+Object testingCreateUniverse() {
+ return _Universe.create();
+}
+
+void testingAddRules(universe, rules) {
+ _Universe.addRules(universe, rules);
+}
+
+bool testingIsSubtype(universe, rti1, rti2) {
+ return isSubtype(universe, _castToRti(rti1), _castToRti(rti2));
+}
+
+Object testingUniverseEval(universe, String recipe) {
+ return _Universe.eval(universe, recipe);
+}
+
+Object testingEnvironmentEval(universe, environment, String recipe) {
+ return _Universe.evalInEnvironment(universe, _castToRti(environment), recipe);
+}
+
+Object testingEnvironmentBind(universe, environment, arguments) {
+ return _Universe.bind(
+ universe, _castToRti(environment), _castToRti(arguments));
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart
new file mode 100644
index 0000000..f87406b
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Contains error codes that transformed async/async* functions use to
+/// communicate with js_helper functions.
+
+const int SUCCESS = 0;
+const int ERROR = 1;
+const int STREAM_WAS_CANCELED = 2;
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/shared/embedded_names.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/embedded_names.dart
new file mode 100644
index 0000000..50cf7e8
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/embedded_names.dart
@@ -0,0 +1,452 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Contains the names of globals that are embedded into the output by the
+/// compiler.
+///
+/// Variables embedded this way should be access with `JS_EMBEDDED_GLOBAL` from
+/// the `_foreign_helper` library.
+///
+/// This library is shared between the compiler and the runtime system.
+library dart2js._embedded_names;
+
+/// The name of the property that is used to mark a type as typedef.
+///
+/// Without reflection typedefs are removed (expanded to their function type)
+/// but with reflection an object is needed to have the typedef's name. The
+/// object is marked with this property.
+///
+/// This property name only lives on internal type-objects and is only used
+/// when reflection is enabled.
+const TYPEDEF_PREDICATE_PROPERTY_NAME = r"$$isTypedef";
+
+/// The name of the property that is used to find the function type of a
+/// typedef.
+///
+/// Without reflection typedefs are removed (expanded to their function type)
+/// but with reflection an object is needed to have the typedef's name.
+///
+/// The typedef's object contains a pointer to its function type (as an index
+/// into the embedded global [TYPES]) in this property.
+///
+/// This property name only lives on internal type-objects and is only used
+/// when reflection is enabled.
+const TYPEDEF_TYPE_PROPERTY_NAME = r"$typedefType";
+
+/// The name of the property that is used to find the native superclass of
+/// an extended class.
+///
+/// Every class that extends a native class has this property set on its
+/// native class.
+const NATIVE_SUPERCLASS_TAG_NAME = r"$nativeSuperclassTag";
+
+/// The name of the static-function property name.
+///
+/// This property is set for all tear-offs of static functions, and provides
+/// the static function's unique (potentially minified) name.
+const STATIC_FUNCTION_NAME_PROPERTY_NAME = r'$static_name';
+
+/// The name of the embedded global for metadata.
+///
+/// Use [JsBuiltin.getMetadata] instead of directly accessing this embedded
+/// global.
+const METADATA = 'metadata';
+
+/// A list of types used in the program e.g. for reflection or encoding of
+/// function types.
+///
+/// Use [JsBuiltin.getType] instead of directly accessing this embedded global.
+const TYPES = 'types';
+
+/// Returns a function that maps a name of a class to its type.
+///
+/// This embedded global is used by the runtime when computing the internal
+/// runtime-type-information (rti) object.
+const GET_TYPE_FROM_NAME = 'getTypeFromName';
+
+/// A JS map from mangled global names to their unmangled names.
+///
+/// If the program does not use reflection, this embedded global may be empty
+/// (but not null or undefined).
+const MANGLED_GLOBAL_NAMES = 'mangledGlobalNames';
+
+/// A JS map from mangled instance names to their unmangled names.
+///
+/// This embedded global is mainly used for reflection, but is also used to
+/// map const-symbols (`const Symbol('x')`) to the mangled instance names.
+///
+/// This embedded global may be empty (but not null or undefined).
+const MANGLED_NAMES = 'mangledNames';
+
+/// A JS map from dispatch tags (usually constructor names of DOM classes) to
+/// interceptor class. This map is used to find the correct interceptor for
+/// native classes.
+///
+/// This embedded global is used for natives.
+const INTERCEPTORS_BY_TAG = 'interceptorsByTag';
+
+/// A JS map from dispatch tags (usually constructor names of DOM classes) to
+/// booleans. Every tag entry of [INTERCEPTORS_BY_TAG] has a corresponding
+/// entry in the leaf-tags map.
+///
+/// A tag-entry is true, when a class can be treated as leaf class in the
+/// hierarchy. That is, even though it might have subclasses, all subclasses
+/// have the same code for the used methods.
+///
+/// This embedded global is used for natives.
+const LEAF_TAGS = 'leafTags';
+
+/// A JS function that returns the isolate tag for a given name.
+///
+/// This function uses the [ISOLATE_TAG] (below) to construct a name that is
+/// unique per isolate.
+///
+/// This embedded global is used for natives.
+// TODO(floitsch): should we rename this variable to avoid confusion with
+// [INTERCEPTORS_BY_TAG] and [LEAF_TAGS].
+const GET_ISOLATE_TAG = 'getIsolateTag';
+
+/// A string that is different for each running isolate.
+///
+/// When this embedded global is initialized a global variable is used to
+/// ensure that no other running isolate uses the same isolate-tag string.
+///
+/// This embedded global is used for natives.
+// TODO(floitsch): should we rename this variable to avoid confusion with
+// [INTERCEPTORS_BY_TAG] and [LEAF_TAGS].
+const ISOLATE_TAG = 'isolateTag';
+
+/// This embedded global (a function) returns the isolate-specific dispatch-tag
+/// that is used to accelerate interceptor calls.
+const DISPATCH_PROPERTY_NAME = "dispatchPropertyName";
+
+/// An embedded global that maps a [Type] to the [Interceptor] and constructors
+/// for that type.
+///
+/// More documentation can be found in the interceptors library (close to its
+/// use).
+const TYPE_TO_INTERCEPTOR_MAP = "typeToInterceptorMap";
+
+/// The current script's URI when the program was loaded.
+///
+/// This embedded global is set at startup, just before invoking `main`.
+const CURRENT_SCRIPT = 'currentScript';
+
+/// Contains a map from load-ids to lists of part indexes.
+///
+/// To load the deferred library that is represented by the load-id, the runtime
+/// must load all associated URIs (named in DEFERRED_PART_URIS) and initialize
+/// all the loaded hunks (DEFERRED_PART_HASHES).
+///
+/// This embedded global is only used for deferred loading.
+const DEFERRED_LIBRARY_PARTS = 'deferredLibraryParts';
+
+/// Contains a list of URIs (Strings), indexed by part.
+///
+/// The lists in the DEFERRED_LIBRARY_PARTS map contain indexes into this list.
+///
+/// This embedded global is only used for deferred loading.
+const DEFERRED_PART_URIS = 'deferredPartUris';
+
+/// Contains a list of hashes, indexed by part.
+///
+/// The lists in the DEFERRED_LIBRARY_PARTS map contain indexes into this list.
+///
+/// The hashes are associated with the URIs of the load-ids (see
+/// [DEFERRED_PART_URIS]). They are SHA1 (or similar) hashes of the code that
+/// must be loaded. By using cryptographic hashes we can (1) handle loading in
+/// the same web page the parts from multiple Dart applications (2) avoid
+/// loading similar code multiple times.
+///
+/// This embedded global is only used for deferred loading.
+const DEFERRED_PART_HASHES = 'deferredPartHashes';
+
+/// Initialize a loaded hunk.
+///
+/// Once a hunk (the code from a deferred URI) has been loaded it must be
+/// initialized. Calling this function with the corresponding hash (see
+/// [DEFERRED_LIBRARY_HASHES]) initializes the code.
+///
+/// This embedded global is only used for deferred loading.
+const INITIALIZE_LOADED_HUNK = 'initializeLoadedHunk';
+
+/// Returns, whether a hunk (identified by its hash) has already been loaded.
+///
+/// This embedded global is only used for deferred loading.
+const IS_HUNK_LOADED = 'isHunkLoaded';
+
+/// Returns, whether a hunk (identified by its hash) has already been
+/// initialized.
+///
+/// This embedded global is only used for deferred loading.
+const IS_HUNK_INITIALIZED = 'isHunkInitialized';
+
+/// A set (implemented as map to booleans) of hunks (identified by hashes) that
+/// have already been initialized.
+///
+/// This embedded global is only used for deferred loading.
+///
+/// This global is an emitter-internal embedded global, and not used by the
+/// runtime. The constant remains in this file to make sure that other embedded
+/// globals don't clash with it.
+const DEFERRED_INITIALIZED = 'deferredInitialized';
+
+/// A 'Universe' object used by 'dart:_rti'.
+///
+/// This embedded global is used for --experiment-new-rti.
+const RTI_UNIVERSE = 'typeUniverse';
+
+/// Returns a function that creates all precompiled functions (in particular
+/// constructors).
+///
+/// That is, the function returns the array that the full emitter would
+/// otherwise build dynamically when it finishes all classes.
+///
+/// This constant is only used in CSP mode.
+///
+/// This global is an emitter-internal embedded global, and not used by the
+/// runtime. The constant remains in this file to make sure that other embedded
+/// globals don't clash with it.
+const PRECOMPILED = 'precompiled';
+
+/// An emitter-internal embedded global. This global is not used by the runtime.
+const FINISHED_CLASSES = 'finishedClasses';
+
+/// A JavaScript object literal that maps the (minified) JavaScript constructor
+/// name (as given by [JsBuiltin.rawRtiToJsConstructorName] to the
+/// JavaScript constructor.
+///
+/// This embedded global is only used by reflection.
+const ALL_CLASSES = 'allClasses';
+
+/// A map from element to type information.
+///
+/// This embedded global is only used by reflection.
+const TYPE_INFORMATION = 'typeInformation';
+
+/// A map from statics to their descriptors.
+///
+/// This embedded global is only used by reflection.
+const STATICS = 'statics';
+
+/// An array of library descriptors.
+///
+/// The descriptor contains information such as name, uri, classes, ...
+///
+/// This embedded global is only used by reflection.
+const LIBRARIES = 'libraries';
+
+/// A map from lazy statics to their initializers.
+///
+/// This embedded global is only used by reflection.
+const LAZIES = 'lazies';
+
+/// Names that are supported by [JS_GET_NAME].
+// TODO(herhut): Make entries lower case (as in fields) and find a better name.
+enum JsGetName {
+ GETTER_PREFIX,
+ SETTER_PREFIX,
+ CALL_PREFIX,
+ CALL_PREFIX0,
+ CALL_PREFIX1,
+ CALL_PREFIX2,
+ CALL_PREFIX3,
+ CALL_PREFIX4,
+ CALL_PREFIX5,
+ CALL_CATCH_ALL,
+ REFLECTABLE,
+ CLASS_DESCRIPTOR_PROPERTY,
+ REQUIRED_PARAMETER_PROPERTY,
+ DEFAULT_VALUES_PROPERTY,
+ CALL_NAME_PROPERTY,
+ DEFERRED_ACTION_PROPERTY,
+
+ /// Prefix used for generated type argument substitutions on classes.
+ OPERATOR_AS_PREFIX,
+
+ /// Name used for generated function types on classes and methods.
+ SIGNATURE_NAME,
+
+ /// Name of JavaScript property used to store runtime-type information on
+ /// instances of parameterized classes.
+ RTI_NAME,
+
+ /// Name used to tag typedefs.
+ TYPEDEF_TAG,
+
+ /// Name used to tag a function type.
+ FUNCTION_TYPE_TAG,
+
+ /// Name used to tag bounds of a generic function type. If bounds are present,
+ /// the property value is an Array of bounds (the length gives the number of
+ /// type parameters). If absent, the type is not a generic function type.
+ FUNCTION_TYPE_GENERIC_BOUNDS_TAG,
+
+ /// Name used to tag void return in function type representations in
+ /// JavaScript.
+ FUNCTION_TYPE_VOID_RETURN_TAG,
+
+ /// Name used to tag return types in function type representations in
+ /// JavaScript.
+ FUNCTION_TYPE_RETURN_TYPE_TAG,
+
+ /// Name used to tag required parameters in function type representations
+ /// in JavaScript.
+ FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG,
+
+ /// Name used to tag optional parameters in function type representations
+ /// in JavaScript.
+ FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG,
+
+ /// Name used to tag named parameters in function type representations in
+ /// JavaScript.
+ FUNCTION_TYPE_NAMED_PARAMETERS_TAG,
+
+ /// Name used to tag a FutureOr type.
+ FUTURE_OR_TAG,
+
+ /// Name used to tag type arguments types in FutureOr type representations in
+ /// JavaScript.
+ FUTURE_OR_TYPE_ARGUMENT_TAG,
+
+ /// String representation of the type of the Future class.
+ FUTURE_CLASS_TYPE_NAME,
+
+ /// Field name used for determining if an object or its interceptor has
+ /// JavaScript indexing behavior.
+ IS_INDEXABLE_FIELD_NAME,
+
+ /// String representation of the type of the null class.
+ NULL_CLASS_TYPE_NAME,
+
+ /// String representation of the type of the object class.
+ OBJECT_CLASS_TYPE_NAME,
+
+ /// String representation of the type of the function class.
+ FUNCTION_CLASS_TYPE_NAME,
+
+ /// String recipe for the [bool] type.
+ BOOL_RECIPE,
+
+ /// String recipe for the [double] type.
+ DOUBLE_RECIPE,
+
+ /// String recipe for the [int] type.
+ INT_RECIPE,
+
+ /// String recipe for the [num] type.
+ NUM_RECIPE,
+
+ /// String recipe for the [String] type.
+ STRING_RECIPE,
+
+ /// Property name for Rti._is field.
+ RTI_FIELD_IS,
+}
+
+enum JsBuiltin {
+ /// Returns the JavaScript constructor function for Dart's Object class.
+ /// This can be used for type tests, as in
+ ///
+ /// var constructor = JS_BUILTIN('', JsBuiltin.dartObjectConstructor);
+ /// if (JS('bool', '# instanceof #', obj, constructor))
+ /// ...
+ dartObjectConstructor,
+
+ /// Returns the JavaScript constructor function for the runtime's Closure
+ /// class, the base class of all closure objects. This can be used for type
+ /// tests, as in
+ ///
+ /// var constructor = JS_BUILTIN('', JsBuiltin.dartClosureConstructor);
+ /// if (JS('bool', '# instanceof #', obj, constructor))
+ /// ...
+ dartClosureConstructor,
+
+ /// Returns the JavaScript-constructor name given an [isCheckProperty].
+ ///
+ /// This relies on a deterministic encoding of is-check properties (for
+ /// example `$isFoo` for a class `Foo`). In minified code the returned
+ /// classname is the minified name of the class.
+ ///
+ /// JS_BUILTIN('returns:String;depends:none;effects:none',
+ /// JsBuiltin.isCheckPropertyToJsConstructorName,
+ /// isCheckProperty);
+ isCheckPropertyToJsConstructorName,
+
+ /// Returns true if the given type is a function type. Returns false for
+ /// the one `Function` type singleton. (See [isFunctionTypeSingleton]).
+ ///
+ /// JS_BUILTIN('bool', JsBuiltin.isFunctionType, o)
+ isFunctionType,
+
+ /// Returns true if the given type is a FutureOr type.
+ ///
+ /// JS_BUILTIN('bool', JsBuiltin.isFutureOrType, o)
+ isFutureOrType,
+
+ /// Returns true if the given type is the `void` type.
+ ///
+ /// JS_BUILTIN('bool', JsBuiltin.isVoidType, o)
+ isVoidType,
+
+ /// Returns true if the given type is the `dynamic` type.
+ ///
+ /// JS_BUILTIN('bool', JsBuiltin.isDynamicType, o)
+ isDynamicType,
+
+ /// Returns true if the given type is a type argument of a js-interop class
+ /// or a supertype of a js-interop class.
+ ///
+ /// JS_BUILTIN('bool', JsBuiltin.isJsInteropTypeArgument, o)
+ isJsInteropTypeArgument,
+
+ /// Returns the JavaScript-constructor name given an rti encoding.
+ ///
+ /// JS_BUILTIN('String', JsBuiltin.rawRtiToJsConstructorName, rti)
+ rawRtiToJsConstructorName,
+
+ /// Returns the raw runtime type of the given object. The given argument
+ /// [o] should be the interceptor (for non-Dart objects).
+ ///
+ /// JS_BUILTIN('', JsBuiltin.rawRuntimeType, o)
+ rawRuntimeType,
+
+ /// Returns whether the given type is a subtype of other.
+ ///
+ /// The argument `other` is the name of the potential supertype. It is
+ /// computed by `runtimeTypeToString`;
+ ///
+ /// *The `other` name must be passed in before the `type`.*
+ ///
+ /// JS_BUILTIN('returns:bool;effects:none;depends:none',
+ /// JsBuiltin.isSubtype, other, type);
+ isSubtype,
+
+ /// Returns true if the given type equals the type given as second
+ /// argument. Use the JS_GET_NAME helpers to get the type representation
+ /// for various Dart classes.
+ ///
+ /// JS_BUILTIN('returns:bool;effects:none;depends:none',
+ /// JsBuiltin.isFunctionTypeLiteral, type, name);
+ isGivenTypeRti,
+
+ /// Returns the metadata of the given [index].
+ ///
+ /// JS_BUILTIN('returns:var;effects:none;depends:none',
+ /// JsBuiltin.getMetadata, index);
+ getMetadata,
+
+ /// Returns the type of the given [index].
+ ///
+ /// JS_BUILTIN('returns:var;effects:none;depends:none',
+ /// JsBuiltin.getType, index);
+ getType,
+}
+
+/// Names of fields of the Rti Universe object.
+class RtiUniverseFieldNames {
+ static String evalCache = 'eC';
+ static String typeRules = 'tR';
+ static String sharedEmptyArray = 'sEA';
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart
new file mode 100644
index 0000000..7666379
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart
@@ -0,0 +1,230 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Constants and predicates used for encoding and decoding type recipes.
+///
+/// This library is shared between the compiler and the runtime system.
+library dart2js._recipe_syntax;
+
+abstract class Recipe {
+ Recipe._();
+
+ // Operators.
+
+ static const int separator = _comma;
+ static const String separatorString = _commaString;
+
+ static const int toType = _semicolon;
+ static const String toTypeString = _semicolonString;
+
+ static const int pushDynamic = _at;
+ static const String pushDynamicString = _atString;
+ static const int pushVoid = _tilde;
+ static const String pushVoidString = _tildeString;
+
+ static const int wrapStar = _asterisk;
+ static const String wrapStarString = _asteriskString;
+ static const int wrapQuestion = _question;
+ static const String wrapQuestionString = _questionString;
+ static const int wrapFutureOr = _slash;
+ static const String wrapFutureOrString = _slashString;
+
+ static const int startTypeArguments = _lessThan;
+ static const String startTypeArgumentsString = _lessThanString;
+ static const int endTypeArguments = _greaterThan;
+ static const String endTypeArgumentsString = _greaterThanString;
+
+ static const int startFunctionArguments = _leftParen;
+ static const String startFunctionArgumentsString = _leftParenString;
+ static const int endFunctionArguments = _rightParen;
+ static const String endFunctionArgumentsString = _rightParenString;
+ static const int startOptionalGroup = _leftBracket;
+ static const String startOptionalGroupString = _leftBracketString;
+ static const int endOptionalGroup = _rightBracket;
+ static const String endOptionalGroupString = _rightBracketString;
+ static const int startNamedGroup = _leftBrace;
+ static const String startNamedGroupString = _leftBraceString;
+ static const int endNamedGroup = _rightBrace;
+ static const String endNamedGroupString = _rightBraceString;
+ static const int nameSeparator = _colon;
+ static const String nameSeparatorString = _colonString;
+
+ static const int genericFunctionTypeParameterIndex = _circumflex;
+ static const String genericFunctionTypeParameterIndexString =
+ _circumflexString;
+
+ static const int extensionOp = _ampersand;
+ static const String extensionOpString = _ampersandString;
+ static const int pushNeverExtension = 0;
+ static const String pushNeverExtensionString = '$pushNeverExtension';
+ static const int pushAnyExtension = 1;
+ static const String pushAnyExtensionString = '$pushAnyExtension';
+
+ // Number and name components.
+
+ static bool isDigit(int code) => code >= _digit0 && code <= _digit9;
+ static int digitValue(int code) => code - _digit0;
+
+ static bool isIdentifierStart(int ch) =>
+ (((ch | 32) - _lowercaseA) & 0xffff) < 26 ||
+ (ch == _underscore) ||
+ (ch == _dollar);
+
+ static const int period = _period;
+
+ // Private names.
+
+ static const int _formfeed = 0x0C;
+ static const String _formfeedString = '\f';
+
+ static const int _space = 0x20;
+ static const String _spaceString = ' ';
+ static const int _exclamation = 0x21;
+ static const String _exclamationString = '!';
+ static const int _hash = 0x23;
+ static const String _hashString = '#';
+ static const int _dollar = 0x24;
+ static const String _dollarString = r'$';
+ static const int _percent = 0x25;
+ static const String _percentString = '%';
+ static const int _ampersand = 0x26;
+ static const String _ampersandString = '&';
+ static const int _apostrophe = 0x27;
+ static const String _apostropheString = "'";
+ static const int _leftParen = 0x28;
+ static const String _leftParenString = '(';
+ static const int _rightParen = 0x29;
+ static const String _rightParenString = ')';
+ static const int _asterisk = 0x2A;
+ static const String _asteriskString = '*';
+ static const int _plus = 0x2B;
+ static const String _plusString = '+';
+ static const int _comma = 0x2C;
+ static const String _commaString = ',';
+ static const int _minus = 0x2D;
+ static const String _minusString = '-';
+ static const int _period = 0x2E;
+ static const String _periodString = '.';
+ static const int _slash = 0x2F;
+ static const String _slashString = '/';
+
+ static const int _digit0 = 0x30;
+ static const int _digit9 = 0x39;
+
+ static const int _colon = 0x3A;
+ static const String _colonString = ':';
+ static const int _semicolon = 0x3B;
+ static const String _semicolonString = ';';
+ static const int _lessThan = 0x3C;
+ static const String _lessThanString = '<';
+ static const int _equals = 0x3D;
+ static const String _equalsString = '=';
+ static const int _greaterThan = 0x3E;
+ static const String _greaterThanString = '>';
+ static const int _question = 0x3F;
+ static const String _questionString = '?';
+ static const int _at = 0x40;
+ static const String _atString = '@';
+
+ static const int _uppercaseA = 0x41;
+ static const int _uppercaseZ = 0x5A;
+
+ static const int _leftBracket = 0x5B;
+ static const String _leftBracketString = '[';
+ static const int _backslash = 0x5C;
+ static const String _backslashString = r'\';
+ static const int _rightBracket = 0x5D;
+ static const String _rightBracketString = ']';
+ static const int _circumflex = 0x5E;
+ static const String _circumflexString = '^';
+ static const int _underscore = 0x5F;
+ static const String _underscoreString = '_';
+ static const int _backtick = 0x60;
+ static const String _backtickString = '`';
+
+ static const int _lowercaseA = 0x61;
+ static const int _lowercaseZ = 0x7A;
+
+ static const int _leftBrace = 0x7B;
+ static const String _leftBraceString = '{';
+ static const int _vertical = 0x7C;
+ static const String _verticalString = '|';
+ static const int _rightBrace = 0x7D;
+ static const String _rightBraceString = '}';
+ static const int _tilde = 0x7E;
+ static const String _tildeString = '~';
+
+ static void testEquivalence() {
+ void test(String label, int charCode, String str) {
+ if (String.fromCharCode(charCode) != str) {
+ throw StateError("$label: String.fromCharCode($charCode) != $str");
+ }
+ }
+
+ void testExtension(String label, int op, String str) {
+ if ('$op' != str) {
+ throw StateError("$label: $op.toString() != $str");
+ }
+ }
+
+ test("separator", separator, separatorString);
+ test("toType", toType, toTypeString);
+ test("pushDynamic", pushDynamic, pushDynamicString);
+ test("pushVoid", pushVoid, pushVoidString);
+ test("wrapStar", wrapStar, wrapStarString);
+ test("wrapQuestion", wrapQuestion, wrapQuestionString);
+ test("wrapFutureOr", wrapFutureOr, wrapFutureOrString);
+ test("startTypeArguments", startTypeArguments, startTypeArgumentsString);
+ test("endTypeArguments", endTypeArguments, endTypeArgumentsString);
+ test("startFunctionArguments", startFunctionArguments,
+ startFunctionArgumentsString);
+ test("endFunctionArguments", endFunctionArguments,
+ endFunctionArgumentsString);
+ test("startOptionalGroup", startOptionalGroup, startOptionalGroupString);
+ test("endOptionalGroup", endOptionalGroup, endOptionalGroupString);
+ test("startNamedGroup", startNamedGroup, startNamedGroupString);
+ test("endNamedGroup", endNamedGroup, endNamedGroupString);
+ test("nameSeparator", nameSeparator, nameSeparatorString);
+ test("genericFunctionTypeParameterIndex", genericFunctionTypeParameterIndex,
+ genericFunctionTypeParameterIndexString);
+ test("extensionOp", extensionOp, extensionOpString);
+ testExtension(
+ "pushNeverExtension", pushNeverExtension, pushNeverExtensionString);
+ testExtension("pushAnyExtension", pushAnyExtension, pushAnyExtensionString);
+
+ test("_formfeed", _formfeed, _formfeedString);
+ test("_space", _space, _spaceString);
+ test("_exclamation", _exclamation, _exclamationString);
+ test("_hash", _hash, _hashString);
+ test("_dollar", _dollar, _dollarString);
+ test("_percent", _percent, _percentString);
+ test("_ampersand", _ampersand, _ampersandString);
+ test("_apostrophe", _apostrophe, _apostropheString);
+ test("_leftParen", _leftParen, _leftParenString);
+ test("_rightParen", _rightParen, _rightParenString);
+ test("_asterisk", _asterisk, _asteriskString);
+ test("_plus", _plus, _plusString);
+ test("_comma", _comma, _commaString);
+ test("_minus", _minus, _minusString);
+ test("_period", _period, _periodString);
+ test("_slash", _slash, _slashString);
+ test("_colon", _colon, _colonString);
+ test("_semicolon", _semicolon, _semicolonString);
+ test("_lessThan", _lessThan, _lessThanString);
+ test("_equals", _equals, _equalsString);
+ test("_greaterThan", _greaterThan, _greaterThanString);
+ test("_question", _question, _questionString);
+ test("_at", _at, _atString);
+ test("_leftBracket", _leftBracket, _leftBracketString);
+ test("_backslash", _backslash, _backslashString);
+ test("_rightBracket", _rightBracket, _rightBracketString);
+ test("_circumflex", _circumflex, _circumflexString);
+ test("_underscore", _underscore, _underscoreString);
+ test("_backtick", _backtick, _backtickString);
+ test("_leftBrace", _leftBrace, _leftBraceString);
+ test("_vertical", _vertical, _verticalString);
+ test("_rightBrace", _rightBrace, _rightBraceString);
+ test("_tilde", _tilde, _tildeString);
+ }
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/string_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/string_helper.dart
new file mode 100644
index 0000000..ea5374e
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/string_helper.dart
@@ -0,0 +1,331 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of _js_helper;
+
+stringIndexOfStringUnchecked(receiver, other, startIndex) {
+ return JS('int', '#.indexOf(#, #)', receiver, other, startIndex);
+}
+
+substring1Unchecked(receiver, startIndex) {
+ return JS('String', '#.substring(#)', receiver, startIndex);
+}
+
+substring2Unchecked(receiver, startIndex, endIndex) {
+ return JS('String', '#.substring(#, #)', receiver, startIndex, endIndex);
+}
+
+stringContainsStringUnchecked(receiver, other, startIndex) {
+ return stringIndexOfStringUnchecked(receiver, other, startIndex) >= 0;
+}
+
+List<String> stringSplitUnchecked(String receiver, pattern) {
+ return new JSArray<String>.markGrowable(JS(
+ 'returns:JSExtendableArray;new:true', '#.split(#)', receiver, pattern));
+}
+
+class StringMatch implements Match {
+ const StringMatch(int this.start, String this.input, String this.pattern);
+
+ int get end => start + pattern.length;
+ String operator [](int g) => group(g);
+ int get groupCount => 0;
+
+ String group(int group_) {
+ if (group_ != 0) {
+ throw new RangeError.value(group_);
+ }
+ return pattern;
+ }
+
+ List<String> groups(List<int> groups_) {
+ List<String> result = new List<String>();
+ for (int g in groups_) {
+ result.add(group(g));
+ }
+ return result;
+ }
+
+ final int start;
+ final String input;
+ final String pattern;
+}
+
+Iterable<Match> allMatchesInStringUnchecked(
+ String pattern, String string, int startIndex) {
+ return new _StringAllMatchesIterable(string, pattern, startIndex);
+}
+
+class _StringAllMatchesIterable extends Iterable<Match> {
+ final String _input;
+ final String _pattern;
+ final int _index;
+
+ _StringAllMatchesIterable(this._input, this._pattern, this._index);
+
+ Iterator<Match> get iterator =>
+ new _StringAllMatchesIterator(_input, _pattern, _index);
+
+ Match get first {
+ int index = stringIndexOfStringUnchecked(_input, _pattern, _index);
+ if (index >= 0) {
+ return new StringMatch(index, _input, _pattern);
+ }
+ throw IterableElementError.noElement();
+ }
+}
+
+class _StringAllMatchesIterator implements Iterator<Match> {
+ final String _input;
+ final String _pattern;
+ int _index;
+ Match _current;
+
+ _StringAllMatchesIterator(this._input, this._pattern, this._index);
+
+ bool moveNext() {
+ if (_index + _pattern.length > _input.length) {
+ _current = null;
+ return false;
+ }
+ var index = stringIndexOfStringUnchecked(_input, _pattern, _index);
+ if (index < 0) {
+ _index = _input.length + 1;
+ _current = null;
+ return false;
+ }
+ int end = index + _pattern.length;
+ _current = new StringMatch(index, _input, _pattern);
+ // Empty match, don't start at same location again.
+ if (end == _index) end++;
+ _index = end;
+ return true;
+ }
+
+ Match get current => _current;
+}
+
+stringContainsUnchecked(receiver, other, startIndex) {
+ if (other is String) {
+ return stringContainsStringUnchecked(receiver, other, startIndex);
+ } else if (other is JSSyntaxRegExp) {
+ return other.hasMatch(receiver.substring(startIndex));
+ } else {
+ var substr = receiver.substring(startIndex);
+ return other.allMatches(substr).isNotEmpty;
+ }
+}
+
+String stringReplaceJS(String receiver, jsRegExp, String replacement) {
+ return JS('String', r'#.replace(#, #)', receiver, jsRegExp,
+ escapeReplacement(replacement));
+}
+
+String escapeReplacement(String replacement) {
+ // The JavaScript `String.prototype.replace` method recognizes replacement
+ // patterns in the replacement string. Dart does not have that behavior, so
+ // the replacement patterns need to be escaped.
+
+ // `String.prototype.replace` tends to be slower when there are replacement
+ // patterns, and the escaping itself uses replacement patterns, so it is
+ // worthwhile checking for `$` first.
+ if (stringContainsStringUnchecked(replacement, r'$', 0)) {
+ return JS('String', r'#.replace(/\$/g, "$$$$")', replacement);
+ }
+ return replacement;
+}
+
+stringReplaceFirstRE(receiver, regexp, replacement, startIndex) {
+ var match = regexp._execGlobal(receiver, startIndex);
+ if (match == null) return receiver;
+ var start = match.start;
+ var end = match.end;
+ return stringReplaceRangeUnchecked(receiver, start, end, replacement);
+}
+
+/// Returns a string for a RegExp pattern that matches [string]. This is done by
+/// escaping all RegExp metacharacters.
+quoteStringForRegExp(string) {
+ // We test and replace essentially the same RegExp because replacement when
+ // there are replacement patterns is slow enough to be worth avoiding.
+ if (JS('bool', r'/[[\]{}()*+?.\\^$|]/.test(#)', string)) {
+ return JS('String', r'#.replace(/[[\]{}()*+?.\\^$|]/g, "\\$&")', string);
+ }
+ return string;
+}
+
+stringReplaceAllUnchecked(receiver, pattern, replacement) {
+ checkString(replacement);
+ if (pattern is String) {
+ return stringReplaceAllUncheckedString(receiver, pattern, replacement);
+ }
+
+ if (pattern is JSSyntaxRegExp) {
+ var re = regExpGetGlobalNative(pattern);
+ return stringReplaceJS(receiver, re, replacement);
+ }
+
+ checkNull(pattern);
+ // TODO(floitsch): implement generic String.replace (with patterns).
+ throw "String.replaceAll(Pattern) UNIMPLEMENTED";
+}
+
+/// Replaces all non-overlapping occurences of [pattern] in [receiver] with
+/// [replacement]. This should be replace with
+/// (String.prototype.replaceAll)[https://github.com/tc39/proposal-string-replace-all]
+/// when available.
+String stringReplaceAllUncheckedString(
+ String receiver, String pattern, String replacement) {
+ if (pattern == "") {
+ if (receiver == "") {
+ return JS('String', '#', replacement); // help type inference.
+ }
+ StringBuffer result = new StringBuffer('');
+ int length = receiver.length;
+ result.write(replacement);
+ for (int i = 0; i < length; i++) {
+ result.write(receiver[i]);
+ result.write(replacement);
+ }
+ return result.toString();
+ }
+
+ if (!const bool.fromEnvironment(
+ 'dart2js.testing.String.replaceAll.force.regexp')) {
+ // First check for no match.
+ int index = stringIndexOfStringUnchecked(receiver, pattern, 0);
+ if (index < 0) return receiver;
+
+ // The fastest approach in general is to replace with a global RegExp, but
+ // this requires the receiver string to be long enough to amortize the cost
+ // of creating the RegExp, and the replacement to have no '$' patterns,
+ // which tend to make `String.prototype.replace` much slower. In these
+ // cases, using split-join usually wins.
+ if (receiver.length < 500 ||
+ stringContainsStringUnchecked(replacement, r'$', 0)) {
+ return stringReplaceAllUsingSplitJoin(receiver, pattern, replacement);
+ }
+ }
+ var quoted = quoteStringForRegExp(pattern);
+ var replacer = JS('', "new RegExp(#, 'g')", quoted);
+ return stringReplaceJS(receiver, replacer, replacement);
+}
+
+String stringReplaceAllUsingSplitJoin(receiver, pattern, replacement) {
+ return JS('String', '#.split(#).join(#)', receiver, pattern, replacement);
+}
+
+String _matchString(Match match) => match[0];
+String _stringIdentity(String string) => string;
+
+stringReplaceAllFuncUnchecked(receiver, pattern, onMatch, onNonMatch) {
+ if (onMatch == null) onMatch = _matchString;
+ if (onNonMatch == null) onNonMatch = _stringIdentity;
+ if (pattern is String) {
+ return stringReplaceAllStringFuncUnchecked(
+ receiver, pattern, onMatch, onNonMatch);
+ }
+ // Placing the Pattern test here is indistinguishable from placing it at the
+ // top of the method but it saves an extra check on the `pattern is String`
+ // path.
+ if (pattern is! Pattern) {
+ throw new ArgumentError.value(pattern, 'pattern', 'is not a Pattern');
+ }
+ StringBuffer buffer = new StringBuffer('');
+ int startIndex = 0;
+ for (Match match in pattern.allMatches(receiver)) {
+ buffer.write(onNonMatch(receiver.substring(startIndex, match.start)));
+ buffer.write(onMatch(match));
+ startIndex = match.end;
+ }
+ buffer.write(onNonMatch(receiver.substring(startIndex)));
+ return buffer.toString();
+}
+
+stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch) {
+ // Pattern is the empty string.
+ StringBuffer buffer = new StringBuffer('');
+ int length = receiver.length;
+ int i = 0;
+ buffer.write(onNonMatch(""));
+ while (i < length) {
+ buffer.write(onMatch(new StringMatch(i, receiver, "")));
+ // Special case to avoid splitting a surrogate pair.
+ int code = receiver.codeUnitAt(i);
+ if ((code & ~0x3FF) == 0xD800 && length > i + 1) {
+ // Leading surrogate;
+ code = receiver.codeUnitAt(i + 1);
+ if ((code & ~0x3FF) == 0xDC00) {
+ // Matching trailing surrogate.
+ buffer.write(onNonMatch(receiver.substring(i, i + 2)));
+ i += 2;
+ continue;
+ }
+ }
+ buffer.write(onNonMatch(receiver[i]));
+ i++;
+ }
+ buffer.write(onMatch(new StringMatch(i, receiver, "")));
+ buffer.write(onNonMatch(""));
+ return buffer.toString();
+}
+
+stringReplaceAllStringFuncUnchecked(receiver, pattern, onMatch, onNonMatch) {
+ int patternLength = pattern.length;
+ if (patternLength == 0) {
+ return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch);
+ }
+ int length = receiver.length;
+ StringBuffer buffer = new StringBuffer('');
+ int startIndex = 0;
+ while (startIndex < length) {
+ int position = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
+ if (position == -1) {
+ break;
+ }
+ buffer.write(onNonMatch(receiver.substring(startIndex, position)));
+ buffer.write(onMatch(new StringMatch(position, receiver, pattern)));
+ startIndex = position + patternLength;
+ }
+ buffer.write(onNonMatch(receiver.substring(startIndex)));
+ return buffer.toString();
+}
+
+stringReplaceFirstUnchecked(receiver, pattern, replacement, int startIndex) {
+ if (pattern is String) {
+ int index = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
+ if (index < 0) return receiver;
+ int end = index + pattern.length;
+ return stringReplaceRangeUnchecked(receiver, index, end, replacement);
+ }
+ if (pattern is JSSyntaxRegExp) {
+ return startIndex == 0
+ ? stringReplaceJS(receiver, regExpGetNative(pattern), replacement)
+ : stringReplaceFirstRE(receiver, pattern, replacement, startIndex);
+ }
+ checkNull(pattern);
+ Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
+ if (!matches.moveNext()) return receiver;
+ Match match = matches.current;
+ return receiver.replaceRange(match.start, match.end, replacement);
+}
+
+stringReplaceFirstMappedUnchecked(receiver, pattern, replace, int startIndex) {
+ Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
+ if (!matches.moveNext()) return receiver;
+ Match match = matches.current;
+ String replacement = "${replace(match)}";
+ return receiver.replaceRange(match.start, match.end, replacement);
+}
+
+stringJoinUnchecked(array, separator) {
+ return JS('String', r'#.join(#)', array, separator);
+}
+
+String stringReplaceRangeUnchecked(
+ String receiver, int start, int end, String replacement) {
+ var prefix = JS('String', '#.substring(0, #)', receiver, start);
+ var suffix = JS('String', '#.substring(#)', receiver, end);
+ return "$prefix$replacement$suffix";
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/typed_data_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/typed_data_patch.dart
new file mode 100644
index 0000000..615c9da
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/typed_data_patch.dart
@@ -0,0 +1,190 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:_js_helper' show patch;
+import 'dart:_native_typed_data';
+
+@patch
+class ByteData {
+ @patch
+ factory ByteData(int length) = NativeByteData;
+}
+
+@patch
+class Float32List {
+ @patch
+ factory Float32List(int length) = NativeFloat32List;
+
+ @patch
+ factory Float32List.fromList(List<double> elements) =
+ NativeFloat32List.fromList;
+}
+
+@patch
+class Float64List {
+ @patch
+ factory Float64List(int length) = NativeFloat64List;
+
+ @patch
+ factory Float64List.fromList(List<double> elements) =
+ NativeFloat64List.fromList;
+}
+
+@patch
+class Int16List {
+ @patch
+ factory Int16List(int length) = NativeInt16List;
+
+ @patch
+ factory Int16List.fromList(List<int> elements) = NativeInt16List.fromList;
+}
+
+@patch
+class Int32List {
+ @patch
+ factory Int32List(int length) = NativeInt32List;
+
+ @patch
+ factory Int32List.fromList(List<int> elements) = NativeInt32List.fromList;
+}
+
+@patch
+class Int8List {
+ @patch
+ factory Int8List(int length) = NativeInt8List;
+
+ @patch
+ factory Int8List.fromList(List<int> elements) = NativeInt8List.fromList;
+}
+
+@patch
+class Uint32List {
+ @patch
+ factory Uint32List(int length) = NativeUint32List;
+
+ @patch
+ factory Uint32List.fromList(List<int> elements) = NativeUint32List.fromList;
+}
+
+@patch
+class Uint16List {
+ @patch
+ factory Uint16List(int length) = NativeUint16List;
+
+ @patch
+ factory Uint16List.fromList(List<int> elements) = NativeUint16List.fromList;
+}
+
+@patch
+class Uint8ClampedList {
+ @patch
+ factory Uint8ClampedList(int length) = NativeUint8ClampedList;
+
+ @patch
+ factory Uint8ClampedList.fromList(List<int> elements) =
+ NativeUint8ClampedList.fromList;
+}
+
+@patch
+class Uint8List {
+ @patch
+ factory Uint8List(int length) = NativeUint8List;
+
+ @patch
+ factory Uint8List.fromList(List<int> elements) = NativeUint8List.fromList;
+}
+
+@patch
+class Int64List {
+ @patch
+ factory Int64List(int length) {
+ throw new UnsupportedError("Int64List not supported by dart2js.");
+ }
+
+ @patch
+ factory Int64List.fromList(List<int> elements) {
+ throw new UnsupportedError("Int64List not supported by dart2js.");
+ }
+}
+
+@patch
+class Uint64List {
+ @patch
+ factory Uint64List(int length) {
+ throw new UnsupportedError("Uint64List not supported by dart2js.");
+ }
+
+ @patch
+ factory Uint64List.fromList(List<int> elements) {
+ throw new UnsupportedError("Uint64List not supported by dart2js.");
+ }
+}
+
+@patch
+class Int32x4List {
+ @patch
+ factory Int32x4List(int length) = NativeInt32x4List;
+
+ @patch
+ factory Int32x4List.fromList(List<Int32x4> elements) =
+ NativeInt32x4List.fromList;
+}
+
+@patch
+class Float32x4List {
+ @patch
+ factory Float32x4List(int length) = NativeFloat32x4List;
+
+ @patch
+ factory Float32x4List.fromList(List<Float32x4> elements) =
+ NativeFloat32x4List.fromList;
+}
+
+@patch
+class Float64x2List {
+ @patch
+ factory Float64x2List(int length) = NativeFloat64x2List;
+
+ @patch
+ factory Float64x2List.fromList(List<Float64x2> elements) =
+ NativeFloat64x2List.fromList;
+}
+
+@patch
+class Float32x4 {
+ @patch
+ factory Float32x4(double x, double y, double z, double w) = NativeFloat32x4;
+ @patch
+ factory Float32x4.splat(double v) = NativeFloat32x4.splat;
+ @patch
+ factory Float32x4.zero() = NativeFloat32x4.zero;
+ @patch
+ factory Float32x4.fromInt32x4Bits(Int32x4 x) =
+ NativeFloat32x4.fromInt32x4Bits;
+ @patch
+ factory Float32x4.fromFloat64x2(Float64x2 v) = NativeFloat32x4.fromFloat64x2;
+}
+
+@patch
+class Int32x4 {
+ @patch
+ factory Int32x4(int x, int y, int z, int w) = NativeInt32x4;
+ @patch
+ factory Int32x4.bool(bool x, bool y, bool z, bool w) = NativeInt32x4.bool;
+ @patch
+ factory Int32x4.fromFloat32x4Bits(Float32x4 x) =
+ NativeInt32x4.fromFloat32x4Bits;
+}
+
+@patch
+class Float64x2 {
+ @patch
+ factory Float64x2(double x, double y) = NativeFloat64x2;
+ @patch
+ factory Float64x2.splat(double v) = NativeFloat64x2.splat;
+ @patch
+ factory Float64x2.zero() = NativeFloat64x2.zero;
+ @patch
+ factory Float64x2.fromFloat32x4(Float32x4 v) = NativeFloat64x2.fromFloat32x4;
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/pubspec.yaml b/sdk_nnbd/lib/_internal/js_runtime/pubspec.yaml
new file mode 100644
index 0000000..821aaac
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/pubspec.yaml
@@ -0,0 +1,6 @@
+# Note: This package is not meant to be uploaded to pub. This file is used to
+# make it easier to develop on dart2js.
+name: js_runtime
+publish_to: none
+environment:
+ sdk: '>=2.0.0 <3.0.0'
diff --git a/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
new file mode 100644
index 0000000..ba141fa
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -0,0 +1,329 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library libraries;
+
+/**
+ * A bit flag used by [LibraryInfo] indicating that a library is used by dart2js
+ */
+const int DART2JS_PLATFORM = 1;
+
+/**
+ * A bit flag used by [LibraryInfo] indicating that a library is used by the VM
+ */
+const int VM_PLATFORM = 2;
+
+/// The contexts that a library can be used from.
+enum Category {
+ /// Indicates that a library can be used in a browser context.
+ client,
+
+ /// Indicates that a library can be used in a command line context.
+ server,
+
+ /// Indicates that a library can be used from embedded devices.
+ embedded
+}
+
+Category parseCategory(String name) {
+ switch (name) {
+ case "Client":
+ return Category.client;
+ case "Server":
+ return Category.server;
+ case "Embedded":
+ return Category.embedded;
+ }
+ return null;
+}
+
+/// Mapping of "dart:" library name (e.g. "core") to information about that
+/// library.
+const Map<String, LibraryInfo> libraries = const {
+ "async": const LibraryInfo("async/async.dart",
+ categories: "Client,Server",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/async_patch.dart"),
+ "_chrome": const LibraryInfo("_chrome/dart2js/chrome_dart2js.dart",
+ categories: "Client", documented: false),
+ "collection": const LibraryInfo("collection/collection.dart",
+ categories: "Client,Server,Embedded",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/collection_patch.dart"),
+ "convert": const LibraryInfo("convert/convert.dart",
+ categories: "Client,Server",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/convert_patch.dart"),
+ "core": const LibraryInfo("core/core.dart",
+ categories: "Client,Server,Embedded",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/core_patch.dart"),
+ "developer": const LibraryInfo("developer/developer.dart",
+ categories: "Client,Server,Embedded",
+ maturity: Maturity.UNSTABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/developer_patch.dart"),
+ "ffi": const LibraryInfo("ffi/ffi.dart",
+ categories: "Server",
+ // TODO(dacoharkes): Update maturity when we release dart:ffi.
+ // https://github.com/dart-lang/sdk/issues/34452
+ maturity: Maturity.EXPERIMENTAL),
+ "html": const LibraryInfo("html/dart2js/html_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ platforms: DART2JS_PLATFORM),
+ "html_common": const LibraryInfo("html/html_common/html_common.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ dart2jsPath: "html/html_common/html_common_dart2js.dart",
+ documented: false,
+ implementation: true),
+ "indexed_db": const LibraryInfo("indexed_db/dart2js/indexed_db_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ platforms: DART2JS_PLATFORM),
+ "_http":
+ const LibraryInfo("_http/http.dart", categories: "", documented: false),
+ "io": const LibraryInfo("io/io.dart",
+ categories: "Server",
+ dart2jsPatchPath: "_internal/js_runtime/lib/io_patch.dart"),
+ "isolate": const LibraryInfo("isolate/isolate.dart",
+ categories: "Client,Server",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/isolate_patch.dart"),
+ "js": const LibraryInfo("js/dart2js/js_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.STABLE,
+ platforms: DART2JS_PLATFORM),
+ "_js": const LibraryInfo("js/_js.dart",
+ categories: "Client",
+ dart2jsPatchPath: "js/_js_client.dart",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "js_util": const LibraryInfo("js_util/dart2js/js_util_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.STABLE,
+ platforms: DART2JS_PLATFORM),
+ "math": const LibraryInfo("math/math.dart",
+ categories: "Client,Server,Embedded",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/math_patch.dart"),
+ "mirrors": const LibraryInfo("mirrors/mirrors.dart",
+ categories: "Client,Server",
+ maturity: Maturity.UNSTABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/mirrors_patch_cfe.dart"),
+ "nativewrappers": const LibraryInfo("html/dartium/nativewrappers.dart",
+ categories: "Client",
+ implementation: true,
+ documented: false,
+ platforms: VM_PLATFORM),
+ "typed_data": const LibraryInfo("typed_data/typed_data.dart",
+ categories: "Client,Server,Embedded",
+ maturity: Maturity.STABLE,
+ dart2jsPatchPath: "_internal/js_runtime/lib/typed_data_patch.dart"),
+ "_native_typed_data": const LibraryInfo(
+ "_internal/js_runtime/lib/native_typed_data.dart",
+ categories: "",
+ implementation: true,
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "cli": const LibraryInfo("cli/cli.dart",
+ categories: "Server",
+ dart2jsPatchPath: "_internal/js_runtime/lib/cli_patch.dart"),
+ "svg": const LibraryInfo("svg/dart2js/svg_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ platforms: DART2JS_PLATFORM),
+ "wasm": const LibraryInfo("wasm/wasm.dart",
+ categories: "Server", maturity: Maturity.EXPERIMENTAL),
+ "web_audio": const LibraryInfo("web_audio/dart2js/web_audio_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ platforms: DART2JS_PLATFORM),
+ "web_gl": const LibraryInfo("web_gl/dart2js/web_gl_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ platforms: DART2JS_PLATFORM),
+ "web_sql": const LibraryInfo("web_sql/dart2js/web_sql_dart2js.dart",
+ categories: "Client",
+ maturity: Maturity.WEB_STABLE,
+ platforms: DART2JS_PLATFORM),
+ "_internal": const LibraryInfo("internal/internal.dart",
+ categories: "",
+ documented: false,
+ dart2jsPatchPath: "_internal/js_runtime/lib/internal_patch.dart"),
+ "_js_helper": const LibraryInfo("_internal/js_runtime/lib/js_helper.dart",
+ categories: "", documented: false, platforms: DART2JS_PLATFORM),
+ "_rti": const LibraryInfo("_internal/js_runtime/lib/rti.dart",
+ categories: "", documented: false, platforms: DART2JS_PLATFORM),
+ "_interceptors": const LibraryInfo(
+ "_internal/js_runtime/lib/interceptors.dart",
+ categories: "",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "_foreign_helper": const LibraryInfo(
+ "_internal/js_runtime/lib/foreign_helper.dart",
+ categories: "",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "_js_names": const LibraryInfo("_internal/js_runtime/lib/js_names.dart",
+ categories: "", documented: false, platforms: DART2JS_PLATFORM),
+ "_js_primitives": const LibraryInfo(
+ "_internal/js_runtime/lib/js_primitives.dart",
+ categories: "",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "_js_embedded_names": const LibraryInfo(
+ "_internal/js_runtime/lib/shared/embedded_names.dart",
+ categories: "",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "_async_await_error_codes": const LibraryInfo(
+ "_internal/js_runtime/lib/shared/async_await_error_codes.dart",
+ categories: "",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "_recipe_syntax": const LibraryInfo(
+ "_internal/js_runtime/lib/shared/recipe_syntax.dart",
+ categories: "",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+ "_metadata": const LibraryInfo("html/html_common/metadata.dart",
+ categories: "", documented: false, platforms: DART2JS_PLATFORM),
+};
+
+/**
+ * Information about a "dart:" library.
+ */
+class LibraryInfo {
+ /**
+ * Path to the library's *.dart file relative to this file.
+ */
+ final String path;
+
+ /**
+ * The categories in which the library can be used encoded as a
+ * comma-separated String.
+ */
+ final String _categories;
+
+ /**
+ * Path to the dart2js library's *.dart file relative to this file
+ * or null if dart2js uses the common library path defined above.
+ * Access using the [#getDart2JsPath()] method.
+ */
+ final String dart2jsPath;
+
+ /**
+ * Path to the dart2js library's patch file relative to this file
+ * or null if no dart2js patch file associated with this library.
+ * Access using the [#getDart2JsPatchPath()] method.
+ */
+ final String dart2jsPatchPath;
+
+ /**
+ * True if this library is documented and should be shown to the user.
+ */
+ final bool documented;
+
+ /**
+ * Bit flags indicating which platforms consume this library.
+ * See [DART2JS_LIBRARY] and [VM_LIBRARY].
+ */
+ final int platforms;
+
+ /**
+ * True if the library contains implementation details for another library.
+ * The implication is that these libraries are less commonly used
+ * and that tools like Dart Editor should not show these libraries
+ * in a list of all libraries unless the user specifically asks the tool to
+ * do so.
+ */
+ final bool implementation;
+
+ /**
+ * States the current maturity of this library.
+ */
+ final Maturity maturity;
+
+ const LibraryInfo(this.path,
+ {String categories: "",
+ this.dart2jsPath,
+ this.dart2jsPatchPath,
+ this.implementation: false,
+ this.documented: true,
+ this.maturity: Maturity.UNSPECIFIED,
+ this.platforms: DART2JS_PLATFORM | VM_PLATFORM})
+ : _categories = categories;
+
+ bool get isDart2jsLibrary => (platforms & DART2JS_PLATFORM) != 0;
+ bool get isVmLibrary => (platforms & VM_PLATFORM) != 0;
+
+ /**
+ * The categories in which the library can be used.
+ *
+ * If no categories are specified, the library is internal and can not be
+ * loaded by user code.
+ */
+ List<Category> get categories {
+ // `"".split(,)` returns [""] not [], so we handle that case separately.
+ if (_categories == "") return const <Category>[];
+ return _categories.split(",").map(parseCategory).toList();
+ }
+
+ bool get isInternal => categories.isEmpty;
+
+ /// The original "categories" String that was passed to the constructor.
+ ///
+ /// Can be used to construct a slightly modified copy of this LibraryInfo.
+ String get categoriesString {
+ return _categories;
+ }
+}
+
+/**
+ * Abstraction to capture the maturity of a library.
+ */
+class Maturity {
+ final int level;
+ final String name;
+ final String description;
+
+ const Maturity(this.level, this.name, this.description);
+
+ String toString() => "$name: $level\n$description\n";
+
+ static const Maturity DEPRECATED = const Maturity(0, "Deprecated",
+ "This library will be remove before next major release.");
+
+ static const Maturity EXPERIMENTAL = const Maturity(
+ 1,
+ "Experimental",
+ "This library is experimental and will likely change or be removed\n"
+ "in future versions.");
+
+ static const Maturity UNSTABLE = const Maturity(
+ 2,
+ "Unstable",
+ "This library is in still changing and have not yet endured\n"
+ "sufficient real-world testing.\n"
+ "Backwards-compatibility is NOT guaranteed.");
+
+ static const Maturity WEB_STABLE = const Maturity(
+ 3,
+ "Web Stable",
+ "This library is tracking the DOM evolution as defined by WC3.\n"
+ "Backwards-compatibility is NOT guaranteed.");
+
+ static const Maturity STABLE = const Maturity(
+ 4,
+ "Stable",
+ "The library is stable. API backwards-compatibility is guaranteed.\n"
+ "However implementation details might change.");
+
+ static const Maturity LOCKED = const Maturity(5, "Locked",
+ "This library will not change except when serious bugs are encountered.");
+
+ static const Maturity UNSPECIFIED = const Maturity(-1, "Unspecified",
+ "The maturity for this library has not been specified.");
+}
diff --git a/sdk_nnbd/lib/_internal/sdk_library_metadata/pubspec.yaml b/sdk_nnbd/lib/_internal/sdk_library_metadata/pubspec.yaml
new file mode 100644
index 0000000..08b5518
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/sdk_library_metadata/pubspec.yaml
@@ -0,0 +1,6 @@
+# Note: This package is not meant to be uploaded to pub. This file is used to
+# make it easer to depend on libraries.dart from sdk packages like dart2js.
+name: sdk_library_metadata
+publish_to: none
+environment:
+ sdk: '>=2.0.0 <3.0.0'
diff --git a/sdk_nnbd/lib/async/async.dart b/sdk_nnbd/lib/async/async.dart
new file mode 100644
index 0000000..b3a5dbd
--- /dev/null
+++ b/sdk_nnbd/lib/async/async.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Support for asynchronous programming,
+ * with classes such as Future and Stream.
+ *
+ * Understanding [Future]s and [Stream]s is a prerequisite for
+ * writing just about any Dart program.
+ *
+ * To use this library in your code:
+ *
+ * import 'dart:async';
+ *
+ * ## Future
+ *
+ * A Future object represents a computation whose return value
+ * might not yet be available.
+ * The Future returns the value of the computation
+ * when it completes at some time in the future.
+ * Futures are often used for potentially lengthy computations
+ * such as I/O and interaction with users.
+ *
+ * Many methods in the Dart libraries return Futures when
+ * performing tasks. For example, when binding an HttpServer
+ * to a host and port, the `bind()` method returns a Future.
+ *
+ * HttpServer.bind('127.0.0.1', 4444)
+ * .then((server) => print('${server.isBroadcast}'))
+ * .catchError(print);
+ *
+ * [Future.then] registers a callback function that runs
+ * when the Future's operation, in this case the `bind()` method,
+ * completes successfully.
+ * The value returned by the operation
+ * is passed into the callback function.
+ * In this example, the `bind()` method returns the HttpServer
+ * object. The callback function prints one of its properties.
+ * [Future.catchError] registers a callback function that
+ * runs if an error occurs within the Future.
+ *
+ * ## Stream
+ *
+ * A Stream provides an asynchronous sequence of data.
+ * Examples of data sequences include individual events, like mouse clicks,
+ * or sequential chunks of larger data, like multiple byte lists with the
+ * contents of a file
+ * such as mouse clicks, and a stream of byte lists read from a file.
+ * The following example opens a file for reading.
+ * [Stream.listen] registers a callback function that runs
+ * each time more data is available.
+ *
+ * Stream<List<int>> stream = new File('quotes.txt').openRead();
+ * stream.transform(utf8.decoder).listen(print);
+ *
+ * The stream emits a sequence of a list of bytes.
+ * The program must interpret the bytes or handle the raw byte data.
+ * Here, the code uses a UTF-8 decoder (provided in the `dart:convert` library)
+ * to convert the sequence of bytes into a sequence
+ * of Dart strings.
+ *
+ * Another common use of streams is for user-generated events
+ * in a web app: The following code listens for mouse clicks on a button.
+ *
+ * querySelector('#myButton').onClick.listen((_) => print('Click.'));
+ *
+ * ## Other resources
+ *
+ * * The [dart:async section of the library tour][asynchronous-programming]:
+ * A brief overview of asynchronous programming.
+ *
+ * * [Use Future-Based APIs][futures-tutorial]: A closer look at Futures and
+ * how to use them to write asynchronous Dart code.
+ *
+ * * [Futures and Error Handling][futures-error-handling]: Everything you
+ * wanted to know about handling errors and exceptions when working with
+ * Futures (but were afraid to ask).
+ *
+ * * [The Event Loop and Dart](https://www.dartlang.org/articles/event-loop/):
+ * Learn how Dart handles the event queue and microtask queue, so you can
+ * write better asynchronous code with fewer surprises.
+ *
+ * * [test package: Asynchronous Tests][test-readme]: How to test asynchronous
+ * code.
+ *
+ * [asynchronous-programming]: https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartasync---asynchronous-programming
+ * [futures-tutorial]: https://www.dartlang.org/docs/tutorials/futures/
+ * [futures-error-handling]: https://www.dartlang.org/articles/futures-and-error-handling/
+ * [test-readme]: https://pub.dartlang.org/packages/test
+ *
+ * {@category Core}
+ */
+library dart.async;
+
+import "dart:collection" show HashMap, IterableBase;
+import "dart:_internal"
+ show
+ CastStream,
+ CastStreamTransformer,
+ EmptyIterator,
+ IterableElementError,
+ printToZone,
+ printToConsole,
+ Since;
+
+part 'async_error.dart';
+part 'broadcast_stream_controller.dart';
+part 'deferred_load.dart';
+part 'future.dart';
+part 'future_impl.dart';
+part 'schedule_microtask.dart';
+part 'stream.dart';
+part 'stream_controller.dart';
+part 'stream_impl.dart';
+part 'stream_pipe.dart';
+part 'stream_transformers.dart';
+part 'timer.dart';
+part 'zone.dart';
diff --git a/sdk_nnbd/lib/async/async_error.dart b/sdk_nnbd/lib/async/async_error.dart
new file mode 100644
index 0000000..1520c54
--- /dev/null
+++ b/sdk_nnbd/lib/async/async_error.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+_invokeErrorHandler(
+ Function errorHandler, Object error, StackTrace stackTrace) {
+ if (errorHandler is ZoneBinaryCallback<dynamic, Null, Null>) {
+ // Dynamic invocation because we don't know the actual type of the
+ // first argument or the error object, but we should successfully call
+ // the handler if they match up.
+ // TODO(lrn): Should we? Why not the same below for the unary case?
+ return (errorHandler as dynamic)(error, stackTrace);
+ } else {
+ ZoneUnaryCallback unaryErrorHandler = errorHandler;
+ return unaryErrorHandler(error);
+ }
+}
diff --git a/sdk_nnbd/lib/async/async_sources.gni b/sdk_nnbd/lib/async/async_sources.gni
new file mode 100644
index 0000000..3299cd4
--- /dev/null
+++ b/sdk_nnbd/lib/async/async_sources.gni
@@ -0,0 +1,23 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# This file contains all sources for the dart:async library.
+async_sdk_sources = [
+ "async.dart",
+
+ # The above file needs to be first as it lists the parts below.
+ "async_error.dart",
+ "broadcast_stream_controller.dart",
+ "deferred_load.dart",
+ "future.dart",
+ "future_impl.dart",
+ "schedule_microtask.dart",
+ "stream.dart",
+ "stream_controller.dart",
+ "stream_impl.dart",
+ "stream_pipe.dart",
+ "stream_transformers.dart",
+ "timer.dart",
+ "zone.dart",
+]
diff --git a/sdk_nnbd/lib/async/broadcast_stream_controller.dart b/sdk_nnbd/lib/async/broadcast_stream_controller.dart
new file mode 100644
index 0000000..32e4582
--- /dev/null
+++ b/sdk_nnbd/lib/async/broadcast_stream_controller.dart
@@ -0,0 +1,510 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+class _BroadcastStream<T> extends _ControllerStream<T> {
+ _BroadcastStream(_StreamControllerLifecycle<T> controller)
+ : super(controller);
+
+ bool get isBroadcast => true;
+}
+
+class _BroadcastSubscription<T> extends _ControllerSubscription<T> {
+ static const int _STATE_EVENT_ID = 1;
+ static const int _STATE_FIRING = 2;
+ static const int _STATE_REMOVE_AFTER_FIRING = 4;
+ // TODO(lrn): Use the _state field on _ControllerSubscription to
+ // also store this state. Requires that the subscription implementation
+ // does not assume that it's use of the state integer is the only use.
+ int _eventState = 0; // Initialized to help dart2js type inference.
+
+ _BroadcastSubscription<T> _next;
+ _BroadcastSubscription<T> _previous;
+
+ _BroadcastSubscription(_StreamControllerLifecycle<T> controller,
+ void onData(T data), Function onError, void onDone(), bool cancelOnError)
+ : super(controller, onData, onError, onDone, cancelOnError) {
+ _next = _previous = this;
+ }
+
+ bool _expectsEvent(int eventId) => (_eventState & _STATE_EVENT_ID) == eventId;
+
+ void _toggleEventId() {
+ _eventState ^= _STATE_EVENT_ID;
+ }
+
+ bool get _isFiring => (_eventState & _STATE_FIRING) != 0;
+
+ void _setRemoveAfterFiring() {
+ assert(_isFiring);
+ _eventState |= _STATE_REMOVE_AFTER_FIRING;
+ }
+
+ bool get _removeAfterFiring =>
+ (_eventState & _STATE_REMOVE_AFTER_FIRING) != 0;
+
+ // The controller._recordPause doesn't do anything for a broadcast controller,
+ // so we don't bother calling it.
+ void _onPause() {}
+
+ // The controller._recordResume doesn't do anything for a broadcast
+ // controller, so we don't bother calling it.
+ void _onResume() {}
+
+ // _onCancel is inherited.
+}
+
+abstract class _BroadcastStreamController<T>
+ implements _StreamControllerBase<T> {
+ static const int _STATE_INITIAL = 0;
+ static const int _STATE_EVENT_ID = 1;
+ static const int _STATE_FIRING = 2;
+ static const int _STATE_CLOSED = 4;
+ static const int _STATE_ADDSTREAM = 8;
+
+ ControllerCallback onListen;
+ ControllerCancelCallback onCancel;
+
+ // State of the controller.
+ int _state;
+
+ // Double-linked list of active listeners.
+ _BroadcastSubscription<T> _firstSubscription;
+ _BroadcastSubscription<T> _lastSubscription;
+
+ // Extra state used during an [addStream] call.
+ _AddStreamState<T> _addStreamState;
+
+ /**
+ * Future returned by [close] and [done].
+ *
+ * The future is completed whenever the done event has been sent to all
+ * relevant listeners.
+ * The relevant listeners are the ones that were listening when [close] was
+ * called. When all of these have been canceled (sending the done event makes
+ * them cancel, but they can also be canceled before sending the event),
+ * this future completes.
+ *
+ * Any attempt to listen after calling [close] will throw, so there won't
+ * be any further listeners.
+ */
+ _Future _doneFuture;
+
+ _BroadcastStreamController(this.onListen, this.onCancel)
+ : _state = _STATE_INITIAL;
+
+ ControllerCallback get onPause {
+ throw new UnsupportedError(
+ "Broadcast stream controllers do not support pause callbacks");
+ }
+
+ void set onPause(void onPauseHandler()) {
+ throw new UnsupportedError(
+ "Broadcast stream controllers do not support pause callbacks");
+ }
+
+ ControllerCallback get onResume {
+ throw new UnsupportedError(
+ "Broadcast stream controllers do not support pause callbacks");
+ }
+
+ void set onResume(void onResumeHandler()) {
+ throw new UnsupportedError(
+ "Broadcast stream controllers do not support pause callbacks");
+ }
+
+ // StreamController interface.
+
+ Stream<T> get stream => new _BroadcastStream<T>(this);
+
+ StreamSink<T> get sink => new _StreamSinkWrapper<T>(this);
+
+ bool get isClosed => (_state & _STATE_CLOSED) != 0;
+
+ /**
+ * A broadcast controller is never paused.
+ *
+ * Each receiving stream may be paused individually, and they handle their
+ * own buffering.
+ */
+ bool get isPaused => false;
+
+ /** Whether there are currently one or more subscribers. */
+ bool get hasListener => !_isEmpty;
+
+ /**
+ * Test whether the stream has exactly one listener.
+ *
+ * Assumes that the stream has a listener (not [_isEmpty]).
+ */
+ bool get _hasOneListener {
+ assert(!_isEmpty);
+ return identical(_firstSubscription, _lastSubscription);
+ }
+
+ /** Whether an event is being fired (sent to some, but not all, listeners). */
+ bool get _isFiring => (_state & _STATE_FIRING) != 0;
+
+ bool get _isAddingStream => (_state & _STATE_ADDSTREAM) != 0;
+
+ bool get _mayAddEvent => (_state < _STATE_CLOSED);
+
+ _Future _ensureDoneFuture() {
+ if (_doneFuture != null) return _doneFuture;
+ return _doneFuture = new _Future();
+ }
+
+ // Linked list helpers
+
+ bool get _isEmpty => _firstSubscription == null;
+
+ /** Adds subscription to linked list of active listeners. */
+ void _addListener(_BroadcastSubscription<T> subscription) {
+ assert(identical(subscription._next, subscription));
+ subscription._eventState = (_state & _STATE_EVENT_ID);
+ // Insert in linked list as last subscription.
+ _BroadcastSubscription<T> oldLast = _lastSubscription;
+ _lastSubscription = subscription;
+ subscription._next = null;
+ subscription._previous = oldLast;
+ if (oldLast == null) {
+ _firstSubscription = subscription;
+ } else {
+ oldLast._next = subscription;
+ }
+ }
+
+ void _removeListener(_BroadcastSubscription<T> subscription) {
+ assert(identical(subscription._controller, this));
+ assert(!identical(subscription._next, subscription));
+ _BroadcastSubscription<T> previous = subscription._previous;
+ _BroadcastSubscription<T> next = subscription._next;
+ if (previous == null) {
+ // This was the first subscription.
+ _firstSubscription = next;
+ } else {
+ previous._next = next;
+ }
+ if (next == null) {
+ // This was the last subscription.
+ _lastSubscription = previous;
+ } else {
+ next._previous = previous;
+ }
+
+ subscription._next = subscription._previous = subscription;
+ }
+
+ // _StreamControllerLifecycle interface.
+
+ StreamSubscription<T> _subscribe(void onData(T data), Function onError,
+ void onDone(), bool cancelOnError) {
+ if (isClosed) {
+ onDone ??= _nullDoneHandler;
+ return new _DoneStreamSubscription<T>(onDone);
+ }
+ StreamSubscription<T> subscription = new _BroadcastSubscription<T>(
+ this, onData, onError, onDone, cancelOnError);
+ _addListener(subscription);
+ if (identical(_firstSubscription, _lastSubscription)) {
+ // Only one listener, so it must be the first listener.
+ _runGuarded(onListen);
+ }
+ return subscription;
+ }
+
+ Future _recordCancel(StreamSubscription<T> sub) {
+ _BroadcastSubscription<T> subscription = sub;
+ // If already removed by the stream, don't remove it again.
+ if (identical(subscription._next, subscription)) return null;
+ if (subscription._isFiring) {
+ subscription._setRemoveAfterFiring();
+ } else {
+ _removeListener(subscription);
+ // If we are currently firing an event, the empty-check is performed at
+ // the end of the listener loop instead of here.
+ if (!_isFiring && _isEmpty) {
+ _callOnCancel();
+ }
+ }
+ return null;
+ }
+
+ void _recordPause(StreamSubscription<T> subscription) {}
+ void _recordResume(StreamSubscription<T> subscription) {}
+
+ // EventSink interface.
+
+ Error _addEventError() {
+ if (isClosed) {
+ return new StateError("Cannot add new events after calling close");
+ }
+ assert(_isAddingStream);
+ return new StateError("Cannot add new events while doing an addStream");
+ }
+
+ void add(T data) {
+ if (!_mayAddEvent) throw _addEventError();
+ _sendData(data);
+ }
+
+ void addError(Object error, [StackTrace stackTrace]) {
+ error = _nonNullError(error);
+ if (!_mayAddEvent) throw _addEventError();
+ AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+ if (replacement != null) {
+ error = _nonNullError(replacement.error);
+ stackTrace = replacement.stackTrace;
+ }
+ _sendError(error, stackTrace);
+ }
+
+ Future close() {
+ if (isClosed) {
+ assert(_doneFuture != null);
+ return _doneFuture;
+ }
+ if (!_mayAddEvent) throw _addEventError();
+ _state |= _STATE_CLOSED;
+ Future doneFuture = _ensureDoneFuture();
+ _sendDone();
+ return doneFuture;
+ }
+
+ Future get done => _ensureDoneFuture();
+
+ Future addStream(Stream<T> stream, {bool cancelOnError}) {
+ if (!_mayAddEvent) throw _addEventError();
+ _state |= _STATE_ADDSTREAM;
+ _addStreamState = new _AddStreamState(this, stream, cancelOnError ?? false);
+ return _addStreamState.addStreamFuture;
+ }
+
+ // _EventSink interface, called from AddStreamState.
+ void _add(T data) {
+ _sendData(data);
+ }
+
+ void _addError(Object error, StackTrace stackTrace) {
+ _sendError(error, stackTrace);
+ }
+
+ void _close() {
+ assert(_isAddingStream);
+ _AddStreamState addState = _addStreamState;
+ _addStreamState = null;
+ _state &= ~_STATE_ADDSTREAM;
+ addState.complete();
+ }
+
+ // Event handling.
+ void _forEachListener(
+ void action(_BufferingStreamSubscription<T> subscription)) {
+ if (_isFiring) {
+ throw new StateError(
+ "Cannot fire new event. Controller is already firing an event");
+ }
+ if (_isEmpty) return;
+
+ // Get event id of this event.
+ int id = (_state & _STATE_EVENT_ID);
+ // Start firing (set the _STATE_FIRING bit). We don't do [onCancel]
+ // callbacks while firing, and we prevent reentrancy of this function.
+ //
+ // Set [_state]'s event id to the next event's id.
+ // Any listeners added while firing this event will expect the next event,
+ // not this one, and won't get notified.
+ _state ^= _STATE_EVENT_ID | _STATE_FIRING;
+ _BroadcastSubscription<T> subscription = _firstSubscription;
+ while (subscription != null) {
+ if (subscription._expectsEvent(id)) {
+ subscription._eventState |= _BroadcastSubscription._STATE_FIRING;
+ action(subscription);
+ subscription._toggleEventId();
+ _BroadcastSubscription<T> next = subscription._next;
+ if (subscription._removeAfterFiring) {
+ _removeListener(subscription);
+ }
+ subscription._eventState &= ~_BroadcastSubscription._STATE_FIRING;
+ subscription = next;
+ } else {
+ subscription = subscription._next;
+ }
+ }
+ _state &= ~_STATE_FIRING;
+
+ if (_isEmpty) {
+ _callOnCancel();
+ }
+ }
+
+ void _callOnCancel() {
+ assert(_isEmpty);
+ if (isClosed && _doneFuture._mayComplete) {
+ // When closed, _doneFuture is not null.
+ _doneFuture._asyncComplete(null);
+ }
+ _runGuarded(onCancel);
+ }
+}
+
+class _SyncBroadcastStreamController<T> extends _BroadcastStreamController<T>
+ implements SynchronousStreamController<T> {
+ _SyncBroadcastStreamController(void onListen(), void onCancel())
+ : super(onListen, onCancel);
+
+ // EventDispatch interface.
+
+ bool get _mayAddEvent => super._mayAddEvent && !_isFiring;
+
+ _addEventError() {
+ if (_isFiring) {
+ return new StateError(
+ "Cannot fire new event. Controller is already firing an event");
+ }
+ return super._addEventError();
+ }
+
+ void _sendData(T data) {
+ if (_isEmpty) return;
+ if (_hasOneListener) {
+ _state |= _BroadcastStreamController._STATE_FIRING;
+ _BroadcastSubscription<T> subscription = _firstSubscription;
+ subscription._add(data);
+ _state &= ~_BroadcastStreamController._STATE_FIRING;
+ if (_isEmpty) {
+ _callOnCancel();
+ }
+ return;
+ }
+ _forEachListener((_BufferingStreamSubscription<T> subscription) {
+ subscription._add(data);
+ });
+ }
+
+ void _sendError(Object error, StackTrace stackTrace) {
+ if (_isEmpty) return;
+ _forEachListener((_BufferingStreamSubscription<T> subscription) {
+ subscription._addError(error, stackTrace);
+ });
+ }
+
+ void _sendDone() {
+ if (!_isEmpty) {
+ _forEachListener((_BufferingStreamSubscription<T> subscription) {
+ subscription._close();
+ });
+ } else {
+ assert(_doneFuture != null);
+ assert(_doneFuture._mayComplete);
+ _doneFuture._asyncComplete(null);
+ }
+ }
+}
+
+class _AsyncBroadcastStreamController<T> extends _BroadcastStreamController<T> {
+ _AsyncBroadcastStreamController(void onListen(), void onCancel())
+ : super(onListen, onCancel);
+
+ // EventDispatch interface.
+
+ void _sendData(T data) {
+ for (_BroadcastSubscription<T> subscription = _firstSubscription;
+ subscription != null;
+ subscription = subscription._next) {
+ subscription._addPending(new _DelayedData<T>(data));
+ }
+ }
+
+ void _sendError(Object error, StackTrace stackTrace) {
+ for (_BroadcastSubscription<T> subscription = _firstSubscription;
+ subscription != null;
+ subscription = subscription._next) {
+ subscription._addPending(new _DelayedError(error, stackTrace));
+ }
+ }
+
+ void _sendDone() {
+ if (!_isEmpty) {
+ for (_BroadcastSubscription<T> subscription = _firstSubscription;
+ subscription != null;
+ subscription = subscription._next) {
+ subscription._addPending(const _DelayedDone());
+ }
+ } else {
+ assert(_doneFuture != null);
+ assert(_doneFuture._mayComplete);
+ _doneFuture._asyncComplete(null);
+ }
+ }
+}
+
+/**
+ * Stream controller that is used by [Stream.asBroadcastStream].
+ *
+ * This stream controller allows incoming events while it is firing
+ * other events. This is handled by delaying the events until the
+ * current event is done firing, and then fire the pending events.
+ *
+ * This class extends [_SyncBroadcastStreamController]. Events of
+ * an "asBroadcastStream" stream are always initiated by events
+ * on another stream, and it is fine to forward them synchronously.
+ */
+class _AsBroadcastStreamController<T> extends _SyncBroadcastStreamController<T>
+ implements _EventDispatch<T> {
+ _StreamImplEvents<T> _pending;
+
+ _AsBroadcastStreamController(void onListen(), void onCancel())
+ : super(onListen, onCancel);
+
+ bool get _hasPending => _pending != null && !_pending.isEmpty;
+
+ void _addPendingEvent(_DelayedEvent event) {
+ _pending ??= new _StreamImplEvents<T>();
+ _pending.add(event);
+ }
+
+ void add(T data) {
+ if (!isClosed && _isFiring) {
+ _addPendingEvent(new _DelayedData<T>(data));
+ return;
+ }
+ super.add(data);
+ while (_hasPending) {
+ _pending.handleNext(this);
+ }
+ }
+
+ void addError(Object error, [StackTrace stackTrace]) {
+ if (!isClosed && _isFiring) {
+ _addPendingEvent(new _DelayedError(error, stackTrace));
+ return;
+ }
+ if (!_mayAddEvent) throw _addEventError();
+ _sendError(error, stackTrace);
+ while (_hasPending) {
+ _pending.handleNext(this);
+ }
+ }
+
+ Future close() {
+ if (!isClosed && _isFiring) {
+ _addPendingEvent(const _DelayedDone());
+ _state |= _BroadcastStreamController._STATE_CLOSED;
+ return super.done;
+ }
+ Future result = super.close();
+ assert(!_hasPending);
+ return result;
+ }
+
+ void _callOnCancel() {
+ if (_hasPending) {
+ _pending.clear();
+ _pending = null;
+ }
+ super._callOnCancel();
+ }
+}
diff --git a/sdk_nnbd/lib/async/deferred_load.dart b/sdk_nnbd/lib/async/deferred_load.dart
new file mode 100644
index 0000000..f83d4b8
--- /dev/null
+++ b/sdk_nnbd/lib/async/deferred_load.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/**
+ * Indicates that loading of [libraryName] is deferred.
+ *
+ * This class is obsolete. Instead use the syntax:
+ * import "library.dart" deferred as prefix;
+ */
+@Deprecated("Dart sdk v. 1.8")
+class DeferredLibrary {
+ final String libraryName;
+ final String uri;
+
+ const DeferredLibrary(this.libraryName, {this.uri});
+
+ /**
+ * Ensure that [libraryName] has been loaded.
+ *
+ * If the library fails to load, the Future will complete with a
+ * DeferredLoadException.
+ */
+ external Future<Null> load();
+}
+
+/**
+ * Thrown when a deferred library fails to load.
+ */
+class DeferredLoadException implements Exception {
+ DeferredLoadException(this._s);
+ String toString() => "DeferredLoadException: '$_s'";
+ final String _s;
+}
diff --git a/sdk_nnbd/lib/async/future.dart b/sdk_nnbd/lib/async/future.dart
new file mode 100644
index 0000000..b9d22c1
--- /dev/null
+++ b/sdk_nnbd/lib/async/future.dart
@@ -0,0 +1,931 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/// A type representing values that are either `Future<T>` or `T`.
+///
+/// This class declaration is a public stand-in for an internal
+/// future-or-value generic type. References to this class are resolved to the
+/// internal type.
+///
+/// It is a compile-time error for any class to extend, mix in or implement
+/// `FutureOr`.
+///
+/// Note: the `FutureOr<T>` type is interpreted as `dynamic` in non strong-mode.
+///
+/// # Examples
+/// ``` dart
+/// // The `Future<T>.then` function takes a callback [f] that returns either
+/// // an `S` or a `Future<S>`.
+/// Future<S> then<S>(FutureOr<S> f(T x), ...);
+///
+/// // `Completer<T>.complete` takes either a `T` or `Future<T>`.
+/// void complete(FutureOr<T> value);
+/// ```
+///
+/// # Advanced
+/// The `FutureOr<int>` type is actually the "type union" of the types `int` and
+/// `Future<int>`. This type union is defined in such a way that
+/// `FutureOr<Object>` is both a super- and sub-type of `Object` (sub-type
+/// because `Object` is one of the types of the union, super-type because
+/// `Object` is a super-type of both of the types of the union). Together it
+/// means that `FutureOr<Object>` is equivalent to `Object`.
+///
+/// As a corollary, `FutureOr<Object>` is equivalent to
+/// `FutureOr<FutureOr<Object>>`, `FutureOr<Future<Object>>` is equivalent to
+/// `Future<Object>`.
+abstract class FutureOr<T> {
+ // Private generative constructor, so that it is not subclassable, mixable, or
+ // instantiable.
+ FutureOr._() {
+ throw new UnsupportedError("FutureOr can't be instantiated");
+ }
+}
+
+/**
+ * An object representing a delayed computation.
+ *
+ * A [Future] is used to represent a potential value, or error,
+ * that will be available at some time in the future.
+ * Receivers of a [Future] can register callbacks
+ * that handle the value or error once it is available.
+ * For example:
+ *
+ * Future<int> future = getFuture();
+ * future.then((value) => handleValue(value))
+ * .catchError((error) => handleError(error));
+ *
+ * A [Future] can be completed in two ways:
+ * with a value ("the future succeeds")
+ * or with an error ("the future fails").
+ * Users can install callbacks for each case.
+ *
+ * In some cases we say that a future is completed with another future.
+ * This is a short way of stating that the future is completed in the same way,
+ * with the same value or error,
+ * as the other future once that completes.
+ * Whenever a function in the core library may complete a future
+ * (for example [Completer.complete] or [new Future.value]),
+ * then it also accepts another future and does this work for the developer.
+ *
+ * The result of registering a pair of callbacks is a new Future (the
+ * "successor") which in turn is completed with the result of invoking the
+ * corresponding callback.
+ * The successor is completed with an error if the invoked callback throws.
+ * For example:
+ * ```
+ * Future<int> successor = future.then((int value) {
+ * // Invoked when the future is completed with a value.
+ * return 42; // The successor is completed with the value 42.
+ * },
+ * onError: (e) {
+ * // Invoked when the future is completed with an error.
+ * if (canHandle(e)) {
+ * return 499; // The successor is completed with the value 499.
+ * } else {
+ * throw e; // The successor is completed with the error e.
+ * }
+ * });
+ * ```
+ *
+ * If a future does not have a successor when it completes with an error,
+ * it forwards the error message to the global error-handler.
+ * This behavior makes sure that no error is silently dropped.
+ * However, it also means that error handlers should be installed early,
+ * so that they are present as soon as a future is completed with an error.
+ * The following example demonstrates this potential bug:
+ * ```
+ * var future = getFuture();
+ * new Timer(new Duration(milliseconds: 5), () {
+ * // The error-handler is not attached until 5 ms after the future has
+ * // been received. If the future fails before that, the error is
+ * // forwarded to the global error-handler, even though there is code
+ * // (just below) to eventually handle the error.
+ * future.then((value) { useValue(value); },
+ * onError: (e) { handleError(e); });
+ * });
+ * ```
+ *
+ * When registering callbacks, it's often more readable to register the two
+ * callbacks separately, by first using [then] with one argument
+ * (the value handler) and using a second [catchError] for handling errors.
+ * Each of these will forward the result that they don't handle
+ * to their successors, and together they handle both value and error result.
+ * It also has the additional benefit of the [catchError] handling errors in the
+ * [then] value callback too.
+ * Using sequential handlers instead of parallel ones often leads to code that
+ * is easier to reason about.
+ * It also makes asynchronous code very similar to synchronous code:
+ * ```
+ * // Synchronous code.
+ * try {
+ * int value = foo();
+ * return bar(value);
+ * } catch (e) {
+ * return 499;
+ * }
+ * ```
+ *
+ * Equivalent asynchronous code, based on futures:
+ * ```
+ * Future<int> future = new Future(foo); // Result of foo() as a future.
+ * future.then((int value) => bar(value))
+ * .catchError((e) => 499);
+ * ```
+ *
+ * Similar to the synchronous code, the error handler (registered with
+ * [catchError]) is handling any errors thrown by either `foo` or `bar`.
+ * If the error-handler had been registered as the `onError` parameter of
+ * the `then` call, it would not catch errors from the `bar` call.
+ *
+ * Futures can have more than one callback-pair registered. Each successor is
+ * treated independently and is handled as if it was the only successor.
+ *
+ * A future may also fail to ever complete. In that case, no callbacks are
+ * called.
+ */
+abstract class Future<T> {
+ /// A `Future<Null>` completed with `null`.
+ static final _Future<Null> _nullFuture =
+ new _Future<Null>.zoneValue(null, Zone.root);
+
+ /// A `Future<bool>` completed with `false`.
+ static final _Future<bool> _falseFuture =
+ new _Future<bool>.zoneValue(false, Zone.root);
+
+ /**
+ * Creates a future containing the result of calling [computation]
+ * asynchronously with [Timer.run].
+ *
+ * If the result of executing [computation] throws, the returned future is
+ * completed with the error.
+ *
+ * If the returned value is itself a [Future], completion of
+ * the created future will wait until the returned future completes,
+ * and will then complete with the same result.
+ *
+ * If a non-future value is returned, the returned future is completed
+ * with that value.
+ */
+ factory Future(FutureOr<T> computation()) {
+ _Future<T> result = new _Future<T>();
+ Timer.run(() {
+ try {
+ result._complete(computation());
+ } catch (e, s) {
+ _completeWithErrorCallback(result, e, s);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Creates a future containing the result of calling [computation]
+ * asynchronously with [scheduleMicrotask].
+ *
+ * If executing [computation] throws,
+ * the returned future is completed with the thrown error.
+ *
+ * If calling [computation] returns a [Future], completion of
+ * the created future will wait until the returned future completes,
+ * and will then complete with the same result.
+ *
+ * If calling [computation] returns a non-future value,
+ * the returned future is completed with that value.
+ */
+ factory Future.microtask(FutureOr<T> computation()) {
+ _Future<T> result = new _Future<T>();
+ scheduleMicrotask(() {
+ try {
+ result._complete(computation());
+ } catch (e, s) {
+ _completeWithErrorCallback(result, e, s);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Returns a future containing the result of immediately calling
+ * [computation].
+ *
+ * If calling [computation] throws, the returned future is completed with the
+ * error.
+ *
+ * If calling [computation] returns a `Future<T>`, that future is returned.
+ *
+ * If calling [computation] returns a non-future value,
+ * a future is returned which has been completed with that value.
+ */
+ factory Future.sync(FutureOr<T> computation()) {
+ try {
+ var result = computation();
+ if (result is Future<T>) {
+ return result;
+ } else {
+ return new _Future<T>.value(result);
+ }
+ } catch (error, stackTrace) {
+ var future = new _Future<T>();
+ AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+ if (replacement != null) {
+ future._asyncCompleteError(
+ _nonNullError(replacement.error), replacement.stackTrace);
+ } else {
+ future._asyncCompleteError(error, stackTrace);
+ }
+ return future;
+ }
+ }
+
+ /**
+ * Creates a future completed with [value].
+ *
+ * If [value] is a future, the created future waits for the
+ * [value] future to complete, and then completes with the same result.
+ * Since a [value] future can complete with an error, so can the future
+ * created by [Future.value], even if the name suggests otherwise.
+ *
+ * If [value] is not a [Future], the created future is completed
+ * with the [value] value,
+ * equivalently to `new Future<T>.sync(() => value)`.
+ *
+ * Use [Completer] to create a future and complete it later.
+ */
+ factory Future.value([FutureOr<T> value]) {
+ return new _Future<T>.immediate(value);
+ }
+
+ /**
+ * Creates a future that completes with an error.
+ *
+ * The created future will be completed with an error in a future microtask.
+ * This allows enough time for someone to add an error handler on the future.
+ * If an error handler isn't added before the future completes, the error
+ * will be considered unhandled.
+ *
+ * If [error] is `null`, it is replaced by a [NullThrownError].
+ *
+ * Use [Completer] to create a future and complete it later.
+ */
+ factory Future.error(Object error, [StackTrace stackTrace]) {
+ error = _nonNullError(error);
+ if (!identical(Zone.current, _rootZone)) {
+ AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+ if (replacement != null) {
+ error = _nonNullError(replacement.error);
+ stackTrace = replacement.stackTrace;
+ }
+ }
+ return new _Future<T>.immediateError(error, stackTrace);
+ }
+
+ /**
+ * Creates a future that runs its computation after a delay.
+ *
+ * The [computation] will be executed after the given [duration] has passed,
+ * and the future is completed with the result of the computation.
+ *
+ * If [computation] returns a future,
+ * the future returned by this constructor will complete with the value or
+ * error of that future.
+ *
+ * If the duration is 0 or less,
+ * it completes no sooner than in the next event-loop iteration,
+ * after all microtasks have run.
+ *
+ * If [computation] is omitted,
+ * it will be treated as if [computation] was `() => null`,
+ * and the future will eventually complete with the `null` value.
+ *
+ * If calling [computation] throws, the created future will complete with the
+ * error.
+ *
+ * See also [Completer] for a way to create and complete a future at a
+ * later time that isn't necessarily after a known fixed duration.
+ */
+ factory Future.delayed(Duration duration, [FutureOr<T> computation()]) {
+ _Future<T> result = new _Future<T>();
+ new Timer(duration, () {
+ if (computation == null) {
+ result._complete(null);
+ } else {
+ try {
+ result._complete(computation());
+ } catch (e, s) {
+ _completeWithErrorCallback(result, e, s);
+ }
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Waits for multiple futures to complete and collects their results.
+ *
+ * Returns a future which will complete once all the provided futures
+ * have completed, either with their results, or with an error if any
+ * of the provided futures fail.
+ *
+ * The value of the returned future will be a list of all the values that
+ * were produced in the order that the futures are provided by iterating
+ * [futures].
+ *
+ * If any future completes with an error,
+ * then the returned future completes with that error.
+ * If further futures also complete with errors, those errors are discarded.
+ *
+ * If `eagerError` is true, the returned future completes with an error
+ * immediately on the first error from one of the futures. Otherwise all
+ * futures must complete before the returned future is completed (still with
+ * the first error; the remaining errors are silently dropped).
+ *
+ * In the case of an error, [cleanUp] (if provided), is invoked on any
+ * non-null result of successful futures.
+ * This makes it possible to `cleanUp` resources that would otherwise be
+ * lost (since the returned future does not provide access to these values).
+ * The [cleanUp] function is unused if there is no error.
+ *
+ * The call to [cleanUp] should not throw. If it does, the error will be an
+ * uncaught asynchronous error.
+ */
+ static Future<List<T>> wait<T>(Iterable<Future<T>> futures,
+ {bool eagerError: false, void cleanUp(T successValue)}) {
+ final _Future<List<T>> result = new _Future<List<T>>();
+ List<T> values; // Collects the values. Set to null on error.
+ int remaining = 0; // How many futures are we waiting for.
+ var error; // The first error from a future.
+ StackTrace stackTrace; // The stackTrace that came with the error.
+
+ // Handle an error from any of the futures.
+ // TODO(jmesserly): use `void` return type once it can be inferred for the
+ // `then` call below.
+ handleError(theError, StackTrace theStackTrace) {
+ remaining--;
+ if (values != null) {
+ if (cleanUp != null) {
+ for (var value in values) {
+ if (value != null) {
+ // Ensure errors from cleanUp are uncaught.
+ new Future.sync(() {
+ cleanUp(value);
+ });
+ }
+ }
+ }
+ values = null;
+ if (remaining == 0 || eagerError) {
+ result._completeError(theError, theStackTrace);
+ } else {
+ error = theError;
+ stackTrace = theStackTrace;
+ }
+ } else if (remaining == 0 && !eagerError) {
+ result._completeError(error, stackTrace);
+ }
+ }
+
+ try {
+ // As each future completes, put its value into the corresponding
+ // position in the list of values.
+ for (var future in futures) {
+ int pos = remaining;
+ future.then((T value) {
+ remaining--;
+ if (values != null) {
+ values[pos] = value;
+ if (remaining == 0) {
+ result._completeWithValue(values);
+ }
+ } else {
+ if (cleanUp != null && value != null) {
+ // Ensure errors from cleanUp are uncaught.
+ new Future.sync(() {
+ cleanUp(value);
+ });
+ }
+ if (remaining == 0 && !eagerError) {
+ result._completeError(error, stackTrace);
+ }
+ }
+ }, onError: handleError);
+ // Increment the 'remaining' after the call to 'then'.
+ // If that call throws, we don't expect any future callback from
+ // the future, and we also don't increment remaining.
+ remaining++;
+ }
+ if (remaining == 0) {
+ return new Future.value(const []);
+ }
+ values = new List<T>(remaining);
+ } catch (e, st) {
+ // The error must have been thrown while iterating over the futures
+ // list, or while installing a callback handler on the future.
+ if (remaining == 0 || eagerError) {
+ // Throw a new Future.error.
+ // Don't just call `result._completeError` since that would propagate
+ // the error too eagerly, not giving the callers time to install
+ // error handlers.
+ // Also, don't use `_asyncCompleteError` since that one doesn't give
+ // zones the chance to intercept the error.
+ return new Future.error(e, st);
+ } else {
+ // Don't allocate a list for values, thus indicating that there was an
+ // error.
+ // Set error to the caught exception.
+ error = e;
+ stackTrace = st;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the result of the first future in [futures] to complete.
+ *
+ * The returned future is completed with the result of the first
+ * future in [futures] to report that it is complete,
+ * whether it's with a value or an error.
+ * The results of all the other futures are discarded.
+ *
+ * If [futures] is empty, or if none of its futures complete,
+ * the returned future never completes.
+ */
+ static Future<T> any<T>(Iterable<Future<T>> futures) {
+ var completer = new Completer<T>.sync();
+ var onValue = (T value) {
+ if (!completer.isCompleted) completer.complete(value);
+ };
+ var onError = (error, StackTrace stack) {
+ if (!completer.isCompleted) completer.completeError(error, stack);
+ };
+ for (var future in futures) {
+ future.then(onValue, onError: onError);
+ }
+ return completer.future;
+ }
+
+ /**
+ * Performs an action for each element of the iterable, in turn.
+ *
+ * The [action] may be either synchronous or asynchronous.
+ *
+ * Calls [action] with each element in [elements] in order.
+ * If the call to [action] returns a `Future<T>`, the iteration waits
+ * until the future is completed before continuing with the next element.
+ *
+ * Returns a [Future] that completes with `null` when all elements have been
+ * processed.
+ *
+ * Non-[Future] return values, and completion-values of returned [Future]s,
+ * are discarded.
+ *
+ * Any error from [action], synchronous or asynchronous,
+ * will stop the iteration and be reported in the returned [Future].
+ */
+ static Future forEach<T>(Iterable<T> elements, FutureOr action(T element)) {
+ var iterator = elements.iterator;
+ return doWhile(() {
+ if (!iterator.moveNext()) return false;
+ var result = action(iterator.current);
+ if (result is Future) return result.then(_kTrue);
+ return true;
+ });
+ }
+
+ // Constant `true` function, used as callback by [forEach].
+ static bool _kTrue(_) => true;
+
+ /**
+ * Performs an operation repeatedly until it returns `false`.
+ *
+ * The operation, [action], may be either synchronous or asynchronous.
+ *
+ * The operation is called repeatedly as long as it returns either the [bool]
+ * value `true` or a `Future<bool>` which completes with the value `true`.
+ *
+ * If a call to [action] returns `false` or a [Future] that completes to
+ * `false`, iteration ends and the future returned by [doWhile] is completed
+ * with a `null` value.
+ *
+ * If a call to [action] throws or a future returned by [action] completes
+ * with an error, iteration ends and the future returned by [doWhile]
+ * completes with the same error.
+ *
+ * Calls to [action] may happen at any time,
+ * including immediately after calling `doWhile`.
+ * The only restriction is a new call to [action] won't happen before
+ * the previous call has returned, and if it returned a `Future<bool>`, not
+ * until that future has completed.
+ */
+ static Future doWhile(FutureOr<bool> action()) {
+ _Future doneSignal = new _Future();
+ void Function(bool) nextIteration;
+ // Bind this callback explicitly so that each iteration isn't bound in the
+ // context of all the previous iterations' callbacks.
+ // This avoids, e.g., deeply nested stack traces from the stack trace
+ // package.
+ nextIteration = Zone.current.bindUnaryCallbackGuarded((bool keepGoing) {
+ while (keepGoing) {
+ FutureOr<bool> result;
+ try {
+ result = action();
+ } catch (error, stackTrace) {
+ // Cannot use _completeWithErrorCallback because it completes
+ // the future synchronously.
+ _asyncCompleteWithErrorCallback(doneSignal, error, stackTrace);
+ return;
+ }
+ if (result is Future<bool>) {
+ result.then(nextIteration, onError: doneSignal._completeError);
+ return;
+ }
+ keepGoing = result;
+ }
+ doneSignal._complete(null);
+ });
+ nextIteration(true);
+ return doneSignal;
+ }
+
+ /**
+ * Register callbacks to be called when this future completes.
+ *
+ * When this future completes with a value,
+ * the [onValue] callback will be called with that value.
+ * If this future is already completed, the callback will not be called
+ * immediately, but will be scheduled in a later microtask.
+ *
+ * If [onError] is provided, and this future completes with an error,
+ * the `onError` callback is called with that error and its stack trace.
+ * The `onError` callback must accept either one argument or two arguments
+ * where the latter is a [StackTrace].
+ * If `onError` accepts two arguments,
+ * it is called with both the error and the stack trace,
+ * otherwise it is called with just the error object.
+ * The `onError` callback must return a value or future that can be used
+ * to complete the returned future, so it must be something assignable to
+ * `FutureOr<R>`.
+ *
+ * Returns a new [Future]
+ * which is completed with the result of the call to `onValue`
+ * (if this future completes with a value)
+ * or to `onError` (if this future completes with an error).
+ *
+ * If the invoked callback throws,
+ * the returned future is completed with the thrown error
+ * and a stack trace for the error.
+ * In the case of `onError`,
+ * if the exception thrown is `identical` to the error argument to `onError`,
+ * the throw is considered a rethrow,
+ * and the original stack trace is used instead.
+ *
+ * If the callback returns a [Future],
+ * the future returned by `then` will be completed with
+ * the same result as the future returned by the callback.
+ *
+ * If [onError] is not given, and this future completes with an error,
+ * the error is forwarded directly to the returned future.
+ *
+ * In most cases, it is more readable to use [catchError] separately, possibly
+ * with a `test` parameter, instead of handling both value and error in a
+ * single [then] call.
+ *
+ * Note that futures don't delay reporting of errors until listeners are
+ * added. If the first `then` or `catchError` call happens after this future
+ * has completed with an error then the error is reported as unhandled error.
+ * See the description on [Future].
+ */
+ Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError});
+
+ /**
+ * Handles errors emitted by this [Future].
+ *
+ * This is the asynchronous equivalent of a "catch" block.
+ *
+ * Returns a new [Future] that will be completed with either the result of
+ * this future or the result of calling the `onError` callback.
+ *
+ * If this future completes with a value,
+ * the returned future completes with the same value.
+ *
+ * If this future completes with an error,
+ * then [test] is first called with the error value.
+ *
+ * If `test` returns false, the exception is not handled by this `catchError`,
+ * and the returned future completes with the same error and stack trace
+ * as this future.
+ *
+ * If `test` returns `true`,
+ * [onError] is called with the error and possibly stack trace,
+ * and the returned future is completed with the result of this call
+ * in exactly the same way as for [then]'s `onError`.
+ *
+ * If `test` is omitted, it defaults to a function that always returns true.
+ * The `test` function should not throw, but if it does, it is handled as
+ * if the `onError` function had thrown.
+ *
+ * Note that futures don't delay reporting of errors until listeners are
+ * added. If the first `catchError` (or `then`) call happens after this future
+ * has completed with an error then the error is reported as unhandled error.
+ * See the description on [Future].
+ */
+ // The `Function` below stands for one of two types:
+ // - (dynamic) -> FutureOr<T>
+ // - (dynamic, StackTrace) -> FutureOr<T>
+ // Given that there is a `test` function that is usually used to do an
+ // `isCheck` we should also expect functions that take a specific argument.
+ // Note: making `catchError` return a `Future<T>` in non-strong mode could be
+ // a breaking change.
+ Future<T> catchError(Function onError, {bool test(Object error)});
+
+ /**
+ * Registers a function to be called when this future completes.
+ *
+ * The [action] function is called when this future completes, whether it
+ * does so with a value or with an error.
+ *
+ * This is the asynchronous equivalent of a "finally" block.
+ *
+ * The future returned by this call, `f`, will complete the same way
+ * as this future unless an error occurs in the [action] call, or in
+ * a [Future] returned by the [action] call. If the call to [action]
+ * does not return a future, its return value is ignored.
+ *
+ * If the call to [action] throws, then `f` is completed with the
+ * thrown error.
+ *
+ * If the call to [action] returns a [Future], `f2`, then completion of
+ * `f` is delayed until `f2` completes. If `f2` completes with
+ * an error, that will be the result of `f` too. The value of `f2` is always
+ * ignored.
+ *
+ * This method is equivalent to:
+ *
+ * Future<T> whenComplete(action()) {
+ * return this.then((v) {
+ * var f2 = action();
+ * if (f2 is Future) return f2.then((_) => v);
+ * return v
+ * }, onError: (e) {
+ * var f2 = action();
+ * if (f2 is Future) return f2.then((_) { throw e; });
+ * throw e;
+ * });
+ * }
+ */
+ Future<T> whenComplete(FutureOr action());
+
+ /**
+ * Creates a [Stream] containing the result of this future.
+ *
+ * The stream will produce single data or error event containing the
+ * completion result of this future, and then it will close with a
+ * done event.
+ *
+ * If the future never completes, the stream will not produce any events.
+ */
+ Stream<T> asStream();
+
+ /**
+ * Time-out the future computation after [timeLimit] has passed.
+ *
+ * Returns a new future that completes with the same value as this future,
+ * if this future completes in time.
+ *
+ * If this future does not complete before `timeLimit` has passed,
+ * the [onTimeout] action is executed instead, and its result (whether it
+ * returns or throws) is used as the result of the returned future.
+ * The [onTimeout] function must return a [T] or a `Future<T>`.
+ *
+ * If `onTimeout` is omitted, a timeout will cause the returned future to
+ * complete with a [TimeoutException].
+ */
+ Future<T> timeout(Duration timeLimit, {FutureOr<T> onTimeout()});
+}
+
+/**
+ * Thrown when a scheduled timeout happens while waiting for an async result.
+ */
+class TimeoutException implements Exception {
+ /** Description of the cause of the timeout. */
+ final String message;
+ /** The duration that was exceeded. */
+ final Duration duration;
+
+ TimeoutException(this.message, [this.duration]);
+
+ String toString() {
+ String result = "TimeoutException";
+ if (duration != null) result = "TimeoutException after $duration";
+ if (message != null) result = "$result: $message";
+ return result;
+ }
+}
+
+/**
+ * A way to produce Future objects and to complete them later
+ * with a value or error.
+ *
+ * Most of the time, the simplest way to create a future is to just use
+ * one of the [Future] constructors to capture the result of a single
+ * asynchronous computation:
+ * ```
+ * new Future(() { doSomething(); return result; });
+ * ```
+ * or, if the future represents the result of a sequence of asynchronous
+ * computations, they can be chained using [Future.then] or similar functions
+ * on [Future]:
+ * ```
+ * Future doStuff(){
+ * return someAsyncOperation().then((result) {
+ * return someOtherAsyncOperation(result);
+ * });
+ * }
+ * ```
+ * If you do need to create a Future from scratch — for example,
+ * when you're converting a callback-based API into a Future-based
+ * one — you can use a Completer as follows:
+ * ```
+ * class AsyncOperation {
+ * Completer _completer = new Completer();
+ *
+ * Future<T> doOperation() {
+ * _startOperation();
+ * return _completer.future; // Send future object back to client.
+ * }
+ *
+ * // Something calls this when the value is ready.
+ * void _finishOperation(T result) {
+ * _completer.complete(result);
+ * }
+ *
+ * // If something goes wrong, call this.
+ * void _errorHappened(error) {
+ * _completer.completeError(error);
+ * }
+ * }
+ * ```
+ */
+abstract class Completer<T> {
+ /**
+ * Creates a new completer.
+ *
+ * The general workflow for creating a new future is to 1) create a
+ * new completer, 2) hand out its future, and, at a later point, 3) invoke
+ * either [complete] or [completeError].
+ *
+ * The completer completes the future asynchronously. That means that
+ * callbacks registered on the future are not called immediately when
+ * [complete] or [completeError] is called. Instead the callbacks are
+ * delayed until a later microtask.
+ *
+ * Example:
+ * ```
+ * var completer = new Completer();
+ * handOut(completer.future);
+ * later: {
+ * completer.complete('completion value');
+ * }
+ * ```
+ */
+ factory Completer() => new _AsyncCompleter<T>();
+
+ /**
+ * Completes the future synchronously.
+ *
+ * This constructor should be avoided unless the completion of the future is
+ * known to be the final result of another asynchronous operation. If in doubt
+ * use the default [Completer] constructor.
+ *
+ * Using an normal, asynchronous, completer will never give the wrong
+ * behavior, but using a synchronous completer incorrectly can cause
+ * otherwise correct programs to break.
+ *
+ * A synchronous completer is only intended for optimizing event
+ * propagation when one asynchronous event immediately triggers another.
+ * It should not be used unless the calls to [complete] and [completeError]
+ * are guaranteed to occur in places where it won't break `Future` invariants.
+ *
+ * Completing synchronously means that the completer's future will be
+ * completed immediately when calling the [complete] or [completeError]
+ * method on a synchronous completer, which also calls any callbacks
+ * registered on that future.
+ *
+ * Completing synchronously must not break the rule that when you add a
+ * callback on a future, that callback must not be called until the code
+ * that added the callback has completed.
+ * For that reason, a synchronous completion must only occur at the very end
+ * (in "tail position") of another synchronous event,
+ * because at that point, completing the future immediately is be equivalent
+ * to returning to the event loop and completing the future in the next
+ * microtask.
+ *
+ * Example:
+ *
+ * var completer = new Completer.sync();
+ * // The completion is the result of the asynchronous onDone event.
+ * // No other operation is performed after the completion. It is safe
+ * // to use the Completer.sync constructor.
+ * stream.listen(print, onDone: () { completer.complete("done"); });
+ *
+ * Bad example. Do not use this code. Only for illustrative purposes:
+ *
+ * var completer = new Completer.sync();
+ * completer.future.then((_) { bar(); });
+ * // The completion is the result of the asynchronous onDone event.
+ * // However, there is still code executed after the completion. This
+ * // operation is *not* safe.
+ * stream.listen(print, onDone: () {
+ * completer.complete("done");
+ * foo(); // In this case, foo() runs after bar().
+ * });
+ */
+ factory Completer.sync() => new _SyncCompleter<T>();
+
+ /**
+ * The future that is completed by this completer.
+ *
+ * The future that is completed when [complete] or [completeError] is called.
+ */
+ Future<T> get future;
+
+ /**
+ * Completes [future] with the supplied values.
+ *
+ * The value must be either a value of type [T]
+ * or a future of type `Future<T>`.
+ *
+ * If the value is itself a future, the completer will wait for that future
+ * to complete, and complete with the same result, whether it is a success
+ * or an error.
+ *
+ * Calling [complete] or [completeError] must be done at most once.
+ *
+ * All listeners on the future are informed about the value.
+ */
+ void complete([FutureOr<T> value]);
+
+ /**
+ * Complete [future] with an error.
+ *
+ * Calling [complete] or [completeError] must be done at most once.
+ *
+ * Completing a future with an error indicates that an exception was thrown
+ * while trying to produce a value.
+ *
+ * If [error] is `null`, it is replaced by a [NullThrownError].
+ *
+ * If `error` is a `Future`, the future itself is used as the error value.
+ * If you want to complete with the result of the future, you can use:
+ * ```
+ * thisCompleter.complete(theFuture)
+ * ```
+ * or if you only want to handle an error from the future:
+ * ```
+ * theFuture.catchError(thisCompleter.completeError);
+ * ```
+ */
+ void completeError(Object error, [StackTrace stackTrace]);
+
+ /**
+ * Whether the [future] has been completed.
+ *
+ * Reflects whether [complete] or [completeError] has been called.
+ * A `true` value doesn't necessarily mean that listeners of this future
+ * have been invoked yet, either because the completer usually waits until
+ * a later microtask to propagate the result, or because [complete]
+ * was called with a future that hasn't completed yet.
+ *
+ * When this value is `true`, [complete] and [completeError] must not be
+ * called again.
+ */
+ bool get isCompleted;
+}
+
+// Helper function completing a _Future with error, but checking the zone
+// for error replacement first.
+void _completeWithErrorCallback(_Future result, error, StackTrace stackTrace) {
+ AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+ if (replacement != null) {
+ error = _nonNullError(replacement.error);
+ stackTrace = replacement.stackTrace;
+ }
+ result._completeError(error, stackTrace);
+}
+
+// Like [_completeWithErrorCallback] but completes asynchronously.
+void _asyncCompleteWithErrorCallback(
+ _Future result, error, StackTrace stackTrace) {
+ AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+ if (replacement != null) {
+ error = _nonNullError(replacement.error);
+ stackTrace = replacement.stackTrace;
+ }
+ result._asyncCompleteError(error, stackTrace);
+}
+
+/** Helper function that converts `null` to a [NullThrownError]. */
+Object _nonNullError(Object error) => error ?? new NullThrownError();
diff --git a/sdk_nnbd/lib/async/future_impl.dart b/sdk_nnbd/lib/async/future_impl.dart
new file mode 100644
index 0000000..1ec0791
--- /dev/null
+++ b/sdk_nnbd/lib/async/future_impl.dart
@@ -0,0 +1,812 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/** The onValue and onError handlers return either a value or a future */
+typedef FutureOr<T> _FutureOnValue<S, T>(S value);
+/** Test used by [Future.catchError] to handle skip some errors. */
+typedef bool _FutureErrorTest(Object error);
+/** Used by [WhenFuture]. */
+typedef dynamic _FutureAction();
+
+abstract class _Completer<T> implements Completer<T> {
+ final _Future<T> future = new _Future<T>();
+
+ void complete([FutureOr<T> value]);
+
+ void completeError(Object error, [StackTrace stackTrace]) {
+ error = _nonNullError(error);
+ if (!future._mayComplete) throw new StateError("Future already completed");
+ AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+ if (replacement != null) {
+ error = _nonNullError(replacement.error);
+ stackTrace = replacement.stackTrace;
+ }
+ _completeError(error, stackTrace);
+ }
+
+ void _completeError(Object error, StackTrace stackTrace);
+
+ // The future's _isComplete doesn't take into account pending completions.
+ // We therefore use _mayComplete.
+ bool get isCompleted => !future._mayComplete;
+}
+
+class _AsyncCompleter<T> extends _Completer<T> {
+ void complete([FutureOr<T> value]) {
+ if (!future._mayComplete) throw new StateError("Future already completed");
+ future._asyncComplete(value);
+ }
+
+ void _completeError(Object error, StackTrace stackTrace) {
+ future._asyncCompleteError(error, stackTrace);
+ }
+}
+
+class _SyncCompleter<T> extends _Completer<T> {
+ void complete([FutureOr<T> value]) {
+ if (!future._mayComplete) throw new StateError("Future already completed");
+ future._complete(value);
+ }
+
+ void _completeError(Object error, StackTrace stackTrace) {
+ future._completeError(error, stackTrace);
+ }
+}
+
+class _FutureListener<S, T> {
+ static const int maskValue = 1;
+ static const int maskError = 2;
+ static const int maskTestError = 4;
+ static const int maskWhencomplete = 8;
+ static const int stateChain = 0;
+ static const int stateThen = maskValue;
+ static const int stateThenOnerror = maskValue | maskError;
+ static const int stateCatcherror = maskError;
+ static const int stateCatcherrorTest = maskError | maskTestError;
+ static const int stateWhencomplete = maskWhencomplete;
+ static const int maskType =
+ maskValue | maskError | maskTestError | maskWhencomplete;
+ static const int stateIsAwait = 16;
+ // Listeners on the same future are linked through this link.
+ _FutureListener _nextListener;
+ // The future to complete when this listener is activated.
+ final _Future<T> result;
+ // Which fields means what.
+ final int state;
+ // Used for then/whenDone callback and error test
+ final Function callback;
+ // Used for error callbacks.
+ final Function errorCallback;
+
+ _FutureListener.then(
+ this.result, _FutureOnValue<S, T> onValue, Function errorCallback)
+ : callback = onValue,
+ errorCallback = errorCallback,
+ state = (errorCallback == null) ? stateThen : stateThenOnerror;
+
+ _FutureListener.thenAwait(
+ this.result, _FutureOnValue<S, T> onValue, Function errorCallback)
+ : callback = onValue,
+ errorCallback = errorCallback,
+ state = ((errorCallback == null) ? stateThen : stateThenOnerror)
+ | stateIsAwait ;
+
+ _FutureListener.catchError(this.result, this.errorCallback, this.callback)
+ : state = (callback == null) ? stateCatcherror : stateCatcherrorTest;
+
+ _FutureListener.whenComplete(this.result, this.callback)
+ : errorCallback = null,
+ state = stateWhencomplete;
+
+ Zone get _zone => result._zone;
+
+ bool get handlesValue => (state & maskValue != 0);
+ bool get handlesError => (state & maskError != 0);
+ bool get hasErrorTest => (state & maskType == stateCatcherrorTest);
+ bool get handlesComplete => (state & maskType == stateWhencomplete);
+ bool get isAwait => (state & stateIsAwait != 0);
+
+ _FutureOnValue<S, T> get _onValue {
+ assert(handlesValue);
+ return callback;
+ }
+
+ Function get _onError => errorCallback;
+ _FutureErrorTest get _errorTest {
+ assert(hasErrorTest);
+ return callback;
+ }
+
+ _FutureAction get _whenCompleteAction {
+ assert(handlesComplete);
+ return callback;
+ }
+
+ /// Whether this listener has an error callback.
+ ///
+ /// This function must only be called if the listener [handlesError].
+ bool get hasErrorCallback {
+ assert(handlesError);
+ return _onError != null;
+ }
+
+ FutureOr<T> handleValue(S sourceResult) {
+ return _zone.runUnary<FutureOr<T>, S>(_onValue, sourceResult);
+ }
+
+ bool matchesErrorTest(AsyncError asyncError) {
+ if (!hasErrorTest) return true;
+ return _zone.runUnary<bool, Object>(_errorTest, asyncError.error);
+ }
+
+ FutureOr<T> handleError(AsyncError asyncError) {
+ assert(handlesError && hasErrorCallback);
+ var errorCallback = this.errorCallback; // To enable promotion.
+ // If the errorCallback returns something which is not a FutureOr<T>,
+ // this return statement throws, and the caller handles the error.
+ if (errorCallback is dynamic Function(Object, StackTrace)) {
+ return _zone.runBinary<dynamic, Object, StackTrace>(
+ errorCallback, asyncError.error, asyncError.stackTrace);
+ } else {
+ assert(errorCallback is dynamic Function(Object));
+ return _zone.runUnary<dynamic, Object>(errorCallback, asyncError.error);
+ }
+ }
+
+ dynamic handleWhenComplete() {
+ assert(!handlesError);
+ return _zone.run(_whenCompleteAction);
+ }
+}
+
+class _Future<T> implements Future<T> {
+ /// Initial state, waiting for a result. In this state, the
+ /// [resultOrListeners] field holds a single-linked list of
+ /// [_FutureListener] listeners.
+ static const int _stateIncomplete = 0;
+
+ /// Pending completion. Set when completed using [_asyncComplete] or
+ /// [_asyncCompleteError]. It is an error to try to complete it again.
+ /// [resultOrListeners] holds listeners.
+ static const int _statePendingComplete = 1;
+
+ /// The future has been chained to another future. The result of that
+ /// other future becomes the result of this future as well.
+ /// [resultOrListeners] contains the source future.
+ static const int _stateChained = 2;
+
+ /// The future has been completed with a value result.
+ static const int _stateValue = 4;
+
+ /// The future has been completed with an error result.
+ static const int _stateError = 8;
+
+ /** Whether the future is complete, and as what. */
+ int _state = _stateIncomplete;
+
+ /**
+ * Zone that the future was completed from.
+ * This is the zone that an error result belongs to.
+ *
+ * Until the future is completed, the field may hold the zone that
+ * listener callbacks used to create this future should be run in.
+ */
+ final Zone _zone;
+
+ /**
+ * Either the result, a list of listeners or another future.
+ *
+ * The result of the future is either a value or an error.
+ * A result is only stored when the future has completed.
+ *
+ * The listeners is an internally linked list of [_FutureListener]s.
+ * Listeners are only remembered while the future is not yet complete,
+ * and it is not chained to another future.
+ *
+ * The future is another future that his future is chained to. This future
+ * is waiting for the other future to complete, and when it does, this future
+ * will complete with the same result.
+ * All listeners are forwarded to the other future.
+ */
+ var _resultOrListeners;
+
+ // This constructor is used by async/await.
+ _Future() : _zone = Zone.current;
+
+ _Future.immediate(FutureOr<T> result) : _zone = Zone.current {
+ _asyncComplete(result);
+ }
+
+ /** Creates a future with the value and the specified zone. */
+ _Future.zoneValue(T value, this._zone) {
+ _setValue(value);
+ }
+
+ _Future.immediateError(var error, [StackTrace stackTrace])
+ : _zone = Zone.current {
+ _asyncCompleteError(error, stackTrace);
+ }
+
+ /** Creates a future that is already completed with the value. */
+ _Future.value(T value) : this.zoneValue(value, Zone.current);
+
+ bool get _mayComplete => _state == _stateIncomplete;
+ bool get _isPendingComplete => _state == _statePendingComplete;
+ bool get _mayAddListener => _state <= _statePendingComplete;
+ bool get _isChained => _state == _stateChained;
+ bool get _isComplete => _state >= _stateValue;
+ bool get _hasError => _state == _stateError;
+
+ static List<Function> _continuationFunctions(_Future<Object> future) {
+ List<Function> result = null;
+ while (true) {
+ if (future._mayAddListener) return result;
+ assert(!future._isComplete);
+ assert(!future._isChained);
+ // So _resultOrListeners contains listeners.
+ _FutureListener<Object, Object> listener = future._resultOrListeners;
+ if (listener != null &&
+ listener._nextListener == null &&
+ listener.isAwait) {
+ (result ??= <Function>[]).add(listener.handleValue);
+ future = listener.result;
+ assert(!future._isComplete);
+ } else {
+ break;
+ }
+ }
+ return result;
+ }
+
+ void _setChained(_Future source) {
+ assert(_mayAddListener);
+ _state = _stateChained;
+ _resultOrListeners = source;
+ }
+
+ Future<R> then<R>(FutureOr<R> f(T value), {Function onError}) {
+ Zone currentZone = Zone.current;
+ if (!identical(currentZone, _rootZone)) {
+ f = currentZone.registerUnaryCallback<FutureOr<R>, T>(f);
+ if (onError != null) {
+ // In checked mode, this checks that onError is assignable to one of:
+ // dynamic Function(Object)
+ // dynamic Function(Object, StackTrace)
+ onError = _registerErrorHandler(onError, currentZone);
+ }
+ }
+ _Future<R> result = new _Future<R>();
+ _addListener(new _FutureListener<T, R>.then(result, f, onError));
+ return result;
+ }
+
+ /// Registers a system created result and error continuation.
+ ///
+ /// Used by the implementation of `await` to listen to a future.
+ /// The system created liseners are not registered in the zone,
+ /// and the listener is marked as being from an `await`.
+ /// This marker is used in [_continuationFunctions].
+ Future<E> _thenAwait<E>(
+ FutureOr<E> f(T value), Function onError) {
+ _Future<E> result = new _Future<E>();
+ _addListener(new _FutureListener<T, E>.thenAwait(result, f, onError));
+ return result;
+ }
+
+ Future<T> catchError(Function onError, {bool test(error)}) {
+ _Future<T> result = new _Future<T>();
+ if (!identical(result._zone, _rootZone)) {
+ onError = _registerErrorHandler(onError, result._zone);
+ if (test != null) test = result._zone.registerUnaryCallback(test);
+ }
+ _addListener(new _FutureListener<T, T>.catchError(result, onError, test));
+ return result;
+ }
+
+ Future<T> whenComplete(dynamic action()) {
+ _Future<T> result = new _Future<T>();
+ if (!identical(result._zone, _rootZone)) {
+ action = result._zone.registerCallback<dynamic>(action);
+ }
+ _addListener(new _FutureListener<T, T>.whenComplete(result, action));
+ return result;
+ }
+
+ Stream<T> asStream() => new Stream<T>.fromFuture(this);
+
+ void _setPendingComplete() {
+ assert(_mayComplete);
+ _state = _statePendingComplete;
+ }
+
+ void _clearPendingComplete() {
+ assert(_isPendingComplete);
+ _state = _stateIncomplete;
+ }
+
+ AsyncError get _error {
+ assert(_hasError);
+ return _resultOrListeners;
+ }
+
+ _Future get _chainSource {
+ assert(_isChained);
+ return _resultOrListeners;
+ }
+
+ // This method is used by async/await.
+ void _setValue(T value) {
+ assert(!_isComplete); // But may have a completion pending.
+ _state = _stateValue;
+ _resultOrListeners = value;
+ }
+
+ void _setErrorObject(AsyncError error) {
+ assert(!_isComplete); // But may have a completion pending.
+ _state = _stateError;
+ _resultOrListeners = error;
+ }
+
+ void _setError(Object error, StackTrace stackTrace) {
+ _setErrorObject(new AsyncError(error, stackTrace));
+ }
+
+ /// Copy the completion result of [source] into this future.
+ ///
+ /// Used when a chained future notices that its source is completed.
+ void _cloneResult(_Future source) {
+ assert(!_isComplete);
+ assert(source._isComplete);
+ _state = source._state;
+ _resultOrListeners = source._resultOrListeners;
+ }
+
+ void _addListener(_FutureListener listener) {
+ assert(listener._nextListener == null);
+ if (_mayAddListener) {
+ listener._nextListener = _resultOrListeners;
+ _resultOrListeners = listener;
+ } else {
+ if (_isChained) {
+ // Delegate listeners to chained source future.
+ // If the source is complete, instead copy its values and
+ // drop the chaining.
+ _Future source = _chainSource;
+ if (!source._isComplete) {
+ source._addListener(listener);
+ return;
+ }
+ _cloneResult(source);
+ }
+ assert(_isComplete);
+ // Handle late listeners asynchronously.
+ _zone.scheduleMicrotask(() {
+ _propagateToListeners(this, listener);
+ });
+ }
+ }
+
+ void _prependListeners(_FutureListener listeners) {
+ if (listeners == null) return;
+ if (_mayAddListener) {
+ _FutureListener existingListeners = _resultOrListeners;
+ _resultOrListeners = listeners;
+ if (existingListeners != null) {
+ _FutureListener cursor = listeners;
+ while (cursor._nextListener != null) {
+ cursor = cursor._nextListener;
+ }
+ cursor._nextListener = existingListeners;
+ }
+ } else {
+ if (_isChained) {
+ // Delegate listeners to chained source future.
+ // If the source is complete, instead copy its values and
+ // drop the chaining.
+ _Future source = _chainSource;
+ if (!source._isComplete) {
+ source._prependListeners(listeners);
+ return;
+ }
+ _cloneResult(source);
+ }
+ assert(_isComplete);
+ listeners = _reverseListeners(listeners);
+ _zone.scheduleMicrotask(() {
+ _propagateToListeners(this, listeners);
+ });
+ }
+ }
+
+ _FutureListener _removeListeners() {
+ // Reverse listeners before returning them, so the resulting list is in
+ // subscription order.
+ assert(!_isComplete);
+ _FutureListener current = _resultOrListeners;
+ _resultOrListeners = null;
+ return _reverseListeners(current);
+ }
+
+ _FutureListener _reverseListeners(_FutureListener listeners) {
+ _FutureListener prev;
+ _FutureListener current = listeners;
+ while (current != null) {
+ _FutureListener next = current._nextListener;
+ current._nextListener = prev;
+ prev = current;
+ current = next;
+ }
+ return prev;
+ }
+
+ // Take the value (when completed) of source and complete target with that
+ // value (or error). This function could chain all Futures, but is slower
+ // for _Future than _chainCoreFuture, so you must use _chainCoreFuture
+ // in that case.
+ static void _chainForeignFuture(Future source, _Future target) {
+ assert(!target._isComplete);
+ assert(source is! _Future);
+
+ // Mark the target as chained (and as such half-completed).
+ target._setPendingComplete();
+ try {
+ source.then((value) {
+ assert(target._isPendingComplete);
+ // The "value" may be another future if the foreign future
+ // implementation is mis-behaving,
+ // so use _complete instead of _completeWithValue.
+ target._clearPendingComplete(); // Clear this first, it's set again.
+ target._complete(value);
+ },
+ // TODO(floitsch): eventually we would like to make this non-optional
+ // and dependent on the listeners of the target future. If none of
+ // the target future's listeners want to have the stack trace we don't
+ // need a trace.
+ onError: (error, [StackTrace stackTrace]) {
+ assert(target._isPendingComplete);
+ target._completeError(error, stackTrace);
+ });
+ } catch (e, s) {
+ // This only happens if the `then` call threw synchronously when given
+ // valid arguments.
+ // That requires a non-conforming implementation of the Future interface,
+ // which should, hopefully, never happen.
+ scheduleMicrotask(() {
+ target._completeError(e, s);
+ });
+ }
+ }
+
+ // Take the value (when completed) of source and complete target with that
+ // value (or error). This function expects that source is a _Future.
+ static void _chainCoreFuture(_Future source, _Future target) {
+ assert(target._mayAddListener); // Not completed, not already chained.
+ while (source._isChained) {
+ source = source._chainSource;
+ }
+ if (source._isComplete) {
+ _FutureListener listeners = target._removeListeners();
+ target._cloneResult(source);
+ _propagateToListeners(target, listeners);
+ } else {
+ _FutureListener listeners = target._resultOrListeners;
+ target._setChained(source);
+ source._prependListeners(listeners);
+ }
+ }
+
+ void _complete(FutureOr<T> value) {
+ assert(!_isComplete);
+ if (value is Future<T>) {
+ if (value is _Future<T>) {
+ _chainCoreFuture(value, this);
+ } else {
+ _chainForeignFuture(value, this);
+ }
+ } else {
+ _FutureListener listeners = _removeListeners();
+ _setValue(value);
+ _propagateToListeners(this, listeners);
+ }
+ }
+
+ void _completeWithValue(T value) {
+ assert(!_isComplete);
+ assert(value is! Future<T>);
+
+ _FutureListener listeners = _removeListeners();
+ _setValue(value);
+ _propagateToListeners(this, listeners);
+ }
+
+ void _completeError(Object error, [StackTrace stackTrace]) {
+ assert(!_isComplete);
+
+ _FutureListener listeners = _removeListeners();
+ _setError(error, stackTrace);
+ _propagateToListeners(this, listeners);
+ }
+
+ void _asyncComplete(FutureOr<T> value) {
+ assert(!_isComplete);
+ // Two corner cases if the value is a future:
+ // 1. the future is already completed and an error.
+ // 2. the future is not yet completed but might become an error.
+ // The first case means that we must not immediately complete the Future,
+ // as our code would immediately start propagating the error without
+ // giving the time to install error-handlers.
+ // However the second case requires us to deal with the value immediately.
+ // Otherwise the value could complete with an error and report an
+ // unhandled error, even though we know we are already going to listen to
+ // it.
+
+ if (value is Future<T>) {
+ _chainFuture(value);
+ return;
+ }
+ _setPendingComplete();
+ _zone.scheduleMicrotask(() {
+ _completeWithValue(value);
+ });
+ }
+
+ void _chainFuture(Future<T> value) {
+ if (value is _Future<T>) {
+ if (value._hasError) {
+ // Delay completion to allow the user to register callbacks.
+ _setPendingComplete();
+ _zone.scheduleMicrotask(() {
+ _chainCoreFuture(value, this);
+ });
+ } else {
+ _chainCoreFuture(value, this);
+ }
+ return;
+ }
+ // Just listen on the foreign future. This guarantees an async delay.
+ _chainForeignFuture(value, this);
+ }
+
+ void _asyncCompleteError(error, StackTrace stackTrace) {
+ assert(!_isComplete);
+
+ _setPendingComplete();
+ _zone.scheduleMicrotask(() {
+ _completeError(error, stackTrace);
+ });
+ }
+
+ /**
+ * Propagates the value/error of [source] to its [listeners], executing the
+ * listeners' callbacks.
+ */
+ static void _propagateToListeners(_Future source, _FutureListener listeners) {
+ while (true) {
+ assert(source._isComplete);
+ bool hasError = source._hasError;
+ if (listeners == null) {
+ if (hasError) {
+ AsyncError asyncError = source._error;
+ source._zone
+ .handleUncaughtError(asyncError.error, asyncError.stackTrace);
+ }
+ return;
+ }
+ // Usually futures only have one listener. If they have several, we
+ // call handle them separately in recursive calls, continuing
+ // here only when there is only one listener left.
+ while (listeners._nextListener != null) {
+ _FutureListener listener = listeners;
+ listeners = listener._nextListener;
+ listener._nextListener = null;
+ _propagateToListeners(source, listener);
+ }
+ _FutureListener listener = listeners;
+ final sourceResult = source._resultOrListeners;
+ // Do the actual propagation.
+ // Set initial state of listenerHasError and listenerValueOrError. These
+ // variables are updated with the outcome of potential callbacks.
+ // Non-error results, including futures, are stored in
+ // listenerValueOrError and listenerHasError is set to false. Errors
+ // are stored in listenerValueOrError as an [AsyncError] and
+ // listenerHasError is set to true.
+ bool listenerHasError = hasError;
+ var listenerValueOrError = sourceResult;
+
+ // Only if we either have an error or callbacks, go into this, somewhat
+ // expensive, branch. Here we'll enter/leave the zone. Many futures
+ // don't have callbacks, so this is a significant optimization.
+ if (hasError || listener.handlesValue || listener.handlesComplete) {
+ Zone zone = listener._zone;
+ if (hasError && !source._zone.inSameErrorZone(zone)) {
+ // Don't cross zone boundaries with errors.
+ AsyncError asyncError = source._error;
+ source._zone
+ .handleUncaughtError(asyncError.error, asyncError.stackTrace);
+ return;
+ }
+
+ Zone oldZone;
+ if (!identical(Zone.current, zone)) {
+ // Change zone if it's not current.
+ oldZone = Zone._enter(zone);
+ }
+
+ // These callbacks are abstracted to isolate the try/catch blocks
+ // from the rest of the code to work around a V8 glass jaw.
+ void handleWhenCompleteCallback() {
+ // The whenComplete-handler is not combined with normal value/error
+ // handling. This means at most one handleX method is called per
+ // listener.
+ assert(!listener.handlesValue);
+ assert(!listener.handlesError);
+ var completeResult;
+ try {
+ completeResult = listener.handleWhenComplete();
+ } catch (e, s) {
+ if (hasError && identical(source._error.error, e)) {
+ listenerValueOrError = source._error;
+ } else {
+ listenerValueOrError = new AsyncError(e, s);
+ }
+ listenerHasError = true;
+ return;
+ }
+ if (completeResult is Future) {
+ if (completeResult is _Future && completeResult._isComplete) {
+ if (completeResult._hasError) {
+ listenerValueOrError = completeResult._error;
+ listenerHasError = true;
+ }
+ // Otherwise use the existing result of source.
+ return;
+ }
+ // We have to wait for the completeResult future to complete
+ // before knowing if it's an error or we should use the result
+ // of source.
+ var originalSource = source;
+ listenerValueOrError = completeResult.then((_) => originalSource);
+ listenerHasError = false;
+ }
+ }
+
+ void handleValueCallback() {
+ try {
+ listenerValueOrError = listener.handleValue(sourceResult);
+ } catch (e, s) {
+ listenerValueOrError = new AsyncError(e, s);
+ listenerHasError = true;
+ }
+ }
+
+ void handleError() {
+ try {
+ AsyncError asyncError = source._error;
+ if (listener.matchesErrorTest(asyncError) &&
+ listener.hasErrorCallback) {
+ listenerValueOrError = listener.handleError(asyncError);
+ listenerHasError = false;
+ }
+ } catch (e, s) {
+ if (identical(source._error.error, e)) {
+ listenerValueOrError = source._error;
+ } else {
+ listenerValueOrError = new AsyncError(e, s);
+ }
+ listenerHasError = true;
+ }
+ }
+
+ if (listener.handlesComplete) {
+ handleWhenCompleteCallback();
+ } else if (!hasError) {
+ if (listener.handlesValue) {
+ handleValueCallback();
+ }
+ } else {
+ if (listener.handlesError) {
+ handleError();
+ }
+ }
+
+ // If we changed zone, oldZone will not be null.
+ if (oldZone != null) Zone._leave(oldZone);
+
+ // If the listener's value is a future we need to chain it. Note that
+ // this can only happen if there is a callback.
+ if (listenerValueOrError is Future) {
+ Future chainSource = listenerValueOrError;
+ // Shortcut if the chain-source is already completed. Just continue
+ // the loop.
+ _Future result = listener.result;
+ if (chainSource is _Future) {
+ if (chainSource._isComplete) {
+ listeners = result._removeListeners();
+ result._cloneResult(chainSource);
+ source = chainSource;
+ continue;
+ } else {
+ _chainCoreFuture(chainSource, result);
+ }
+ } else {
+ _chainForeignFuture(chainSource, result);
+ }
+ return;
+ }
+ }
+ _Future result = listener.result;
+ listeners = result._removeListeners();
+ if (!listenerHasError) {
+ result._setValue(listenerValueOrError);
+ } else {
+ AsyncError asyncError = listenerValueOrError;
+ result._setErrorObject(asyncError);
+ }
+ // Prepare for next round.
+ source = result;
+ }
+ }
+
+ Future<T> timeout(Duration timeLimit, {FutureOr<T> onTimeout()}) {
+ if (_isComplete) return new _Future.immediate(this);
+ _Future<T> result = new _Future<T>();
+ Timer timer;
+ if (onTimeout == null) {
+ timer = new Timer(timeLimit, () {
+ result._completeError(
+ new TimeoutException("Future not completed", timeLimit));
+ });
+ } else {
+ Zone zone = Zone.current;
+ onTimeout = zone.registerCallback(onTimeout);
+ timer = new Timer(timeLimit, () {
+ try {
+ result._complete(zone.run(onTimeout));
+ } catch (e, s) {
+ result._completeError(e, s);
+ }
+ });
+ }
+ this.then((T v) {
+ if (timer.isActive) {
+ timer.cancel();
+ result._completeWithValue(v);
+ }
+ }, onError: (e, StackTrace s) {
+ if (timer.isActive) {
+ timer.cancel();
+ result._completeError(e, s);
+ }
+ });
+ return result;
+ }
+}
+
+/// Registers errorHandler in zone if it has the correct type.
+///
+/// Checks that the function accepts either an [Object] and a [StackTrace]
+/// or just one [Object]. Does not check the return type.
+/// The actually returned value must be `FutureOr<R>` where `R` is the
+/// value type of the future that the call will complete (either returned
+/// by [Future.then] or [Future.catchError]). We check the returned value
+/// dynamically because the functions are passed as arguments in positions
+/// without inference, so a function expression won't infer the return type.
+///
+/// Throws if the type is not valid.
+Function _registerErrorHandler(Function errorHandler, Zone zone) {
+ if (errorHandler is dynamic Function(Object, StackTrace)) {
+ return zone
+ .registerBinaryCallback<dynamic, Object, StackTrace>(errorHandler);
+ }
+ if (errorHandler is dynamic Function(Object)) {
+ return zone.registerUnaryCallback<dynamic, Object>(errorHandler);
+ }
+ throw new ArgumentError.value(
+ errorHandler,
+ "onError",
+ "Error handler must accept one Object or one Object and a StackTrace"
+ " as arguments, and return a a valid result");
+}
diff --git a/sdk_nnbd/lib/async/schedule_microtask.dart b/sdk_nnbd/lib/async/schedule_microtask.dart
new file mode 100644
index 0000000..801490a
--- /dev/null
+++ b/sdk_nnbd/lib/async/schedule_microtask.dart
@@ -0,0 +1,153 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+typedef void _AsyncCallback();
+
+class _AsyncCallbackEntry {
+ final _AsyncCallback callback;
+ _AsyncCallbackEntry next;
+ _AsyncCallbackEntry(this.callback);
+}
+
+/** Head of single linked list of pending callbacks. */
+_AsyncCallbackEntry _nextCallback;
+/** Tail of single linked list of pending callbacks. */
+_AsyncCallbackEntry _lastCallback;
+/**
+ * Tail of priority callbacks added by the currently executing callback.
+ *
+ * Priority callbacks are put at the beginning of the
+ * callback queue, so that if one callback schedules more than one
+ * priority callback, they are still enqueued in scheduling order.
+ */
+_AsyncCallbackEntry _lastPriorityCallback;
+/**
+ * Whether we are currently inside the callback loop.
+ *
+ * If we are inside the loop, we never need to schedule the loop,
+ * even if adding a first element.
+ */
+bool _isInCallbackLoop = false;
+
+void _microtaskLoop() {
+ while (_nextCallback != null) {
+ _lastPriorityCallback = null;
+ _AsyncCallbackEntry entry = _nextCallback;
+ _nextCallback = entry.next;
+ if (_nextCallback == null) _lastCallback = null;
+ (entry.callback)();
+ }
+}
+
+void _startMicrotaskLoop() {
+ _isInCallbackLoop = true;
+ try {
+ // Moved to separate function because try-finally prevents
+ // good optimization.
+ _microtaskLoop();
+ } finally {
+ _lastPriorityCallback = null;
+ _isInCallbackLoop = false;
+ if (_nextCallback != null) {
+ _AsyncRun._scheduleImmediate(_startMicrotaskLoop);
+ }
+ }
+}
+
+/**
+ * Schedules a callback to be called as a microtask.
+ *
+ * The microtask is called after all other currently scheduled
+ * microtasks, but as part of the current system event.
+ */
+void _scheduleAsyncCallback(_AsyncCallback callback) {
+ _AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback);
+ if (_nextCallback == null) {
+ _nextCallback = _lastCallback = newEntry;
+ if (!_isInCallbackLoop) {
+ _AsyncRun._scheduleImmediate(_startMicrotaskLoop);
+ }
+ } else {
+ _lastCallback.next = newEntry;
+ _lastCallback = newEntry;
+ }
+}
+
+/**
+ * Schedules a callback to be called before all other currently scheduled ones.
+ *
+ * This callback takes priority over existing scheduled callbacks.
+ * It is only used internally to give higher priority to error reporting.
+ *
+ * Is always run in the root zone.
+ */
+void _schedulePriorityAsyncCallback(_AsyncCallback callback) {
+ if (_nextCallback == null) {
+ _scheduleAsyncCallback(callback);
+ _lastPriorityCallback = _lastCallback;
+ return;
+ }
+ _AsyncCallbackEntry entry = new _AsyncCallbackEntry(callback);
+ if (_lastPriorityCallback == null) {
+ entry.next = _nextCallback;
+ _nextCallback = _lastPriorityCallback = entry;
+ } else {
+ entry.next = _lastPriorityCallback.next;
+ _lastPriorityCallback.next = entry;
+ _lastPriorityCallback = entry;
+ if (entry.next == null) {
+ _lastCallback = entry;
+ }
+ }
+}
+
+/**
+ * Runs a function asynchronously.
+ *
+ * Callbacks registered through this function are always executed in order and
+ * are guaranteed to run before other asynchronous events (like [Timer] events,
+ * or DOM events).
+ *
+ * **Warning:** it is possible to starve the DOM by registering asynchronous
+ * callbacks through this method. For example the following program runs
+ * the callbacks without ever giving the Timer callback a chance to execute:
+ *
+ * main() {
+ * Timer.run(() { print("executed"); }); // Will never be executed.
+ * foo() {
+ * scheduleMicrotask(foo); // Schedules [foo] in front of other events.
+ * }
+ * foo();
+ * }
+ *
+ * ## Other resources
+ *
+ * * [The Event Loop and Dart](https://www.dartlang.org/articles/event-loop/):
+ * Learn how Dart handles the event queue and microtask queue, so you can write
+ * better asynchronous code with fewer surprises.
+ */
+void scheduleMicrotask(void callback()) {
+ _Zone currentZone = Zone.current;
+ if (identical(_rootZone, currentZone)) {
+ // No need to bind the callback. We know that the root's scheduleMicrotask
+ // will be invoked in the root zone.
+ _rootScheduleMicrotask(null, null, _rootZone, callback);
+ return;
+ }
+ _ZoneFunction implementation = currentZone._scheduleMicrotask;
+ if (identical(_rootZone, implementation.zone) &&
+ _rootZone.inSameErrorZone(currentZone)) {
+ _rootScheduleMicrotask(
+ null, null, currentZone, currentZone.registerCallback(callback));
+ return;
+ }
+ Zone.current.scheduleMicrotask(Zone.current.bindCallbackGuarded(callback));
+}
+
+class _AsyncRun {
+ /** Schedule the given callback before any other event in the event-loop. */
+ external static void _scheduleImmediate(void callback());
+}
diff --git a/sdk_nnbd/lib/async/stream.dart b/sdk_nnbd/lib/async/stream.dart
new file mode 100644
index 0000000..95a8b97
--- /dev/null
+++ b/sdk_nnbd/lib/async/stream.dart
@@ -0,0 +1,2267 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+// -------------------------------------------------------------------
+// Core Stream types
+// -------------------------------------------------------------------
+
+typedef void _TimerCallback();
+
+/**
+ * A source of asynchronous data events.
+ *
+ * A Stream provides a way to receive a sequence of events.
+ * Each event is either a data event, also called an *element* of the stream,
+ * or an error event, which is a notification that something has failed.
+ * When a stream has emitted all its event,
+ * a single "done" event will notify the listener that the end has been reached.
+ *
+ * You [listen] on a stream to make it start generating events,
+ * and to set up listeners that receive the events.
+ * When you listen, you receive a [StreamSubscription] object
+ * which is the active object providing the events,
+ * and which can be used to stop listening again,
+ * or to temporarily pause events from the subscription.
+ *
+ * There are two kinds of streams: "Single-subscription" streams and
+ * "broadcast" streams.
+ *
+ * *A single-subscription stream* allows only a single listener during the whole
+ * lifetime of the stream.
+ * It doesn't start generating events until it has a listener,
+ * and it stops sending events when the listener is unsubscribed,
+ * even if the source of events could still provide more.
+ *
+ * Listening twice on a single-subscription stream is not allowed, even after
+ * the first subscription has been canceled.
+ *
+ * Single-subscription streams are generally used for streaming chunks of
+ * larger contiguous data like file I/O.
+ *
+ * *A broadcast stream* allows any number of listeners, and it fires
+ * its events when they are ready, whether there are listeners or not.
+ *
+ * Broadcast streams are used for independent events/observers.
+ *
+ * If several listeners want to listen to a single subscription stream,
+ * use [asBroadcastStream] to create a broadcast stream on top of the
+ * non-broadcast stream.
+ *
+ * On either kind of stream, stream transformations, such as [where] and
+ * [skip], return the same type of stream as the one the method was called on,
+ * unless otherwise noted.
+ *
+ * When an event is fired, the listener(s) at that time will receive the event.
+ * If a listener is added to a broadcast stream while an event is being fired,
+ * that listener will not receive the event currently being fired.
+ * If a listener is canceled, it immediately stops receiving events.
+ * Listening on a broadcast stream can be treated as listening on a new stream
+ * containing only the events that have not yet been emitted when the [listen]
+ * call occurs.
+ * For example, the [first] getter listens to the stream, then returns the first
+ * event that listener receives.
+ * This is not necessarily the first even emitted by the stream, but the first
+ * of the *remaining* events of the broadcast stream.
+ *
+ * When the "done" event is fired, subscribers are unsubscribed before
+ * receiving the event. After the event has been sent, the stream has no
+ * subscribers. Adding new subscribers to a broadcast stream after this point
+ * is allowed, but they will just receive a new "done" event as soon
+ * as possible.
+ *
+ * Stream subscriptions always respect "pause" requests. If necessary they need
+ * to buffer their input, but often, and preferably, they can simply request
+ * their input to pause too.
+ *
+ * The default implementation of [isBroadcast] returns false.
+ * A broadcast stream inheriting from [Stream] must override [isBroadcast]
+ * to return `true`.
+ */
+abstract class Stream<T> {
+ Stream();
+
+ /**
+ * Internal use only. We do not want to promise that Stream stays const.
+ *
+ * If mixins become compatible with const constructors, we may use a
+ * stream mixin instead of extending Stream from a const class.
+ */
+ const Stream._internal();
+
+ /**
+ * Creates an empty broadcast stream.
+ *
+ * This is a stream which does nothing except sending a done event
+ * when it's listened to.
+ */
+ const factory Stream.empty() = _EmptyStream<T>;
+
+ /**
+ * Creates a stream which emits a single data event before completing.
+ *
+ * This stream emits a single data event of [value]
+ * and then completes with a done event.
+ *
+ * Example:
+ * ```dart
+ * Future<void> printThings(Stream<String> data) async {
+ * await for (var x in data) {
+ * print(x);
+ * }
+ * }
+ * printThings(Stream<String>.value("ok")); // prints "ok".
+ * ```
+ *
+ * The returned stream is effectively equivalent to one created by
+ * `(() async* { yield value; } ())` or `Future<T>.value(value).asStream()`.
+ */
+ @Since("2.5")
+ factory Stream.value(T value) =>
+ (_AsyncStreamController<T>(null, null, null, null)
+ .._add(value)
+ .._closeUnchecked())
+ .stream;
+
+ /**
+ * Creates a stream which emits a single error event before completing.
+ *
+ * This stream emits a single error event of [error] and [stackTrace]
+ * and then completes with a done event.
+ *
+ * Example:
+ * ```dart
+ * Future<void> tryThings(Stream<int> data) async {
+ * try {
+ * await for (var x in data) {
+ * print("Data: $x");
+ * }
+ * } catch (e) {
+ * print(e);
+ * }
+ * }
+ * tryThings(Stream<int>.error("Error")); // prints "Error".
+ * ```
+ * The returned stream is effectively equivalent to one created by
+ * `Future<T>.error(error, stackTrace).asStream()`, by or
+ * `(() async* { throw error; } ())`, except that you can control the
+ * stack trace as well.
+ */
+ @Since("2.5")
+ factory Stream.error(Object error, [StackTrace stackTrace]) =>
+ (_AsyncStreamController<T>(null, null, null, null)
+ .._addError(error, stackTrace)
+ .._closeUnchecked())
+ .stream;
+
+ /**
+ * Creates a new single-subscription stream from the future.
+ *
+ * When the future completes, the stream will fire one event, either
+ * data or error, and then close with a done-event.
+ */
+ factory Stream.fromFuture(Future<T> future) {
+ // Use the controller's buffering to fill in the value even before
+ // the stream has a listener. For a single value, it's not worth it
+ // to wait for a listener before doing the `then` on the future.
+ _StreamController<T> controller =
+ new _SyncStreamController<T>(null, null, null, null);
+ future.then((value) {
+ controller._add(value);
+ controller._closeUnchecked();
+ }, onError: (error, stackTrace) {
+ controller._addError(error, stackTrace);
+ controller._closeUnchecked();
+ });
+ return controller.stream;
+ }
+
+ /**
+ * Create a stream from a group of futures.
+ *
+ * The stream reports the results of the futures on the stream in the order
+ * in which the futures complete.
+ * Each future provides either a data event or an error event,
+ * depending on how the future completes.
+ *
+ * If some futures have already completed when `Stream.fromFutures` is called,
+ * their results will be emitted in some unspecified order.
+ *
+ * When all futures have completed, the stream is closed.
+ *
+ * If [futures] is empty, the stream closes as soon as possible.
+ */
+ factory Stream.fromFutures(Iterable<Future<T>> futures) {
+ _StreamController<T> controller =
+ new _SyncStreamController<T>(null, null, null, null);
+ int count = 0;
+ // Declare these as variables holding closures instead of as
+ // function declarations.
+ // This avoids creating a new closure from the functions for each future.
+ var onValue = (T value) {
+ if (!controller.isClosed) {
+ controller._add(value);
+ if (--count == 0) controller._closeUnchecked();
+ }
+ };
+ var onError = (error, StackTrace stack) {
+ if (!controller.isClosed) {
+ controller._addError(error, stack);
+ if (--count == 0) controller._closeUnchecked();
+ }
+ };
+ // The futures are already running, so start listening to them immediately
+ // (instead of waiting for the stream to be listened on).
+ // If we wait, we might not catch errors in the futures in time.
+ for (var future in futures) {
+ count++;
+ future.then(onValue, onError: onError);
+ }
+ // Use schedule microtask since controller is sync.
+ if (count == 0) scheduleMicrotask(controller.close);
+ return controller.stream;
+ }
+
+ /**
+ * Creates a single-subscription stream that gets its data from [elements].
+ *
+ * The iterable is iterated when the stream receives a listener, and stops
+ * iterating if the listener cancels the subscription, or if the
+ * [Iterator.moveNext] method returns `false` or throws.
+ * Iteration is suspended while the stream subscription is paused.
+ *
+ * If calling [Iterator.moveNext] on `elements.iterator` throws,
+ * the stream emits that error and then it closes.
+ * If reading [Iterator.current] on `elements.iterator` throws,
+ * the stream emits that error, but keeps iterating.
+ */
+ factory Stream.fromIterable(Iterable<T> elements) {
+ return new _GeneratedStreamImpl<T>(
+ () => new _IterablePendingEvents<T>(elements));
+ }
+
+ /**
+ * Creates a stream that repeatedly emits events at [period] intervals.
+ *
+ * The event values are computed by invoking [computation]. The argument to
+ * this callback is an integer that starts with 0 and is incremented for
+ * every event.
+ *
+ * If [computation] is omitted the event values will all be `null`.
+ */
+ factory Stream.periodic(Duration period,
+ [T computation(int computationCount)]) {
+ Timer timer;
+ int computationCount = 0;
+ StreamController<T> controller;
+ // Counts the time that the Stream was running (and not paused).
+ Stopwatch watch = new Stopwatch();
+
+ void sendEvent() {
+ watch.reset();
+ T data;
+ if (computation != null) {
+ try {
+ data = computation(computationCount++);
+ } catch (e, s) {
+ controller.addError(e, s);
+ return;
+ }
+ }
+ controller.add(data);
+ }
+
+ void startPeriodicTimer() {
+ assert(timer == null);
+ timer = new Timer.periodic(period, (Timer timer) {
+ sendEvent();
+ });
+ }
+
+ controller = new StreamController<T>(
+ sync: true,
+ onListen: () {
+ watch.start();
+ startPeriodicTimer();
+ },
+ onPause: () {
+ timer.cancel();
+ timer = null;
+ watch.stop();
+ },
+ onResume: () {
+ assert(timer == null);
+ Duration elapsed = watch.elapsed;
+ watch.start();
+ timer = new Timer(period - elapsed, () {
+ timer = null;
+ startPeriodicTimer();
+ sendEvent();
+ });
+ },
+ onCancel: () {
+ if (timer != null) timer.cancel();
+ timer = null;
+ return Future._nullFuture;
+ });
+ return controller.stream;
+ }
+
+ /**
+ * Creates a stream where all events of an existing stream are piped through
+ * a sink-transformation.
+ *
+ * The given [mapSink] closure is invoked when the returned stream is
+ * listened to. All events from the [source] are added into the event sink
+ * that is returned from the invocation. The transformation puts all
+ * transformed events into the sink the [mapSink] closure received during
+ * its invocation. Conceptually the [mapSink] creates a transformation pipe
+ * with the input sink being the returned [EventSink] and the output sink
+ * being the sink it received.
+ *
+ * This constructor is frequently used to build transformers.
+ *
+ * Example use for a duplicating transformer:
+ *
+ * class DuplicationSink implements EventSink<String> {
+ * final EventSink<String> _outputSink;
+ * DuplicationSink(this._outputSink);
+ *
+ * void add(String data) {
+ * _outputSink.add(data);
+ * _outputSink.add(data);
+ * }
+ *
+ * void addError(e, [st]) { _outputSink.addError(e, st); }
+ * void close() { _outputSink.close(); }
+ * }
+ *
+ * class DuplicationTransformer extends StreamTransformerBase<String, String> {
+ * // Some generic types omitted for brevity.
+ * Stream bind(Stream stream) => new Stream<String>.eventTransformed(
+ * stream,
+ * (EventSink sink) => new DuplicationSink(sink));
+ * }
+ *
+ * stringStream.transform(new DuplicationTransformer());
+ *
+ * The resulting stream is a broadcast stream if [source] is.
+ */
+ factory Stream.eventTransformed(
+ Stream source, EventSink mapSink(EventSink<T> sink)) {
+ return new _BoundSinkStream(source, mapSink);
+ }
+
+ /**
+ * Adapts [source] to be a `Stream<T>`.
+ *
+ * This allows [source] to be used at the new type, but at run-time it
+ * must satisfy the requirements of both the new type and its original type.
+ *
+ * Data events created by the source stream must also be instances of [T].
+ */
+ static Stream<T> castFrom<S, T>(Stream<S> source) =>
+ new CastStream<S, T>(source);
+
+ /**
+ * Whether this stream is a broadcast stream.
+ */
+ bool get isBroadcast => false;
+
+ /**
+ * Returns a multi-subscription stream that produces the same events as this.
+ *
+ * The returned stream will subscribe to this stream when its first
+ * subscriber is added, and will stay subscribed until this stream ends,
+ * or a callback cancels the subscription.
+ *
+ * If [onListen] is provided, it is called with a subscription-like object
+ * that represents the underlying subscription to this stream. It is
+ * possible to pause, resume or cancel the subscription during the call
+ * to [onListen]. It is not possible to change the event handlers, including
+ * using [StreamSubscription.asFuture].
+ *
+ * If [onCancel] is provided, it is called in a similar way to [onListen]
+ * when the returned stream stops having listener. If it later gets
+ * a new listener, the [onListen] function is called again.
+ *
+ * Use the callbacks, for example, for pausing the underlying subscription
+ * while having no subscribers to prevent losing events, or canceling the
+ * subscription when there are no listeners.
+ */
+ Stream<T> asBroadcastStream(
+ {void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)}) {
+ return new _AsBroadcastStream<T>(this, onListen, onCancel);
+ }
+
+ /**
+ * Adds a subscription to this stream.
+ *
+ * Returns a [StreamSubscription] which handles events from this stream using
+ * the provided [onData], [onError] and [onDone] handlers.
+ * The handlers can be changed on the subscription, but they start out
+ * as the provided functions.
+ *
+ * On each data event from this stream, the subscriber's [onData] handler
+ * is called. If [onData] is `null`, nothing happens.
+ *
+ * On errors from this stream, the [onError] handler is called with the
+ * error object and possibly a stack trace.
+ *
+ * The [onError] callback must be of type `void onError(error)` or
+ * `void onError(error, StackTrace stackTrace)`. If [onError] accepts
+ * two arguments it is called with the error object and the stack trace
+ * (which could be `null` if this stream itself received an error without
+ * stack trace).
+ * Otherwise it is called with just the error object.
+ * If [onError] is omitted, any errors on this stream are considered unhandled,
+ * and will be passed to the current [Zone]'s error handler.
+ * By default unhandled async errors are treated
+ * as if they were uncaught top-level errors.
+ *
+ * If this stream closes and sends a done event, the [onDone] handler is
+ * called. If [onDone] is `null`, nothing happens.
+ *
+ * If [cancelOnError] is true, the subscription is automatically canceled
+ * when the first error event is delivered. The default is `false`.
+ *
+ * While a subscription is paused, or when it has been canceled,
+ * the subscription doesn't receive events and none of the
+ * event handler functions are called.
+ */
+ StreamSubscription<T> listen(void onData(T event),
+ {Function onError, void onDone(), bool cancelOnError});
+
+ /**
+ * Creates a new stream from this stream that discards some elements.
+ *
+ * The new stream sends the same error and done events as this stream,
+ * but it only sends the data events that satisfy the [test].
+ *
+ * If the [test] function throws, the data event is dropped and the
+ * error is emitted on the returned stream instead.
+ *
+ * The returned stream is a broadcast stream if this stream is.
+ * If a broadcast stream is listened to more than once, each subscription
+ * will individually perform the `test`.
+ */
+ Stream<T> where(bool test(T event)) {
+ return new _WhereStream<T>(this, test);
+ }
+
+ /**
+ * Transforms each element of this stream into a new stream event.
+ *
+ * Creates a new stream that converts each element of this stream
+ * to a new value using the [convert] function, and emits the result.
+ *
+ * For each data event, `o`, in this stream, the returned stream
+ * provides a data event with the value `convert(o)`.
+ * If [convert] throws, the returned stream reports it as an error
+ * event instead.
+ *
+ * Error and done events are passed through unchanged to the returned stream.
+ *
+ * The returned stream is a broadcast stream if this stream is.
+ * The [convert] function is called once per data event per listener.
+ * If a broadcast stream is listened to more than once, each subscription
+ * will individually call [convert] on each data event.
+ *
+ * Unlike [transform], this method does not treat the stream as
+ * chunks of a single value. Instead each event is converted independently
+ * of the previous and following events, which may not always be correct.
+ * For example, UTF-8 encoding, or decoding, will give wrong results
+ * if a surrogate pair, or a multibyte UTF-8 encoding, is split into
+ * separate events, and those events are attempted encoded or decoded
+ * independently.
+ */
+ Stream<S> map<S>(S convert(T event)) {
+ return new _MapStream<T, S>(this, convert);
+ }
+
+ /**
+ * Creates a new stream with each data event of this stream asynchronously
+ * mapped to a new event.
+ *
+ * This acts like [map], except that [convert] may return a [Future],
+ * and in that case, this stream waits for that future to complete before
+ * continuing with its result.
+ *
+ * The returned stream is a broadcast stream if this stream is.
+ */
+ Stream<E> asyncMap<E>(FutureOr<E> convert(T event)) {
+ _StreamControllerBase<E> controller;
+ StreamSubscription<T> subscription;
+
+ void onListen() {
+ final add = controller.add;
+ assert(controller is _StreamController<E> ||
+ controller is _BroadcastStreamController);
+ final addError = controller._addError;
+ subscription = this.listen((T event) {
+ FutureOr<E> newValue;
+ try {
+ newValue = convert(event);
+ } catch (e, s) {
+ controller.addError(e, s);
+ return;
+ }
+ if (newValue is Future<E>) {
+ subscription.pause();
+ newValue
+ .then(add, onError: addError)
+ .whenComplete(subscription.resume);
+ } else {
+ controller.add(newValue);
+ }
+ }, onError: addError, onDone: controller.close);
+ }
+
+ if (this.isBroadcast) {
+ controller = new StreamController<E>.broadcast(
+ onListen: onListen,
+ onCancel: () {
+ subscription.cancel();
+ },
+ sync: true);
+ } else {
+ controller = new StreamController<E>(
+ onListen: onListen,
+ onPause: () {
+ subscription.pause();
+ },
+ onResume: () {
+ subscription.resume();
+ },
+ onCancel: () => subscription.cancel(),
+ sync: true);
+ }
+ return controller.stream;
+ }
+
+ /**
+ * Transforms each element into a sequence of asynchronous events.
+ *
+ * Returns a new stream and for each event of this stream, do the following:
+ *
+ * * If the event is an error event or a done event, it is emitted directly
+ * by the returned stream.
+ * * Otherwise it is an element. Then the [convert] function is called
+ * with the element as argument to produce a convert-stream for the element.
+ * * If that call throws, the error is emitted on the returned stream.
+ * * If the call returns `null`, no further action is taken for the elements.
+ * * Otherwise, this stream is paused and convert-stream is listened to.
+ * Every data and error event of the convert-stream is emitted on the returned
+ * stream in the order it is produced.
+ * When the convert-stream ends, this stream is resumed.
+ *
+ * The returned stream is a broadcast stream if this stream is.
+ */
+ Stream<E> asyncExpand<E>(Stream<E> convert(T event)) {
+ _StreamControllerBase<E> controller;
+ StreamSubscription<T> subscription;
+ void onListen() {
+ assert(controller is _StreamController ||
+ controller is _BroadcastStreamController);
+ subscription = this.listen((T event) {
+ Stream<E> newStream;
+ try {
+ newStream = convert(event);
+ } catch (e, s) {
+ controller.addError(e, s);
+ return;
+ }
+ if (newStream != null) {
+ subscription.pause();
+ controller.addStream(newStream).whenComplete(subscription.resume);
+ }
+ },
+ onError: controller._addError, // Avoid Zone error replacement.
+ onDone: controller.close);
+ }
+
+ if (this.isBroadcast) {
+ controller = new StreamController<E>.broadcast(
+ onListen: onListen,
+ onCancel: () {
+ subscription.cancel();
+ },
+ sync: true);
+ } else {
+ controller = new StreamController<E>(
+ onListen: onListen,
+ onPause: () {
+ subscription.pause();
+ },
+ onResume: () {
+ subscription.resume();
+ },
+ onCancel: () => subscription.cancel(),
+ sync: true);
+ }
+ return controller.stream;
+ }
+
+ /**
+ * Creates a wrapper Stream that intercepts some errors from this stream.
+ *
+ * If this stream sends an error that matches [test], then it is intercepted
+ * by the [onError] function.
+ *
+ * The [onError] callback must be of type `void onError(error)` or
+ * `void onError(error, StackTrace stackTrace)`.
+ * The function type determines whether [onError] is invoked with a stack
+ * trace argument.
+ * The stack trace argument may be `null` if this stream received an error
+ * without a stack trace.
+ *
+ * An asynchronous error `error` is matched by a test function if
+ *`test(error)` returns true. If [test] is omitted, every error is considered
+ * matching.
+ *
+ * If the error is intercepted, the [onError] function can decide what to do
+ * with it. It can throw if it wants to raise a new (or the same) error,
+ * or simply return to make this stream forget the error.
+ * If the received `error` value is thrown again by the [onError] function,
+ * it acts like a `rethrow` and it is emitted along with its original
+ * stack trace, not the stack trace of the `throw` inside [onError].
+ *
+ * If you need to transform an error into a data event, use the more generic
+ * [Stream.transform] to handle the event by writing a data event to
+ * the output sink.
+ *
+ * The returned stream is a broadcast stream if this stream is.
+ * If a broadcast stream is listened to more than once, each subscription
+ * will individually perform the `test` and handle the error.
+ */
+ Stream<T> handleError(Function onError, {bool test(error)}) {
+ return new _HandleErrorStream<T>(this, onError, test);
+ }
+
+ /**
+ * Transforms each element of this stream into a sequence of elements.
+ *
+ * Returns a new stream where each element of this stream is replaced
+ * by zero or more data events.
+ * The event values are provided as an [Iterable] by a call to [convert]
+ * with the element as argument, and the elements of that iterable is
+ * emitted in iteration order.
+ * If calling [convert] throws, or if the iteration of the returned values
+ * throws, the error is emitted on the returned stream and iteration ends
+ * for that element of this stream.
+ *
+ * Error events and the done event of this stream are forwarded directly
+ * to the returned stream.
+ *
+ * The returned stream is a broadcast stream if this stream is.
+ * If a broadcast stream is listened to more than once, each subscription
+ * will individually call `convert` and expand the events.
+ */
+ Stream<S> expand<S>(Iterable<S> convert(T element)) {
+ return new _ExpandStream<T, S>(this, convert);
+ }
+
+ /**
+ * Pipes the events of this stream into [streamConsumer].
+ *
+ * All events of this stream are added to `streamConsumer` using
+ * [StreamConsumer.addStream].
+ * The `streamConsumer` is closed when this stream has been successfully added
+ * to it - when the future returned by `addStream` completes without an error.
+ *
+ * Returns a future which completes when this stream has been consumed
+ * and the consumer has been closed.
+ *
+ * The returned future completes with the same result as the future returned
+ * by [StreamConsumer.close].
+ * If the call to [StreamConsumer.addStream] fails in some way, this
+ * method fails in the same way.
+ */
+ Future pipe(StreamConsumer<T> streamConsumer) {
+ return streamConsumer.addStream(this).then((_) => streamConsumer.close());
+ }
+
+ /**
+ * Applies [streamTransformer] to this stream.
+ *
+ * Returns the transformed stream,
+ * that is, the result of `streamTransformer.bind(this)`.
+ * This method simply allows writing the call to `streamTransformer.bind`
+ * in a chained fashion, like
+ * ```
+ * stream.map(mapping).transform(transformation).toList()
+ * ```
+ * which can be more convenient than calling `bind` directly.
+ *
+ * The [streamTransformer] can return any stream.
+ * Whether the returned stream is a broadcast stream or not,
+ * and which elements it will contain,
+ * is entirely up to the transformation.
+ *
+ * This method should always be used for transformations which treat
+ * the entire stream as representing a single value
+ * which has perhaps been split into several parts for transport,
+ * like a file being read from disk or being fetched over a network.
+ * The transformation will then produce a new stream which
+ * transforms the stream's value incrementally (perhaps using
+ * [Converter.startChunkedConversion]). The resulting stream
+ * may again be chunks of the result, but does not have to
+ * correspond to specific events from the source string.
+ */
+ Stream<S> transform<S>(StreamTransformer<T, S> streamTransformer) {
+ return streamTransformer.bind(this);
+ }
+
+ /**
+ * Combines a sequence of values by repeatedly applying [combine].
+ *
+ * Similar to [Iterable.reduce], this function maintains a value,
+ * starting with the first element of this stream
+ * and updated for each further element of this stream.
+ * For each element after the first,
+ * the value is updated to the result of calling [combine]
+ * with the previous value and the element.
+ *
+ * When this stream is done, the returned future is completed with
+ * the value at that time.
+ *
+ * If this stream is empty, the returned future is completed with
+ * an error.
+ * If this stream emits an error, or the call to [combine] throws,
+ * the returned future is completed with that error,
+ * and processing is stopped.
+ */
+ Future<T> reduce(T combine(T previous, T element)) {
+ _Future<T> result = new _Future<T>();
+ bool seenFirst = false;
+ T value;
+ StreamSubscription subscription;
+ subscription = this.listen(
+ (T element) {
+ if (seenFirst) {
+ _runUserCode(() => combine(value, element), (T newValue) {
+ value = newValue;
+ }, _cancelAndErrorClosure(subscription, result));
+ } else {
+ value = element;
+ seenFirst = true;
+ }
+ },
+ onError: result._completeError,
+ onDone: () {
+ if (!seenFirst) {
+ try {
+ // Throw and recatch, instead of just doing
+ // _completeWithErrorCallback, e, theError, StackTrace.current),
+ // to ensure that the stackTrace is set on the error.
+ throw IterableElementError.noElement();
+ } catch (e, s) {
+ _completeWithErrorCallback(result, e, s);
+ }
+ } else {
+ result._complete(value);
+ }
+ },
+ cancelOnError: true);
+ return result;
+ }
+
+ /**
+ * Combines a sequence of values by repeatedly applying [combine].
+ *
+ * Similar to [Iterable.fold], this function maintains a value,
+ * starting with [initialValue] and updated for each element of
+ * this stream.
+ * For each element, the value is updated to the result of calling
+ * [combine] with the previous value and the element.
+ *
+ * When this stream is done, the returned future is completed with
+ * the value at that time.
+ * For an empty stream, the future is completed with [initialValue].
+ *
+ * If this stream emits an error, or the call to [combine] throws,
+ * the returned future is completed with that error,
+ * and processing is stopped.
+ */
+ Future<S> fold<S>(S initialValue, S combine(S previous, T element)) {
+ _Future<S> result = new _Future<S>();
+ S value = initialValue;
+ StreamSubscription subscription;
+ subscription = this.listen(
+ (T element) {
+ _runUserCode(() => combine(value, element), (S newValue) {
+ value = newValue;
+ }, _cancelAndErrorClosure(subscription, result));
+ },
+ onError: result._completeError,
+ onDone: () {
+ result._complete(value);
+ },
+ cancelOnError: true);
+ return result;
+ }
+
+ /**
+ * Combines the string representation of elements into a single string.
+ *
+ * Each element is converted to a string using its [Object.toString] method.
+ * If [separator] is provided, it is inserted between element string
+ * representations.
+ *
+ * The returned future is completed with the combined string when this stream
+ * is done.
+ *
+ * If this stream emits an error, or the call to [Object.toString] throws,
+ * the returned future is completed with that error,
+ * and processing stops.
+ */
+ Future<String> join([String separator = ""]) {
+ _Future<String> result = new _Future<String>();
+ StringBuffer buffer = new StringBuffer();
+ StreamSubscription subscription;
+ bool first = true;
+ subscription = this.listen(
+ (T element) {
+ if (!first) {
+ buffer.write(separator);
+ }
+ first = false;
+ try {
+ buffer.write(element);
+ } catch (e, s) {
+ _cancelAndErrorWithReplacement(subscription, result, e, s);
+ }
+ },
+ onError: result._completeError,
+ onDone: () {
+ result._complete(buffer.toString());
+ },
+ cancelOnError: true);
+ return result;
+ }
+
+ /**
+ * Returns whether [needle] occurs in the elements provided by this stream.
+ *
+ * Compares each element of this stream to [needle] using [Object.==].
+ * If an equal element is found, the returned future is completed with `true`.
+ * If this stream ends without finding a match, the future is completed with
+ * `false`.
+ *
+ * If this stream emits an error, or the call to [Object.==] throws,
+ * the returned future is completed with that error,
+ * and processing stops.
+ */
+ Future<bool> contains(Object needle) {
+ _Future<bool> future = new _Future<bool>();
+ StreamSubscription subscription;
+ subscription = this.listen(
+ (T element) {
+ _runUserCode(() => (element == needle), (bool isMatch) {
+ if (isMatch) {
+ _cancelAndValue(subscription, future, true);
+ }
+ }, _cancelAndErrorClosure(subscription, future));
+ },
+ onError: future._completeError,
+ onDone: () {
+ future._complete(false);
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * Executes [action] on each element of this stream.
+ *
+ * Completes the returned [Future] when all elements of this stream
+ * have been processed.
+ *
+ * If this stream emits an error, or if the call to [action] throws,
+ * the returned future completes with that error,
+ * and processing stops.
+ */
+ Future forEach(void action(T element)) {
+ _Future future = new _Future();
+ StreamSubscription subscription;
+ subscription = this.listen(
+ (T element) {
+ // TODO(floitsch): the type should be 'void' and inferred.
+ _runUserCode<dynamic>(() => action(element), (_) {},
+ _cancelAndErrorClosure(subscription, future));
+ },
+ onError: future._completeError,
+ onDone: () {
+ future._complete(null);
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * Checks whether [test] accepts all elements provided by this stream.
+ *
+ * Calls [test] on each element of this stream.
+ * If the call returns `false`, the returned future is completed with `false`
+ * and processing stops.
+ *
+ * If this stream ends without finding an element that [test] rejects,
+ * the returned future is completed with `true`.
+ *
+ * If this stream emits an error, or if the call to [test] throws,
+ * the returned future is completed with that error,
+ * and processing stops.
+ */
+ Future<bool> every(bool test(T element)) {
+ _Future<bool> future = new _Future<bool>();
+ StreamSubscription subscription;
+ subscription = this.listen(
+ (T element) {
+ _runUserCode(() => test(element), (bool isMatch) {
+ if (!isMatch) {
+ _cancelAndValue(subscription, future, false);
+ }
+ }, _cancelAndErrorClosure(subscription, future));
+ },
+ onError: future._completeError,
+ onDone: () {
+ future._complete(true);
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * Checks whether [test] accepts any element provided by this stream.
+ *
+ * Calls [test] on each element of this stream.
+ * If the call returns `true`, the returned future is completed with `true`
+ * and processing stops.
+ *
+ * If this stream ends without finding an element that [test] accepts,
+ * the returned future is completed with `false`.
+ *
+ * If this stream emits an error, or if the call to [test] throws,
+ * the returned future is completed with that error,
+ * and processing stops.
+ */
+ Future<bool> any(bool test(T element)) {
+ _Future<bool> future = new _Future<bool>();
+ StreamSubscription subscription;
+ subscription = this.listen(
+ (T element) {
+ _runUserCode(() => test(element), (bool isMatch) {
+ if (isMatch) {
+ _cancelAndValue(subscription, future, true);
+ }
+ }, _cancelAndErrorClosure(subscription, future));
+ },
+ onError: future._completeError,
+ onDone: () {
+ future._complete(false);
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * The number of elements in this stream.
+ *
+ * Waits for all elements of this stream. When this stream ends,
+ * the returned future is completed with the number of elements.
+ *
+ * If this stream emits an error,
+ * the returned future is completed with that error,
+ * and processing stops.
+ *
+ * This operation listens to this stream, and a non-broadcast stream cannot
+ * be reused after finding its length.
+ */
+ Future<int> get length {
+ _Future<int> future = new _Future<int>();
+ int count = 0;
+ this.listen(
+ (_) {
+ count++;
+ },
+ onError: future._completeError,
+ onDone: () {
+ future._complete(count);
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * Whether this stream contains any elements.
+ *
+ * Waits for the first element of this stream, then completes the returned
+ * future with `true`.
+ * If this stream ends without emitting any elements, the returned future is
+ * completed with `false`.
+ *
+ * If the first event is an error, the returned future is completed with that
+ * error.
+ *
+ * This operation listens to this stream, and a non-broadcast stream cannot
+ * be reused after checking whether it is empty.
+ */
+ Future<bool> get isEmpty {
+ _Future<bool> future = new _Future<bool>();
+ StreamSubscription subscription;
+ subscription = this.listen(
+ (_) {
+ _cancelAndValue(subscription, future, false);
+ },
+ onError: future._completeError,
+ onDone: () {
+ future._complete(true);
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * Adapt this stream to be a `Stream<R>`.
+ *
+ * This stream is wrapped as a `Stream<R>` which checks at run-time that
+ * each data event emitted by this stream is also an instance of [R].
+ */
+ Stream<R> cast<R>() => Stream.castFrom<T, R>(this);
+ /**
+ * Collects all elements of this stream in a [List].
+ *
+ * Creates a `List<T>` and adds all elements of this stream to the list
+ * in the order they arrive.
+ * When this stream ends, the returned future is completed with that list.
+ *
+ * If this stream emits an error,
+ * the returned future is completed with that error,
+ * and processing stops.
+ */
+ Future<List<T>> toList() {
+ List<T> result = <T>[];
+ _Future<List<T>> future = new _Future<List<T>>();
+ this.listen(
+ (T data) {
+ result.add(data);
+ },
+ onError: future._completeError,
+ onDone: () {
+ future._complete(result);
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * Collects the data of this stream in a [Set].
+ *
+ * Creates a `Set<T>` and adds all elements of this stream to the set.
+ * in the order they arrive.
+ * When this stream ends, the returned future is completed with that set.
+ *
+ * The returned set is the same type as returned by `new Set<T>()`.
+ * If another type of set is needed, either use [forEach] to add each
+ * element to the set, or use
+ * `toList().then((list) => new SomeOtherSet.from(list))`
+ * to create the set.
+ *
+ * If this stream emits an error,
+ * the returned future is completed with that error,
+ * and processing stops.
+ */
+ Future<Set<T>> toSet() {
+ Set<T> result = new Set<T>();
+ _Future<Set<T>> future = new _Future<Set<T>>();
+ this.listen(
+ (T data) {
+ result.add(data);
+ },
+ onError: future._completeError,
+ onDone: () {
+ future._complete(result);
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * Discards all data on this stream, but signals when it is done or an error
+ * occurred.
+ *
+ * When subscribing using [drain], cancelOnError will be true. This means
+ * that the future will complete with the first error on this stream and then
+ * cancel the subscription.
+ * If this stream emits an error, or the call to [combine] throws,
+ * the returned future is completed with that error,
+ * and processing is stopped.
+ *
+ * In case of a `done` event the future completes with the given
+ * [futureValue].
+ */
+ Future<E> drain<E>([E futureValue]) =>
+ listen(null, cancelOnError: true).asFuture<E>(futureValue);
+
+ /**
+ * Provides at most the first [count] data events of this stream.
+ *
+ * Returns a stream that emits the same events that this stream would
+ * if listened to at the same time,
+ * until either this stream ends or it has emitted [count] data events,
+ * at which point the returned stream is done.
+ *
+ * If this stream produces fewer than [count] data events before it's done,
+ * so will the returned stream.
+ *
+ * Starts listening to this stream when the returned stream is listened to
+ * and stops listening when the first [count] data events have been received.
+ *
+ * This means that if this is a single-subscription (non-broadcast) streams
+ * it cannot be reused after the returned stream has been listened to.
+ *
+ * If this is a broadcast stream, the returned stream is a broadcast stream.
+ * In that case, the events are only counted from the time
+ * the returned stream is listened to.
+ */
+ Stream<T> take(int count) {
+ return new _TakeStream<T>(this, count);
+ }
+
+ /**
+ * Forwards data events while [test] is successful.
+ *
+ * Returns a stream that provides the same events as this stream
+ * until [test] fails for a data event.
+ * The returned stream is done when either this stream is done,
+ * or when this stream first emits a data event that fails [test].
+ *
+ * The `test` call is considered failing if it returns a non-`true` value
+ * or if it throws. If the `test` call throws, the error is emitted as the
+ * last event on the returned streams.
+ *
+ * Stops listening to this stream after the accepted elements.
+ *
+ * Internally the method cancels its subscription after these elements. This
+ * means that single-subscription (non-broadcast) streams are closed and
+ * cannot be reused after a call to this method.
+ *
+ * The returned stream is a broadcast stream if this stream is.
+ * For a broadcast stream, the events are only tested from the time
+ * the returned stream is listened to.
+ */
+ Stream<T> takeWhile(bool test(T element)) {
+ return new _TakeWhileStream<T>(this, test);
+ }
+
+ /**
+ * Skips the first [count] data events from this stream.
+ *
+ * Returns a stream that emits the same events as this stream would
+ * if listened to at the same time, except that the first [count]
+ * data events are not emitted.
+ * The returned stream is done when this stream is.
+ *
+ * If this stream emits fewer than [count] data events
+ * before being done, the returned stream emits no data events.
+ *
+ * The returned stream is a broadcast stream if this stream is.
+ * For a broadcast stream, the events are only counted from the time
+ * the returned stream is listened to.
+ */
+ Stream<T> skip(int count) {
+ return new _SkipStream<T>(this, count);
+ }
+
+ /**
+ * Skip data events from this stream while they are matched by [test].
+ *
+ * Returns a stream that emits the same events as this stream,
+ * except that data events are not emitted until a data event fails `test`.
+ * The test fails when called with a data event
+ * if it returns a non-`true` value or if the call to `test` throws.
+ * If the call throws, the error is emitted as an error event
+ * on the returned stream instead of the data event,
+ * otherwise the event that made `test` return non-true is emitted as the
+ * first data event.
+ *
+ * Error and done events are provided by the returned stream unmodified.
+ *
+ * The returned stream is a broadcast stream if this stream is.
+ * For a broadcast stream, the events are only tested from the time
+ * the returned stream is listened to.
+ */
+ Stream<T> skipWhile(bool test(T element)) {
+ return new _SkipWhileStream<T>(this, test);
+ }
+
+ /**
+ * Skips data events if they are equal to the previous data event.
+ *
+ * The returned stream provides the same events as this stream, except
+ * that it never provides two consecutive data events that are equal.
+ * That is, errors are passed through to the returned stream, and
+ * data events are passed through if they are distinct from the most
+ * recently emitted data event.
+ *
+ * Equality is determined by the provided [equals] method. If that is
+ * omitted, the '==' operator on the last provided data element is used.
+ *
+ * If [equals] throws, the data event is replaced by an error event
+ * containing the thrown error. The behavior is equivalent to the
+ * original stream emitting the error event, and it doesn't change
+ * the what the most recently emitted data event is.
+ *
+ * The returned stream is a broadcast stream if this stream is.
+ * If a broadcast stream is listened to more than once, each subscription
+ * will individually perform the `equals` test.
+ */
+ Stream<T> distinct([bool equals(T previous, T next)]) {
+ return new _DistinctStream<T>(this, equals);
+ }
+
+ /**
+ * The first element of this stream.
+ *
+ * Stops listening to this stream after the first element has been received.
+ *
+ * Internally the method cancels its subscription after the first element.
+ * This means that single-subscription (non-broadcast) streams are closed
+ * and cannot be reused after a call to this getter.
+ *
+ * If an error event occurs before the first data event, the returned future
+ * is completed with that error.
+ *
+ * If this stream is empty (a done event occurs before the first data event),
+ * the returned future completes with an error.
+ *
+ * Except for the type of the error, this method is equivalent to
+ * `this.elementAt(0)`.
+ */
+ Future<T> get first {
+ _Future<T> future = new _Future<T>();
+ StreamSubscription subscription;
+ subscription = this.listen(
+ (T value) {
+ _cancelAndValue(subscription, future, value);
+ },
+ onError: future._completeError,
+ onDone: () {
+ try {
+ throw IterableElementError.noElement();
+ } catch (e, s) {
+ _completeWithErrorCallback(future, e, s);
+ }
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * The last element of this stream.
+ *
+ * If this stream emits an error event,
+ * the returned future is completed with that error
+ * and processing stops.
+ *
+ * If this stream is empty (the done event is the first event),
+ * the returned future completes with an error.
+ */
+ Future<T> get last {
+ _Future<T> future = new _Future<T>();
+ T result;
+ bool foundResult = false;
+ listen(
+ (T value) {
+ foundResult = true;
+ result = value;
+ },
+ onError: future._completeError,
+ onDone: () {
+ if (foundResult) {
+ future._complete(result);
+ return;
+ }
+ try {
+ throw IterableElementError.noElement();
+ } catch (e, s) {
+ _completeWithErrorCallback(future, e, s);
+ }
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * The single element of this stream.
+ *
+ * If this stream emits an error event,
+ * the returned future is completed with that error
+ * and processing stops.
+ *
+ * If [this] is empty or has more than one element,
+ * the returned future completes with an error.
+ */
+ Future<T> get single {
+ _Future<T> future = new _Future<T>();
+ T result;
+ bool foundResult = false;
+ StreamSubscription subscription;
+ subscription = this.listen(
+ (T value) {
+ if (foundResult) {
+ // This is the second element we get.
+ try {
+ throw IterableElementError.tooMany();
+ } catch (e, s) {
+ _cancelAndErrorWithReplacement(subscription, future, e, s);
+ }
+ return;
+ }
+ foundResult = true;
+ result = value;
+ },
+ onError: future._completeError,
+ onDone: () {
+ if (foundResult) {
+ future._complete(result);
+ return;
+ }
+ try {
+ throw IterableElementError.noElement();
+ } catch (e, s) {
+ _completeWithErrorCallback(future, e, s);
+ }
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * Finds the first element of this stream matching [test].
+ *
+ * Returns a future that is completed with the first element of this stream
+ * that [test] returns `true` for.
+ *
+ * If no such element is found before this stream is done, and a
+ * [orElse] function is provided, the result of calling [orElse]
+ * becomes the value of the future. If [orElse] throws, the returned
+ * future is completed with that error.
+ *
+ * If this stream emits an error before the first matching element,
+ * the returned future is completed with that error, and processing stops.
+ *
+ * Stops listening to this stream after the first matching element or error
+ * has been received.
+ *
+ * Internally the method cancels its subscription after the first element that
+ * matches the predicate. This means that single-subscription (non-broadcast)
+ * streams are closed and cannot be reused after a call to this method.
+ *
+ * If an error occurs, or if this stream ends without finding a match and
+ * with no [orElse] function provided,
+ * the returned future is completed with an error.
+ */
+ Future<T> firstWhere(bool test(T element), {T orElse()}) {
+ _Future<T> future = new _Future();
+ StreamSubscription subscription;
+ subscription = this.listen(
+ (T value) {
+ _runUserCode(() => test(value), (bool isMatch) {
+ if (isMatch) {
+ _cancelAndValue(subscription, future, value);
+ }
+ }, _cancelAndErrorClosure(subscription, future));
+ },
+ onError: future._completeError,
+ onDone: () {
+ if (orElse != null) {
+ _runUserCode(orElse, future._complete, future._completeError);
+ return;
+ }
+ try {
+ throw IterableElementError.noElement();
+ } catch (e, s) {
+ _completeWithErrorCallback(future, e, s);
+ }
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * Finds the last element in this stream matching [test].
+ *
+ * If this stream emits an error, the returned future is completed with that
+ * error, and processing stops.
+ *
+ * Otherwise as [firstWhere], except that the last matching element is found
+ * instead of the first.
+ * That means that a non-error result cannot be provided before this stream
+ * is done.
+ */
+ Future<T> lastWhere(bool test(T element), {T orElse()}) {
+ _Future<T> future = new _Future();
+ T result;
+ bool foundResult = false;
+ StreamSubscription subscription;
+ subscription = this.listen(
+ (T value) {
+ _runUserCode(() => true == test(value), (bool isMatch) {
+ if (isMatch) {
+ foundResult = true;
+ result = value;
+ }
+ }, _cancelAndErrorClosure(subscription, future));
+ },
+ onError: future._completeError,
+ onDone: () {
+ if (foundResult) {
+ future._complete(result);
+ return;
+ }
+ if (orElse != null) {
+ _runUserCode(orElse, future._complete, future._completeError);
+ return;
+ }
+ try {
+ throw IterableElementError.noElement();
+ } catch (e, s) {
+ _completeWithErrorCallback(future, e, s);
+ }
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * Finds the single element in this stream matching [test].
+ *
+ * Like [lastWhere], except that it is an error if more than one
+ * matching element occurs in this stream.
+ */
+ Future<T> singleWhere(bool test(T element), {T orElse()}) {
+ _Future<T> future = new _Future<T>();
+ T result;
+ bool foundResult = false;
+ StreamSubscription subscription;
+ subscription = this.listen(
+ (T value) {
+ _runUserCode(() => true == test(value), (bool isMatch) {
+ if (isMatch) {
+ if (foundResult) {
+ try {
+ throw IterableElementError.tooMany();
+ } catch (e, s) {
+ _cancelAndErrorWithReplacement(subscription, future, e, s);
+ }
+ return;
+ }
+ foundResult = true;
+ result = value;
+ }
+ }, _cancelAndErrorClosure(subscription, future));
+ },
+ onError: future._completeError,
+ onDone: () {
+ if (foundResult) {
+ future._complete(result);
+ return;
+ }
+ try {
+ if (orElse != null) {
+ _runUserCode(orElse, future._complete, future._completeError);
+ return;
+ }
+ throw IterableElementError.noElement();
+ } catch (e, s) {
+ _completeWithErrorCallback(future, e, s);
+ }
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * Returns the value of the [index]th data event of this stream.
+ *
+ * Stops listening to this stream after the [index]th data event has been
+ * received.
+ *
+ * Internally the method cancels its subscription after these elements. This
+ * means that single-subscription (non-broadcast) streams are closed and
+ * cannot be reused after a call to this method.
+ *
+ * If an error event occurs before the value is found, the future completes
+ * with this error.
+ *
+ * If a done event occurs before the value is found, the future completes
+ * with a [RangeError].
+ */
+ Future<T> elementAt(int index) {
+ ArgumentError.checkNotNull(index, "index");
+ RangeError.checkNotNegative(index, "index");
+ _Future<T> future = new _Future<T>();
+ StreamSubscription subscription;
+ int elementIndex = 0;
+ subscription = this.listen(
+ (T value) {
+ if (index == elementIndex) {
+ _cancelAndValue(subscription, future, value);
+ return;
+ }
+ elementIndex += 1;
+ },
+ onError: future._completeError,
+ onDone: () {
+ future._completeError(
+ new RangeError.index(index, this, "index", null, elementIndex));
+ },
+ cancelOnError: true);
+ return future;
+ }
+
+ /**
+ * Creates a new stream with the same events as this stream.
+ *
+ * Whenever more than [timeLimit] passes between two events from this stream,
+ * the [onTimeout] function is called, which can emit further events on
+ * the returned stream.
+ *
+ * The countdown doesn't start until the returned stream is listened to.
+ * The countdown is reset every time an event is forwarded from this stream,
+ * or when this stream is paused and resumed.
+ *
+ * The [onTimeout] function is called with one argument: an
+ * [EventSink] that allows putting events into the returned stream.
+ * This `EventSink` is only valid during the call to [onTimeout].
+ * Calling [EventSink.close] on the sink passed to [onTimeout] closes the
+ * returned stream, and no further events are processed.
+ *
+ * If [onTimeout] is omitted, a timeout will just put a [TimeoutException]
+ * into the error channel of the returned stream.
+ * If the call to [onTimeout] throws, the error is emitted on the returned
+ * stream.
+ *
+ * The returned stream is a broadcast stream if this stream is.
+ * If a broadcast stream is listened to more than once, each subscription
+ * will have its individually timer that starts counting on listen,
+ * and the subscriptions' timers can be paused individually.
+ */
+ Stream<T> timeout(Duration timeLimit, {void onTimeout(EventSink<T> sink)}) {
+ _StreamControllerBase<T> controller;
+ // The following variables are set on listen.
+ StreamSubscription<T> subscription;
+ Timer timer;
+ Zone zone;
+ _TimerCallback timeout;
+
+ void onData(T event) {
+ timer.cancel();
+ timer = zone.createTimer(timeLimit, timeout);
+ // It might close the stream and cancel timer, so create recuring Timer
+ // before calling into add();
+ // issue: https://github.com/dart-lang/sdk/issues/37565
+ controller.add(event);
+ }
+
+ void onError(error, StackTrace stackTrace) {
+ timer.cancel();
+ assert(controller is _StreamController ||
+ controller is _BroadcastStreamController);
+ controller._addError(error, stackTrace); // Avoid Zone error replacement.
+ timer = zone.createTimer(timeLimit, timeout);
+ }
+
+ void onDone() {
+ timer.cancel();
+ controller.close();
+ }
+
+ void onListen() {
+ // This is the onListen callback for of controller.
+ // It runs in the same zone that the subscription was created in.
+ // Use that zone for creating timers and running the onTimeout
+ // callback.
+ zone = Zone.current;
+ if (onTimeout == null) {
+ timeout = () {
+ controller.addError(
+ new TimeoutException("No stream event", timeLimit), null);
+ };
+ } else {
+ // TODO(floitsch): the return type should be 'void', and the type
+ // should be inferred.
+ var registeredOnTimeout =
+ zone.registerUnaryCallback<dynamic, EventSink<T>>(onTimeout);
+ var wrapper = new _ControllerEventSinkWrapper<T>(null);
+ timeout = () {
+ wrapper._sink = controller; // Only valid during call.
+ zone.runUnaryGuarded(registeredOnTimeout, wrapper);
+ wrapper._sink = null;
+ };
+ }
+
+ subscription = this.listen(onData, onError: onError, onDone: onDone);
+ timer = zone.createTimer(timeLimit, timeout);
+ }
+
+ Future onCancel() {
+ timer.cancel();
+ Future result = subscription.cancel();
+ subscription = null;
+ return result;
+ }
+
+ controller = isBroadcast
+ ? new _SyncBroadcastStreamController<T>(onListen, onCancel)
+ : new _SyncStreamController<T>(onListen, () {
+ // Don't null the timer, onCancel may call cancel again.
+ timer.cancel();
+ subscription.pause();
+ }, () {
+ subscription.resume();
+ timer = zone.createTimer(timeLimit, timeout);
+ }, onCancel);
+ return controller.stream;
+ }
+}
+
+/**
+ * A subscription on events from a [Stream].
+ *
+ * When you listen on a [Stream] using [Stream.listen],
+ * a [StreamSubscription] object is returned.
+ *
+ * The subscription provides events to the listener,
+ * and holds the callbacks used to handle the events.
+ * The subscription can also be used to unsubscribe from the events,
+ * or to temporarily pause the events from the stream.
+ */
+abstract class StreamSubscription<T> {
+ /**
+ * Cancels this subscription.
+ *
+ * After this call, the subscription no longer receives events.
+ *
+ * The stream may need to shut down the source of events and clean up after
+ * the subscription is canceled.
+ *
+ * Returns a future that is completed once the stream has finished
+ * its cleanup.
+ *
+ * For historical reasons, may also return `null` if no cleanup was necessary.
+ * Returning `null` is deprecated and should be avoided.
+ *
+ * Typically, futures are returned when the stream needs to release resources.
+ * For example, a stream might need to close an open file (as an asynchronous
+ * operation). If the listener wants to delete the file after having
+ * canceled the subscription, it must wait for the cleanup future to complete.
+ *
+ * A returned future completes with a `null` value.
+ * If the cleanup throws, which it really shouldn't, the returned future
+ * completes with that error.
+ */
+ Future cancel();
+
+ /**
+ * Replaces the data event handler of this subscription.
+ *
+ * The [handleData] function is called for each element of the stream
+ * after this function is called.
+ * If [handleData] is `null`, further elements are ignored.
+ *
+ * This method replaces the current handler set by the invocation of
+ * [Stream.listen] or by a previous call to [onData].
+ */
+ void onData(void handleData(T data));
+
+ /**
+ * Replaces the error event handler of this subscription.
+ *
+ * The [handleError] function must be able to be called with either
+ * one positional argument, or with two positional arguments
+ * where the seconds is always a [StackTrace].
+ *
+ * The [handleError] argument may be `null`, in which case further
+ * error events are considered unhandled, and will be reported to
+ * [Zone.handleUncaughtError].
+ *
+ * The provided function is called for all error events from the
+ * stream subscription.
+ *
+ * This method replaces the current handler set by the invocation of
+ * [Stream.listen], by calling [asFuture], or by a previous call to [onError].
+ */
+ void onError(Function handleError);
+
+ /**
+ * Replaces the done event handler of this subscription.
+ *
+ * The [handleDone] function is called when the stream closes.
+ * The value may be `null`, in which case no function is called.
+ *
+ * This method replaces the current handler set by the invocation of
+ * [Stream.listen], by calling [asFuture], or by a previous call to [onDone].
+ */
+ void onDone(void handleDone());
+
+ /**
+ * Request that the stream pauses events until further notice.
+ *
+ * While paused, the subscription will not fire any events.
+ * If it receives events from its source, they will be buffered until
+ * the subscription is resumed.
+ * For non-broadcast streams, the underlying source is usually informed
+ * about the pause,
+ * so it can stop generating events until the subscription is resumed.
+ *
+ * To avoid buffering events on a broadcast stream, it is better to
+ * cancel this subscription, and start to listen again when events
+ * are needed, if the intermediate events are not important.
+ *
+ * If [resumeSignal] is provided, the stream subscription will undo the pause
+ * when the future completes, as if by a call to [resume].
+ * If the future completes with an error,
+ * the stream will still resume, but the error will be considered unhandled
+ * and is passed to [Zone.handleUncaughtError].
+ *
+ * A call to [resume] will also undo a pause.
+ *
+ * If the subscription is paused more than once, an equal number
+ * of resumes must be performed to resume the stream.
+ * Calls to [resume] and the completion of a [resumeSignal] are
+ * interchangeable - the [pause] which was passed a [resumeSignal] may be
+ * ended by a call to [resume], and completing the [resumeSignal] may end a
+ * different [pause].
+ *
+ * It is safe to [resume] or complete a [resumeSignal] even when the
+ * subscription is not paused, and the resume will have no effect.
+ *
+ * Currently DOM streams silently drop events when the stream is paused. This
+ * is a bug and will be fixed.
+ */
+ void pause([Future resumeSignal]);
+
+ /**
+ * Resume after a pause.
+ *
+ * This undoes one previous call to [pause].
+ * When all previously calls to [pause] have been matched by a calls to
+ * [resume], possibly through a `resumeSignal` passed to [pause],
+ * the stream subscription may emit events again.
+ *
+ * It is safe to [resume] even when the subscription is not paused, and the
+ * resume will have no effect.
+ */
+ void resume();
+
+ /**
+ * Whether the [StreamSubscription] is currently paused.
+ *
+ * If there have been more calls to [pause] than to [resume] on this
+ * stream subscription, the subscription is paused, and this getter
+ * returns `true`.
+ *
+ * Returns `false` if the stream can currently emit events, or if
+ * the subscription has completed or been cancelled.
+ */
+ bool get isPaused;
+
+ /**
+ * Returns a future that handles the [onDone] and [onError] callbacks.
+ *
+ * This method *overwrites* the existing [onDone] and [onError] callbacks
+ * with new ones that complete the returned future.
+ *
+ * In case of an error the subscription will automatically cancel (even
+ * when it was listening with `cancelOnError` set to `false`).
+ *
+ * In case of a `done` event the future completes with the given
+ * [futureValue].
+ */
+ Future<E> asFuture<E>([E futureValue]);
+}
+
+/**
+ * A [Sink] that supports adding errors.
+ *
+ * This makes it suitable for capturing the results of asynchronous
+ * computations, which can complete with a value or an error.
+ *
+ * The [EventSink] has been designed to handle asynchronous events from
+ * [Stream]s. See, for example, [Stream.eventTransformed] which uses
+ * `EventSink`s to transform events.
+ */
+abstract class EventSink<T> implements Sink<T> {
+ /**
+ * Adds a data [event] to the sink.
+ *
+ * Must not be called on a closed sink.
+ */
+ void add(T event);
+
+ /**
+ * Adds an [error] to the sink.
+ *
+ * Must not be called on a closed sink.
+ */
+ void addError(Object error, [StackTrace stackTrace]);
+
+ /**
+ * Closes the sink.
+ *
+ * Calling this method more than once is allowed, but does nothing.
+ *
+ * Neither [add] nor [addError] must be called after this method.
+ */
+ void close();
+}
+
+/** [Stream] wrapper that only exposes the [Stream] interface. */
+class StreamView<T> extends Stream<T> {
+ final Stream<T> _stream;
+
+ const StreamView(Stream<T> stream)
+ : _stream = stream,
+ super._internal();
+
+ bool get isBroadcast => _stream.isBroadcast;
+
+ Stream<T> asBroadcastStream(
+ {void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)}) =>
+ _stream.asBroadcastStream(onListen: onListen, onCancel: onCancel);
+
+ StreamSubscription<T> listen(void onData(T value),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ return _stream.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+}
+
+/**
+ * Abstract interface for a "sink" accepting multiple entire streams.
+ *
+ * A consumer can accept a number of consecutive streams using [addStream],
+ * and when no further data need to be added, the [close] method tells the
+ * consumer to complete its work and shut down.
+ *
+ * The [Stream.pipe] accepts a `StreamConsumer` and will pass the stream
+ * to the consumer's [addStream] method. When that completes, it will
+ * call [close] and then complete its own returned future.
+ */
+abstract class StreamConsumer<S> {
+ /**
+ * Consumes the elements of [stream].
+ *
+ * Listens on [stream] and does something for each event.
+ *
+ * Returns a future which is completed when the stream is done being added,
+ * and the consumer is ready to accept a new stream.
+ * No further calls to [addStream] or [close] should happen before the
+ * returned future has completed.
+ *
+ * The consumer may stop listening to the stream after an error,
+ * it may consume all the errors and only stop at a done event,
+ * or it may be canceled early if the receiver don't want any further events.
+ *
+ * If the consumer stops listening because of some error preventing it
+ * from continuing, it may report this error in the returned future,
+ * otherwise it will just complete the future with `null`.
+ */
+ Future addStream(Stream<S> stream);
+
+ /**
+ * Tells the consumer that no further streams will be added.
+ *
+ * This allows the consumer to complete any remaining work and release
+ * resources that are no longer needed
+ *
+ * Returns a future which is completed when the consumer has shut down.
+ * If cleaning up can fail, the error may be reported in the returned future,
+ * otherwise it completes with `null`.
+ */
+ Future close();
+}
+
+/**
+ * A object that accepts stream events both synchronously and asynchronously.
+ *
+ * A [StreamSink] combines the methods from [StreamConsumer] and [EventSink].
+ *
+ * The [EventSink] methods can't be used while the [addStream] is called.
+ * As soon as the [addStream]'s [Future] completes with a value, the
+ * [EventSink] methods can be used again.
+ *
+ * If [addStream] is called after any of the [EventSink] methods, it'll
+ * be delayed until the underlying system has consumed the data added by the
+ * [EventSink] methods.
+ *
+ * When [EventSink] methods are used, the [done] [Future] can be used to
+ * catch any errors.
+ *
+ * When [close] is called, it will return the [done] [Future].
+ */
+abstract class StreamSink<S> implements EventSink<S>, StreamConsumer<S> {
+ /**
+ * Tells the stream sink that no further streams will be added.
+ *
+ * This allows the stream sink to complete any remaining work and release
+ * resources that are no longer needed
+ *
+ * Returns a future which is completed when the stream sink has shut down.
+ * If cleaning up can fail, the error may be reported in the returned future,
+ * otherwise it completes with `null`.
+ *
+ * Returns the same future as [done].
+ *
+ * The stream sink may close before the [close] method is called, either due
+ * to an error or because it is itself providing events to someone who has
+ * stopped listening. In that case, the [done] future is completed first,
+ * and the `close` method will return the `done` future when called.
+ *
+ * Unifies [StreamConsumer.close] and [EventSink.close] which both mark their
+ * object as not expecting any further events.
+ */
+ Future close();
+
+ /**
+ * Return a future which is completed when the [StreamSink] is finished.
+ *
+ * If the `StreamSink` fails with an error,
+ * perhaps in response to adding events using [add], [addError] or [close],
+ * the [done] future will complete with that error.
+ *
+ * Otherwise, the returned future will complete when either:
+ *
+ * * all events have been processed and the sink has been closed, or
+ * * the sink has otherwise been stopped from handling more events
+ * (for example by canceling a stream subscription).
+ */
+ Future get done;
+}
+
+/**
+ * Transforms a Stream.
+ *
+ * When a stream's [Stream.transform] method is invoked with a
+ * [StreamTransformer], the stream calls the [bind] method on the provided
+ * transformer. The resulting stream is then returned from the
+ * [Stream.transform] method.
+ *
+ * Conceptually, a transformer is simply a function from [Stream] to [Stream]
+ * that is encapsulated into a class.
+ *
+ * It is good practice to write transformers that can be used multiple times.
+ *
+ * All other transforming methods on [Stream], such as [Stream.map],
+ * [Stream.where] or [Stream.expand] can be implemented using
+ * [Stream.transform]. A [StreamTransformer] is thus very powerful but often
+ * also a bit more complicated to use.
+ */
+abstract class StreamTransformer<S, T> {
+ /**
+ * Creates a [StreamTransformer] based on the given [onListen] callback.
+ *
+ * The returned stream transformer uses the provided [onListen] callback
+ * when a transformed stream is listened to. At that time, the callback
+ * receives the input stream (the one passed to [bind]) and a
+ * boolean flag `cancelOnError` to create a [StreamSubscription].
+ *
+ * If the transformed stream is a broadcast stream, so is the stream
+ * returned by the [StreamTransformer.bind] method by this transformer.
+ *
+ * If the transformed stream is listened to multiple times, the [onListen]
+ * callback is called again for each new [Stream.listen] call.
+ * This happens whether the stream is a broadcast stream or not,
+ * but the call will usually fail for non-broadcast streams.
+ *
+ * The [onListen] callback does *not* receive the handlers that were passed
+ * to [Stream.listen]. These are automatically set after the call to the
+ * [onListen] callback (using [StreamSubscription.onData],
+ * [StreamSubscription.onError] and [StreamSubscription.onDone]).
+ *
+ * Most commonly, an [onListen] callback will first call [Stream.listen] on
+ * the provided stream (with the corresponding `cancelOnError` flag), and then
+ * return a new [StreamSubscription].
+ *
+ * There are two common ways to create a StreamSubscription:
+ *
+ * 1. by allocating a [StreamController] and to return the result of
+ * listening to its stream. It's important to forward pause, resume and
+ * cancel events (unless the transformer intentionally wants to change
+ * this behavior).
+ * 2. by creating a new class that implements [StreamSubscription].
+ * Note that the subscription should run callbacks in the [Zone] the
+ * stream was listened to (see [Zone] and [Zone.bindCallback]).
+ *
+ * Example:
+ *
+ * ```
+ * /// Starts listening to [input] and duplicates all non-error events.
+ * StreamSubscription<int> _onListen(Stream<int> input, bool cancelOnError) {
+ * StreamSubscription<String> subscription;
+ * // Create controller that forwards pause, resume and cancel events.
+ * var controller = new StreamController<String>(
+ * onPause: () {
+ * subscription.pause();
+ * },
+ * onResume: () {
+ * subscription.resume();
+ * },
+ * onCancel: () => subscription.cancel(),
+ * sync: true); // "sync" is correct here, since events are forwarded.
+ *
+ * // Listen to the provided stream using `cancelOnError`.
+ * subscription = input.listen((data) {
+ * // Duplicate the data.
+ * controller.add(data);
+ * controller.add(data);
+ * },
+ * onError: controller.addError,
+ * onDone: controller.close,
+ * cancelOnError: cancelOnError);
+ *
+ * // Return a new [StreamSubscription] by listening to the controller's
+ * // stream.
+ * return controller.stream.listen(null);
+ * }
+ *
+ * // Instantiate a transformer:
+ * var duplicator = const StreamTransformer<int, int>(_onListen);
+ *
+ * // Use as follows:
+ * intStream.transform(duplicator);
+ * ```
+ */
+ const factory StreamTransformer(
+ StreamSubscription<T> onListen(
+ Stream<S> stream, bool cancelOnError)) =
+ _StreamSubscriptionTransformer<S, T>;
+
+ /**
+ * Creates a [StreamTransformer] that delegates events to the given functions.
+ *
+ * Example use of a duplicating transformer:
+ *
+ * ```
+ * stringStream.transform(new StreamTransformer<String, String>.fromHandlers(
+ * handleData: (String value, EventSink<String> sink) {
+ * sink.add(value);
+ * sink.add(value); // Duplicate the incoming events.
+ * }));
+ * ```
+ *
+ * Transformers that are constructed this way cannot use captured state if
+ * they are used in streams that can be listened to multiple times.
+ * ```
+ * StreamController<String> controller;
+ * controller = new StreamController.broadcast(onListen: () {
+ * scheduleMicrotask(() {
+ * controller.addError("Bad");
+ * controller.addError("Worse");
+ * controller.addError("Worst");
+ * });
+ * });
+ * var sharedState = 0;
+ * var transformedStream = controller.stream.transform(
+ * new StreamTransformer<String>.fromHandlers(
+ * handleError: (error, stackTrace, sink) {
+ * sharedState++; // Increment shared error-counter.
+ * sink.add("Error $sharedState: $error");
+ * }));
+ *
+ * transformedStream.listen(print);
+ * transformedStream.listen(print); // Listen twice.
+ * // Listening twice to the same stream makes the transformer share the same
+ * // state. Instead of having "Error 1: Bad", "Error 2: Worse",
+ * // "Error 3: Worst" as output (each twice for the separate subscriptions),
+ * // this program emits:
+ * // Error 1: Bad
+ * // Error 2: Bad
+ * // Error 3: Worse
+ * // Error 4: Worse
+ * // Error 5: Worst
+ * // Error 6: Worst
+ * ```
+ */
+ factory StreamTransformer.fromHandlers(
+ {void handleData(S data, EventSink<T> sink),
+ void handleError(Object error, StackTrace stackTrace, EventSink<T> sink),
+ void handleDone(EventSink<T> sink)}) = _StreamHandlerTransformer<S, T>;
+
+ /**
+ * Creates a [StreamTransformer] based on a [bind] callback.
+ *
+ * The returned stream transformer uses the [bind] argument to implement the
+ * [StreamTransformer.bind] API and can be used when the transformation is
+ * available as a stream-to-stream function.
+ *
+ * ```dart
+ * final splitDecoded = StreamTransformer<List<int>, String>.fromBind(
+ * (stream) => stream.transform(utf8.decoder).transform(LineSplitter()));
+ * ```
+ */
+ @Since("2.1")
+ factory StreamTransformer.fromBind(Stream<T> Function(Stream<S>) bind) =
+ _StreamBindTransformer<S, T>;
+
+ /**
+ * Adapts [source] to be a `StreamTransformer<TS, TT>`.
+ *
+ * This allows [source] to be used at the new type, but at run-time it
+ * must satisfy the requirements of both the new type and its original type.
+ *
+ * Data events passed into the returned transformer must also be instances
+ * of [SS], and data events produced by [source] for those events must
+ * also be instances of [TT].
+ */
+ static StreamTransformer<TS, TT> castFrom<SS, ST, TS, TT>(
+ StreamTransformer<SS, ST> source) {
+ return new CastStreamTransformer<SS, ST, TS, TT>(source);
+ }
+
+ /**
+ * Transforms the provided [stream].
+ *
+ * Returns a new stream with events that are computed from events of the
+ * provided [stream].
+ *
+ * The [StreamTransformer] interface is completely generic,
+ * so it cannot say what subclasses do.
+ * Each [StreamTransformer] should document clearly how it transforms the
+ * stream (on the class or variable used to access the transformer),
+ * as well as any differences from the following typical behavior:
+ *
+ * * When the returned stream is listened to, it starts listening to the
+ * input [stream].
+ * * Subscriptions of the returned stream forward (in a reasonable time)
+ * a [StreamSubscription.pause] call to the subscription of the input
+ * [stream].
+ * * Similarly, canceling a subscription of the returned stream eventually
+ * (in reasonable time) cancels the subscription of the input [stream].
+ *
+ * "Reasonable time" depends on the transformer and stream. Some transformers,
+ * like a "timeout" transformer, might make these operations depend on a
+ * duration. Others might not delay them at all, or just by a microtask.
+ *
+ * Transformers are free to handle errors in any way.
+ * A transformer implementation may choose to propagate errors,
+ * or convert them to other events, or ignore them completely,
+ * but if errors are ignored, it should be documented explicitly.
+ */
+ Stream<T> bind(Stream<S> stream);
+
+ /**
+ * Provides a `StreamTransformer<RS, RT>` view of this stream transformer.
+ *
+ * The resulting transformer will check at run-time that all data events
+ * of the stream it transforms are actually instances of [S],
+ * and it will check that all data events produced by this transformer
+ * are actually instances of [RT].
+ */
+ StreamTransformer<RS, RT> cast<RS, RT>();
+}
+
+/**
+ * Base class for implementing [StreamTransformer].
+ *
+ * Contains default implementations of every method except [bind].
+ */
+abstract class StreamTransformerBase<S, T> implements StreamTransformer<S, T> {
+ const StreamTransformerBase();
+
+ StreamTransformer<RS, RT> cast<RS, RT>() =>
+ StreamTransformer.castFrom<S, T, RS, RT>(this);
+}
+
+/**
+ * An [Iterator] like interface for the values of a [Stream].
+ *
+ * This wraps a [Stream] and a subscription on the stream. It listens
+ * on the stream, and completes the future returned by [moveNext] when the
+ * next value becomes available.
+ *
+ * The stream may be paused between calls to [moveNext].
+ */
+abstract class StreamIterator<T> {
+ /** Create a [StreamIterator] on [stream]. */
+ factory StreamIterator(Stream<T> stream)
+ // TODO(lrn): use redirecting factory constructor when type
+ // arguments are supported.
+ =>
+ new _StreamIterator<T>(stream);
+
+ /**
+ * Wait for the next stream value to be available.
+ *
+ * Returns a future which will complete with either `true` or `false`.
+ * Completing with `true` means that another event has been received and
+ * can be read as [current].
+ * Completing with `false` means that the stream iteration is done and
+ * no further events will ever be available.
+ * The future may complete with an error, if the stream produces an error,
+ * which also ends iteration.
+ *
+ * The function must not be called again until the future returned by a
+ * previous call is completed.
+ */
+ Future<bool> moveNext();
+
+ /**
+ * The current value of the stream.
+ *
+ * Is `null` before the first call to [moveNext] and after a call to
+ * `moveNext` completes with a `false` result or an error.
+ *
+ * When a `moveNext` call completes with `true`, the `current` field holds
+ * the most recent event of the stream, and it stays like that until the next
+ * call to `moveNext`.
+ * Between a call to `moveNext` and when its returned future completes,
+ * the value is unspecified.
+ */
+ T get current;
+
+ /**
+ * Cancels the stream iterator (and the underlying stream subscription) early.
+ *
+ * The stream iterator is automatically canceled if the [moveNext] future
+ * completes with either `false` or an error.
+ *
+ * If you need to stop listening for values before the stream iterator is
+ * automatically closed, you must call [cancel] to ensure that the stream
+ * is properly closed.
+ *
+ * If [moveNext] has been called when the iterator is canceled,
+ * its returned future will complete with `false` as value,
+ * as will all further calls to [moveNext].
+ *
+ * Returns a future if the cancel-operation is not completed synchronously.
+ * Otherwise returns `null`.
+ */
+ Future cancel();
+}
+
+/**
+ * Wraps an [_EventSink] so it exposes only the [EventSink] interface.
+ */
+class _ControllerEventSinkWrapper<T> implements EventSink<T> {
+ EventSink _sink;
+ _ControllerEventSinkWrapper(this._sink);
+
+ void add(T data) {
+ _sink.add(data);
+ }
+
+ void addError(error, [StackTrace stackTrace]) {
+ _sink.addError(error, stackTrace);
+ }
+
+ void close() {
+ _sink.close();
+ }
+}
diff --git a/sdk_nnbd/lib/async/stream_controller.dart b/sdk_nnbd/lib/async/stream_controller.dart
new file mode 100644
index 0000000..34c6adf
--- /dev/null
+++ b/sdk_nnbd/lib/async/stream_controller.dart
@@ -0,0 +1,942 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+// -------------------------------------------------------------------
+// Controller for creating and adding events to a stream.
+// -------------------------------------------------------------------
+
+/**
+ * Type of a stream controller's `onListen`, `onPause` and `onResume` callbacks.
+ */
+typedef void ControllerCallback();
+
+/**
+ * Type of stream controller `onCancel` callbacks.
+ *
+ * The callback may return either `void` or a future.
+ */
+typedef ControllerCancelCallback();
+
+/**
+ * A controller with the stream it controls.
+ *
+ * This controller allows sending data, error and done events on
+ * its [stream].
+ * This class can be used to create a simple stream that others
+ * can listen on, and to push events to that stream.
+ *
+ * It's possible to check whether the stream is paused or not, and whether
+ * it has subscribers or not, as well as getting a callback when either of
+ * these change.
+ */
+abstract class StreamController<T> implements StreamSink<T> {
+ /** The stream that this controller is controlling. */
+ Stream<T> get stream;
+
+ /**
+ * A controller with a [stream] that supports only one single subscriber.
+ *
+ * If [sync] is true, the returned stream controller is a
+ * [SynchronousStreamController], and must be used with the care
+ * and attention necessary to not break the [Stream] contract. If in doubt,
+ * use the non-sync version.
+ *
+ * Using an asynchronous controller will never give the wrong
+ * behavior, but using a synchronous controller incorrectly can cause
+ * otherwise correct programs to break.
+ *
+ * A synchronous controller is only intended for optimizing event
+ * propagation when one asynchronous event immediately triggers another.
+ * It should not be used unless the calls to [add] or [addError]
+ * are guaranteed to occur in places where it won't break `Stream` invariants.
+ *
+ * Use synchronous controllers only to forward (potentially transformed)
+ * events from another stream or a future.
+ *
+ * A Stream should be inert until a subscriber starts listening on it (using
+ * the [onListen] callback to start producing events). Streams should not
+ * leak resources (like websockets) when no user ever listens on the stream.
+ *
+ * The controller buffers all incoming events until a subscriber is
+ * registered, but this feature should only be used in rare circumstances.
+ *
+ * The [onPause] function is called when the stream becomes
+ * paused. [onResume] is called when the stream resumed.
+ *
+ * The [onListen] callback is called when the stream
+ * receives its listener and [onCancel] when the listener ends
+ * its subscription. If [onCancel] needs to perform an asynchronous operation,
+ * [onCancel] should return a future that completes when the cancel operation
+ * is done.
+ *
+ * If the stream is canceled before the controller needs new data the
+ * [onResume] call might not be executed.
+ */
+ factory StreamController(
+ {void onListen(),
+ void onPause(),
+ void onResume(),
+ onCancel(),
+ bool sync: false}) {
+ return sync
+ ? new _SyncStreamController<T>(onListen, onPause, onResume, onCancel)
+ : new _AsyncStreamController<T>(onListen, onPause, onResume, onCancel);
+ }
+
+ /**
+ * A controller where [stream] can be listened to more than once.
+ *
+ * The [Stream] returned by [stream] is a broadcast stream.
+ * It can be listened to more than once.
+ *
+ * A Stream should be inert until a subscriber starts listening on it (using
+ * the [onListen] callback to start producing events). Streams should not
+ * leak resources (like websockets) when no user ever listens on the stream.
+ *
+ * Broadcast streams do not buffer events when there is no listener.
+ *
+ * The controller distributes any events to all currently subscribed
+ * listeners at the time when [add], [addError] or [close] is called.
+ * It is not allowed to call `add`, `addError`, or `close` before a previous
+ * call has returned. The controller does not have any internal queue of
+ * events, and if there are no listeners at the time the event is added,
+ * it will just be dropped, or, if it is an error, be reported as uncaught.
+ *
+ * Each listener subscription is handled independently,
+ * and if one pauses, only the pausing listener is affected.
+ * A paused listener will buffer events internally until unpaused or canceled.
+ *
+ * If [sync] is true, events may be fired directly by the stream's
+ * subscriptions during an [add], [addError] or [close] call.
+ * The returned stream controller is a [SynchronousStreamController],
+ * and must be used with the care and attention necessary to not break
+ * the [Stream] contract.
+ * See [Completer.sync] for some explanations on when a synchronous
+ * dispatching can be used.
+ * If in doubt, keep the controller non-sync.
+ *
+ * If [sync] is false, the event will always be fired at a later time,
+ * after the code adding the event has completed.
+ * In that case, no guarantees are given with regard to when
+ * multiple listeners get the events, except that each listener will get
+ * all events in the correct order. Each subscription handles the events
+ * individually.
+ * If two events are sent on an async controller with two listeners,
+ * one of the listeners may get both events
+ * before the other listener gets any.
+ * A listener must be subscribed both when the event is initiated
+ * (that is, when [add] is called)
+ * and when the event is later delivered,
+ * in order to receive the event.
+ *
+ * The [onListen] callback is called when the first listener is subscribed,
+ * and the [onCancel] is called when there are no longer any active listeners.
+ * If a listener is added again later, after the [onCancel] was called,
+ * the [onListen] will be called again.
+ */
+ factory StreamController.broadcast(
+ {void onListen(), void onCancel(), bool sync: false}) {
+ return sync
+ ? new _SyncBroadcastStreamController<T>(onListen, onCancel)
+ : new _AsyncBroadcastStreamController<T>(onListen, onCancel);
+ }
+
+ /**
+ * The callback which is called when the stream is listened to.
+ *
+ * May be set to `null`, in which case no callback will happen.
+ */
+ ControllerCallback get onListen;
+
+ void set onListen(void onListenHandler());
+
+ /**
+ * The callback which is called when the stream is paused.
+ *
+ * May be set to `null`, in which case no callback will happen.
+ *
+ * Pause related callbacks are not supported on broadcast stream controllers.
+ */
+ ControllerCallback get onPause;
+
+ void set onPause(void onPauseHandler());
+
+ /**
+ * The callback which is called when the stream is resumed.
+ *
+ * May be set to `null`, in which case no callback will happen.
+ *
+ * Pause related callbacks are not supported on broadcast stream controllers.
+ */
+ ControllerCallback get onResume;
+
+ void set onResume(void onResumeHandler());
+
+ /**
+ * The callback which is called when the stream is canceled.
+ *
+ * May be set to `null`, in which case no callback will happen.
+ */
+ ControllerCancelCallback get onCancel;
+
+ void set onCancel(onCancelHandler());
+
+ /**
+ * Returns a view of this object that only exposes the [StreamSink] interface.
+ */
+ StreamSink<T> get sink;
+
+ /**
+ * Whether the stream controller is closed for adding more events.
+ *
+ * The controller becomes closed by calling the [close] method.
+ * New events cannot be added, by calling [add] or [addError],
+ * to a closed controller.
+ *
+ * If the controller is closed,
+ * the "done" event might not have been delivered yet,
+ * but it has been scheduled, and it is too late to add more events.
+ */
+ bool get isClosed;
+
+ /**
+ * Whether the subscription would need to buffer events.
+ *
+ * This is the case if the controller's stream has a listener and it is
+ * paused, or if it has not received a listener yet. In that case, the
+ * controller is considered paused as well.
+ *
+ * A broadcast stream controller is never considered paused. It always
+ * forwards its events to all uncanceled subscriptions, if any,
+ * and let the subscriptions handle their own pausing and buffering.
+ */
+ bool get isPaused;
+
+ /** Whether there is a subscriber on the [Stream]. */
+ bool get hasListener;
+
+ /**
+ * Sends a data [event].
+ *
+ * Listeners receive this event in a later microtask.
+ *
+ * Note that a synchronous controller (created by passing true to the `sync`
+ * parameter of the `StreamController` constructor) delivers events
+ * immediately. Since this behavior violates the contract mentioned here,
+ * synchronous controllers should only be used as described in the
+ * documentation to ensure that the delivered events always *appear* as if
+ * they were delivered in a separate microtask.
+ */
+ void add(T event);
+
+ /**
+ * Sends or enqueues an error event.
+ *
+ * If [error] is `null`, it is replaced by a [NullThrownError].
+ *
+ * Listeners receive this event at a later microtask. This behavior can be
+ * overridden by using `sync` controllers. Note, however, that sync
+ * controllers have to satisfy the preconditions mentioned in the
+ * documentation of the constructors.
+ */
+ void addError(Object error, [StackTrace stackTrace]);
+
+ /**
+ * Closes the stream.
+ *
+ * Listeners receive the done event at a later microtask. This behavior can be
+ * overridden by using `sync` controllers. Note, however, that sync
+ * controllers have to satisfy the preconditions mentioned in the
+ * documentation of the constructors.
+ */
+ Future close();
+
+ /**
+ * Receives events from [source] and puts them into this controller's stream.
+ *
+ * Returns a future which completes when the source stream is done.
+ *
+ * Events must not be added directly to this controller using [add],
+ * [addError], [close] or [addStream], until the returned future
+ * is complete.
+ *
+ * Data and error events are forwarded to this controller's stream. A done
+ * event on the source will end the `addStream` operation and complete the
+ * returned future.
+ *
+ * If [cancelOnError] is true, only the first error on [source] is
+ * forwarded to the controller's stream, and the `addStream` ends
+ * after this. If [cancelOnError] is false, all errors are forwarded
+ * and only a done event will end the `addStream`.
+ * If [cancelOnError] is omitted, it defaults to false.
+ */
+ Future addStream(Stream<T> source, {bool cancelOnError});
+}
+
+/**
+ * A stream controller that delivers its events synchronously.
+ *
+ * A synchronous stream controller is intended for cases where
+ * an already asynchronous event triggers an event on a stream.
+ *
+ * Instead of adding the event to the stream in a later microtask,
+ * causing extra latency, the event is instead fired immediately by the
+ * synchronous stream controller, as if the stream event was
+ * the current event or microtask.
+ *
+ * The synchronous stream controller can be used to break the contract
+ * on [Stream], and it must be used carefully to avoid doing so.
+ *
+ * The only advantage to using a [SynchronousStreamController] over a
+ * normal [StreamController] is the improved latency.
+ * Only use the synchronous version if the improvement is significant,
+ * and if its use is safe. Otherwise just use a normal stream controller,
+ * which will always have the correct behavior for a [Stream], and won't
+ * accidentally break other code.
+ *
+ * Adding events to a synchronous controller should only happen as the
+ * very last part of the handling of the original event.
+ * At that point, adding an event to the stream is equivalent to
+ * returning to the event loop and adding the event in the next microtask.
+ *
+ * Each listener callback will be run as if it was a top-level event
+ * or microtask. This means that if it throws, the error will be reported as
+ * uncaught as soon as possible.
+ * This is one reason to add the event as the last thing in the original event
+ * handler - any action done after adding the event will delay the report of
+ * errors in the event listener callbacks.
+ *
+ * If an event is added in a setting that isn't known to be another event,
+ * it may cause the stream's listener to get that event before the listener
+ * is ready to handle it. We promise that after calling [Stream.listen],
+ * you won't get any events until the code doing the listen has completed.
+ * Calling [add] in response to a function call of unknown origin may break
+ * that promise.
+ *
+ * An [onListen] callback from the controller is *not* an asynchronous event,
+ * and adding events to the controller in the `onListen` callback is always
+ * wrong. The events will be delivered before the listener has even received
+ * the subscription yet.
+ *
+ * The synchronous broadcast stream controller also has a restrictions that a
+ * normal stream controller does not:
+ * The [add], [addError], [close] and [addStream] methods *must not* be
+ * called while an event is being delivered.
+ * That is, if a callback on a subscription on the controller's stream causes
+ * a call to any of the functions above, the call will fail.
+ * A broadcast stream may have more than one listener, and if an
+ * event is added synchronously while another is being also in the process
+ * of being added, the latter event might reach some listeners before
+ * the former. To prevent that, an event cannot be added while a previous
+ * event is being fired.
+ * This guarantees that an event is fully delivered when the
+ * first [add], [addError] or [close] returns,
+ * and further events will be delivered in the correct order.
+ *
+ * This still only guarantees that the event is delivered to the subscription.
+ * If the subscription is paused, the actual callback may still happen later,
+ * and the event will instead be buffered by the subscription.
+ * Barring pausing, and the following buffered events that haven't been
+ * delivered yet, callbacks will be called synchronously when an event is added.
+ *
+ * Adding an event to a synchronous non-broadcast stream controller while
+ * another event is in progress may cause the second event to be delayed
+ * and not be delivered synchronously, and until that event is delivered,
+ * the controller will not act synchronously.
+ */
+abstract class SynchronousStreamController<T> implements StreamController<T> {
+ /**
+ * Adds event to the controller's stream.
+ *
+ * As [StreamController.add], but must not be called while an event is
+ * being added by [add], [addError] or [close].
+ */
+ void add(T data);
+
+ /**
+ * Adds error to the controller's stream.
+ *
+ * As [StreamController.addError], but must not be called while an event is
+ * being added by [add], [addError] or [close].
+ */
+ void addError(Object error, [StackTrace stackTrace]);
+
+ /**
+ * Closes the controller's stream.
+ *
+ * As [StreamController.close], but must not be called while an event is
+ * being added by [add], [addError] or [close].
+ */
+ Future close();
+}
+
+abstract class _StreamControllerLifecycle<T> {
+ StreamSubscription<T> _subscribe(
+ void onData(T data), Function onError, void onDone(), bool cancelOnError);
+ void _recordPause(StreamSubscription<T> subscription) {}
+ void _recordResume(StreamSubscription<T> subscription) {}
+ Future _recordCancel(StreamSubscription<T> subscription) => null;
+}
+
+// Base type for implementations of stream controllers.
+abstract class _StreamControllerBase<T>
+ implements
+ StreamController<T>,
+ _StreamControllerLifecycle<T>,
+ _EventSink<T>,
+ _EventDispatch<T> {}
+
+/**
+ * Default implementation of [StreamController].
+ *
+ * Controls a stream that only supports a single controller.
+ */
+abstract class _StreamController<T> implements _StreamControllerBase<T> {
+ // The states are bit-flags. More than one can be set at a time.
+ //
+ // The "subscription state" goes through the states:
+ // initial -> subscribed -> canceled.
+ // These are mutually exclusive.
+ // The "closed" state records whether the [close] method has been called
+ // on the controller. This can be done at any time. If done before
+ // subscription, the done event is queued. If done after cancel, the done
+ // event is ignored (just as any other event after a cancel).
+
+ /** The controller is in its initial state with no subscription. */
+ static const int _STATE_INITIAL = 0;
+ /** The controller has a subscription, but hasn't been closed or canceled. */
+ static const int _STATE_SUBSCRIBED = 1;
+ /** The subscription is canceled. */
+ static const int _STATE_CANCELED = 2;
+ /** Mask for the subscription state. */
+ static const int _STATE_SUBSCRIPTION_MASK = 3;
+
+ // The following state relate to the controller, not the subscription.
+ // If closed, adding more events is not allowed.
+ // If executing an [addStream], new events are not allowed either, but will
+ // be added by the stream.
+
+ /**
+ * The controller is closed due to calling [close].
+ *
+ * When the stream is closed, you can neither add new events nor add new
+ * listeners.
+ */
+ static const int _STATE_CLOSED = 4;
+ /**
+ * The controller is in the middle of an [addStream] operation.
+ *
+ * While adding events from a stream, no new events can be added directly
+ * on the controller.
+ */
+ static const int _STATE_ADDSTREAM = 8;
+
+ /**
+ * Field containing different data depending on the current subscription
+ * state.
+ *
+ * If [_state] is [_STATE_INITIAL], the field may contain a [_PendingEvents]
+ * for events added to the controller before a subscription.
+ *
+ * While [_state] is [_STATE_SUBSCRIBED], the field contains the subscription.
+ *
+ * When [_state] is [_STATE_CANCELED] the field is currently not used.
+ */
+ var _varData;
+
+ /** Current state of the controller. */
+ int _state = _STATE_INITIAL;
+
+ /**
+ * Future completed when the stream sends its last event.
+ *
+ * This is also the future returned by [close].
+ */
+ // TODO(lrn): Could this be stored in the varData field too, if it's not
+ // accessed until the call to "close"? Then we need to special case if it's
+ // accessed earlier, or if close is called before subscribing.
+ _Future _doneFuture;
+
+ ControllerCallback onListen;
+ ControllerCallback onPause;
+ ControllerCallback onResume;
+ ControllerCancelCallback onCancel;
+
+ _StreamController(this.onListen, this.onPause, this.onResume, this.onCancel);
+
+ // Return a new stream every time. The streams are equal, but not identical.
+ Stream<T> get stream => new _ControllerStream<T>(this);
+
+ /**
+ * Returns a view of this object that only exposes the [StreamSink] interface.
+ */
+ StreamSink<T> get sink => new _StreamSinkWrapper<T>(this);
+
+ /**
+ * Whether a listener has existed and been canceled.
+ *
+ * After this, adding more events will be ignored.
+ */
+ bool get _isCanceled => (_state & _STATE_CANCELED) != 0;
+
+ /** Whether there is an active listener. */
+ bool get hasListener => (_state & _STATE_SUBSCRIBED) != 0;
+
+ /** Whether there has not been a listener yet. */
+ bool get _isInitialState =>
+ (_state & _STATE_SUBSCRIPTION_MASK) == _STATE_INITIAL;
+
+ bool get isClosed => (_state & _STATE_CLOSED) != 0;
+
+ bool get isPaused =>
+ hasListener ? _subscription._isInputPaused : !_isCanceled;
+
+ bool get _isAddingStream => (_state & _STATE_ADDSTREAM) != 0;
+
+ /** New events may not be added after close, or during addStream. */
+ bool get _mayAddEvent => (_state < _STATE_CLOSED);
+
+ // Returns the pending events.
+ // Pending events are events added before a subscription exists.
+ // They are added to the subscription when it is created.
+ // Pending events, if any, are kept in the _varData field until the
+ // stream is listened to.
+ // While adding a stream, pending events are moved into the
+ // state object to allow the state object to use the _varData field.
+ _PendingEvents<T> get _pendingEvents {
+ assert(_isInitialState);
+ if (!_isAddingStream) {
+ return _varData;
+ }
+ _StreamControllerAddStreamState<T> state = _varData;
+ return state.varData;
+ }
+
+ // Returns the pending events, and creates the object if necessary.
+ _StreamImplEvents<T> _ensurePendingEvents() {
+ assert(_isInitialState);
+ if (!_isAddingStream) {
+ _varData ??= new _StreamImplEvents<T>();
+ return _varData;
+ }
+ _StreamControllerAddStreamState<T> state = _varData;
+ if (state.varData == null) state.varData = new _StreamImplEvents<T>();
+ return state.varData;
+ }
+
+ // Get the current subscription.
+ // If we are adding a stream, the subscription is moved into the state
+ // object to allow the state object to use the _varData field.
+ _ControllerSubscription<T> get _subscription {
+ assert(hasListener);
+ if (_isAddingStream) {
+ _StreamControllerAddStreamState<T> addState = _varData;
+ return addState.varData;
+ }
+ return _varData;
+ }
+
+ /**
+ * Creates an error describing why an event cannot be added.
+ *
+ * The reason, and therefore the error message, depends on the current state.
+ */
+ Error _badEventState() {
+ if (isClosed) {
+ return new StateError("Cannot add event after closing");
+ }
+ assert(_isAddingStream);
+ return new StateError("Cannot add event while adding a stream");
+ }
+
+ // StreamSink interface.
+ Future addStream(Stream<T> source, {bool cancelOnError}) {
+ if (!_mayAddEvent) throw _badEventState();
+ if (_isCanceled) return new _Future.immediate(null);
+ _StreamControllerAddStreamState<T> addState =
+ new _StreamControllerAddStreamState<T>(
+ this, _varData, source, cancelOnError ?? false);
+ _varData = addState;
+ _state |= _STATE_ADDSTREAM;
+ return addState.addStreamFuture;
+ }
+
+ /**
+ * Returns a future that is completed when the stream is done
+ * processing events.
+ *
+ * This happens either when the done event has been sent, or if the
+ * subscriber of a single-subscription stream is cancelled.
+ */
+ Future get done => _ensureDoneFuture();
+
+ Future _ensureDoneFuture() {
+ _doneFuture ??= _isCanceled ? Future._nullFuture : new _Future();
+ return _doneFuture;
+ }
+
+ /**
+ * Send or enqueue a data event.
+ */
+ void add(T value) {
+ if (!_mayAddEvent) throw _badEventState();
+ _add(value);
+ }
+
+ /**
+ * Send or enqueue an error event.
+ */
+ void addError(Object error, [StackTrace stackTrace]) {
+ if (!_mayAddEvent) throw _badEventState();
+ error = _nonNullError(error);
+ AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+ if (replacement != null) {
+ error = _nonNullError(replacement.error);
+ stackTrace = replacement.stackTrace;
+ }
+ _addError(error, stackTrace);
+ }
+
+ /**
+ * Closes this controller and sends a done event on the stream.
+ *
+ * The first time a controller is closed, a "done" event is added to its
+ * stream.
+ *
+ * You are allowed to close the controller more than once, but only the first
+ * call has any effect.
+ *
+ * After closing, no further events may be added using [add], [addError]
+ * or [addStream].
+ *
+ * The returned future is completed when the done event has been delivered.
+ */
+ Future close() {
+ if (isClosed) {
+ return _ensureDoneFuture();
+ }
+ if (!_mayAddEvent) throw _badEventState();
+ _closeUnchecked();
+ return _ensureDoneFuture();
+ }
+
+ void _closeUnchecked() {
+ _state |= _STATE_CLOSED;
+ if (hasListener) {
+ _sendDone();
+ } else if (_isInitialState) {
+ _ensurePendingEvents().add(const _DelayedDone());
+ }
+ }
+
+ // EventSink interface. Used by the [addStream] events.
+
+ // Add data event, used both by the [addStream] events and by [add].
+ void _add(T value) {
+ if (hasListener) {
+ _sendData(value);
+ } else if (_isInitialState) {
+ _ensurePendingEvents().add(new _DelayedData<T>(value));
+ }
+ }
+
+ void _addError(Object error, StackTrace stackTrace) {
+ if (hasListener) {
+ _sendError(error, stackTrace);
+ } else if (_isInitialState) {
+ _ensurePendingEvents().add(new _DelayedError(error, stackTrace));
+ }
+ }
+
+ void _close() {
+ // End of addStream stream.
+ assert(_isAddingStream);
+ _StreamControllerAddStreamState<T> addState = _varData;
+ _varData = addState.varData;
+ _state &= ~_STATE_ADDSTREAM;
+ addState.complete();
+ }
+
+ // _StreamControllerLifeCycle interface
+
+ StreamSubscription<T> _subscribe(void onData(T data), Function onError,
+ void onDone(), bool cancelOnError) {
+ if (!_isInitialState) {
+ throw new StateError("Stream has already been listened to.");
+ }
+ _ControllerSubscription<T> subscription = new _ControllerSubscription<T>(
+ this, onData, onError, onDone, cancelOnError);
+
+ _PendingEvents<T> pendingEvents = _pendingEvents;
+ _state |= _STATE_SUBSCRIBED;
+ if (_isAddingStream) {
+ _StreamControllerAddStreamState<T> addState = _varData;
+ addState.varData = subscription;
+ addState.resume();
+ } else {
+ _varData = subscription;
+ }
+ subscription._setPendingEvents(pendingEvents);
+ subscription._guardCallback(() {
+ _runGuarded(onListen);
+ });
+
+ return subscription;
+ }
+
+ Future _recordCancel(StreamSubscription<T> subscription) {
+ // When we cancel, we first cancel any stream being added,
+ // Then we call `onCancel`, and finally the _doneFuture is completed.
+ // If either of addStream's cancel or `onCancel` returns a future,
+ // we wait for it before continuing.
+ // Any error during this process ends up in the returned future.
+ // If more errors happen, we act as if it happens inside nested try/finallys
+ // or whenComplete calls, and only the last error ends up in the
+ // returned future.
+ Future result;
+ if (_isAddingStream) {
+ _StreamControllerAddStreamState<T> addState = _varData;
+ result = addState.cancel();
+ }
+ _varData = null;
+ _state =
+ (_state & ~(_STATE_SUBSCRIBED | _STATE_ADDSTREAM)) | _STATE_CANCELED;
+
+ if (onCancel != null) {
+ if (result == null) {
+ // Only introduce a future if one is needed.
+ // If _onCancel returns null, no future is needed.
+ try {
+ result = onCancel();
+ } catch (e, s) {
+ // Return the error in the returned future.
+ // Complete it asynchronously, so there is time for a listener
+ // to handle the error.
+ result = new _Future().._asyncCompleteError(e, s);
+ }
+ } else {
+ // Simpler case when we already know that we will return a future.
+ result = result.whenComplete(onCancel);
+ }
+ }
+
+ void complete() {
+ if (_doneFuture != null && _doneFuture._mayComplete) {
+ _doneFuture._asyncComplete(null);
+ }
+ }
+
+ if (result != null) {
+ result = result.whenComplete(complete);
+ } else {
+ complete();
+ }
+
+ return result;
+ }
+
+ void _recordPause(StreamSubscription<T> subscription) {
+ if (_isAddingStream) {
+ _StreamControllerAddStreamState<T> addState = _varData;
+ addState.pause();
+ }
+ _runGuarded(onPause);
+ }
+
+ void _recordResume(StreamSubscription<T> subscription) {
+ if (_isAddingStream) {
+ _StreamControllerAddStreamState<T> addState = _varData;
+ addState.resume();
+ }
+ _runGuarded(onResume);
+ }
+}
+
+abstract class _SyncStreamControllerDispatch<T>
+ implements _StreamController<T>, SynchronousStreamController<T> {
+ int get _state;
+ void set _state(int state);
+
+ void _sendData(T data) {
+ _subscription._add(data);
+ }
+
+ void _sendError(Object error, StackTrace stackTrace) {
+ _subscription._addError(error, stackTrace);
+ }
+
+ void _sendDone() {
+ _subscription._close();
+ }
+}
+
+abstract class _AsyncStreamControllerDispatch<T>
+ implements _StreamController<T> {
+ void _sendData(T data) {
+ _subscription._addPending(new _DelayedData<T>(data));
+ }
+
+ void _sendError(Object error, StackTrace stackTrace) {
+ _subscription._addPending(new _DelayedError(error, stackTrace));
+ }
+
+ void _sendDone() {
+ _subscription._addPending(const _DelayedDone());
+ }
+}
+
+// TODO(lrn): Use common superclass for callback-controllers when VM supports
+// constructors in mixin superclasses.
+
+class _AsyncStreamController<T> = _StreamController<T>
+ with _AsyncStreamControllerDispatch<T>;
+
+class _SyncStreamController<T> = _StreamController<T>
+ with _SyncStreamControllerDispatch<T>;
+
+typedef _NotificationHandler();
+
+void _runGuarded(_NotificationHandler notificationHandler) {
+ if (notificationHandler == null) return;
+ try {
+ notificationHandler();
+ } catch (e, s) {
+ Zone.current.handleUncaughtError(e, s);
+ }
+}
+
+class _ControllerStream<T> extends _StreamImpl<T> {
+ _StreamControllerLifecycle<T> _controller;
+
+ _ControllerStream(this._controller);
+
+ StreamSubscription<T> _createSubscription(void onData(T data),
+ Function onError, void onDone(), bool cancelOnError) =>
+ _controller._subscribe(onData, onError, onDone, cancelOnError);
+
+ // Override == and hashCode so that new streams returned by the same
+ // controller are considered equal. The controller returns a new stream
+ // each time it's queried, but doesn't have to cache the result.
+
+ int get hashCode => _controller.hashCode ^ 0x35323532;
+
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+ return other is _ControllerStream &&
+ identical(other._controller, this._controller);
+ }
+}
+
+class _ControllerSubscription<T> extends _BufferingStreamSubscription<T> {
+ final _StreamControllerLifecycle<T> _controller;
+
+ _ControllerSubscription(this._controller, void onData(T data),
+ Function onError, void onDone(), bool cancelOnError)
+ : super(onData, onError, onDone, cancelOnError);
+
+ Future _onCancel() {
+ return _controller._recordCancel(this);
+ }
+
+ void _onPause() {
+ _controller._recordPause(this);
+ }
+
+ void _onResume() {
+ _controller._recordResume(this);
+ }
+}
+
+/** A class that exposes only the [StreamSink] interface of an object. */
+class _StreamSinkWrapper<T> implements StreamSink<T> {
+ final StreamController _target;
+ _StreamSinkWrapper(this._target);
+ void add(T data) {
+ _target.add(data);
+ }
+
+ void addError(Object error, [StackTrace stackTrace]) {
+ _target.addError(error, stackTrace);
+ }
+
+ Future close() => _target.close();
+
+ Future addStream(Stream<T> source) => _target.addStream(source);
+
+ Future get done => _target.done;
+}
+
+/**
+ * Object containing the state used to handle [StreamController.addStream].
+ */
+class _AddStreamState<T> {
+ // [_Future] returned by call to addStream.
+ final _Future addStreamFuture;
+
+ // Subscription on stream argument to addStream.
+ final StreamSubscription addSubscription;
+
+ _AddStreamState(
+ _EventSink<T> controller, Stream<T> source, bool cancelOnError)
+ : addStreamFuture = new _Future(),
+ addSubscription = source.listen(controller._add,
+ onError: cancelOnError
+ ? makeErrorHandler(controller)
+ : controller._addError,
+ onDone: controller._close,
+ cancelOnError: cancelOnError);
+
+ static makeErrorHandler(_EventSink controller) => (e, StackTrace s) {
+ controller._addError(e, s);
+ controller._close();
+ };
+
+ void pause() {
+ addSubscription.pause();
+ }
+
+ void resume() {
+ addSubscription.resume();
+ }
+
+ /**
+ * Stop adding the stream.
+ *
+ * Complete the future returned by `StreamController.addStream` when
+ * the cancel is complete.
+ *
+ * Return a future if the cancel takes time, otherwise return `null`.
+ */
+ Future cancel() {
+ var cancel = addSubscription.cancel();
+ if (cancel == null) {
+ addStreamFuture._asyncComplete(null);
+ return null;
+ }
+ return cancel.whenComplete(() {
+ addStreamFuture._asyncComplete(null);
+ });
+ }
+
+ void complete() {
+ addStreamFuture._asyncComplete(null);
+ }
+}
+
+class _StreamControllerAddStreamState<T> extends _AddStreamState<T> {
+ // The subscription or pending data of a _StreamController.
+ // Stored here because we reuse the `_varData` field in the _StreamController
+ // to store this state object.
+ var varData;
+
+ _StreamControllerAddStreamState(_StreamController<T> controller, this.varData,
+ Stream<T> source, bool cancelOnError)
+ : super(controller, source, cancelOnError) {
+ if (controller.isPaused) {
+ addSubscription.pause();
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/async/stream_impl.dart b/sdk_nnbd/lib/async/stream_impl.dart
new file mode 100644
index 0000000..14c84a5
--- /dev/null
+++ b/sdk_nnbd/lib/async/stream_impl.dart
@@ -0,0 +1,1062 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/** Abstract and private interface for a place to put events. */
+abstract class _EventSink<T> {
+ void _add(T data);
+ void _addError(Object error, StackTrace stackTrace);
+ void _close();
+}
+
+/**
+ * Abstract and private interface for a place to send events.
+ *
+ * Used by event buffering to finally dispatch the pending event, where
+ * [_EventSink] is where the event first enters the stream subscription,
+ * and may yet be buffered.
+ */
+abstract class _EventDispatch<T> {
+ void _sendData(T data);
+ void _sendError(Object error, StackTrace stackTrace);
+ void _sendDone();
+}
+
+/**
+ * Default implementation of stream subscription of buffering events.
+ *
+ * The only public methods are those of [StreamSubscription], so instances of
+ * [_BufferingStreamSubscription] can be returned directly as a
+ * [StreamSubscription] without exposing internal functionality.
+ *
+ * The [StreamController] is a public facing version of [Stream] and this class,
+ * with some methods made public.
+ *
+ * The user interface of [_BufferingStreamSubscription] are the following
+ * methods:
+ *
+ * * [_add]: Add a data event to the stream.
+ * * [_addError]: Add an error event to the stream.
+ * * [_close]: Request to close the stream.
+ * * [_onCancel]: Called when the subscription will provide no more events,
+ * either due to being actively canceled, or after sending a done event.
+ * * [_onPause]: Called when the subscription wants the event source to pause.
+ * * [_onResume]: Called when allowing new events after a pause.
+ *
+ * The user should not add new events when the subscription requests a paused,
+ * but if it happens anyway, the subscription will enqueue the events just as
+ * when new events arrive while still firing an old event.
+ */
+class _BufferingStreamSubscription<T>
+ implements StreamSubscription<T>, _EventSink<T>, _EventDispatch<T> {
+ /** The `cancelOnError` flag from the `listen` call. */
+ static const int _STATE_CANCEL_ON_ERROR = 1;
+ /**
+ * Whether the "done" event has been received.
+ * No further events are accepted after this.
+ */
+ static const int _STATE_CLOSED = 2;
+ /**
+ * Set if the input has been asked not to send events.
+ *
+ * This is not the same as being paused, since the input will remain paused
+ * after a call to [resume] if there are pending events.
+ */
+ static const int _STATE_INPUT_PAUSED = 4;
+ /**
+ * Whether the subscription has been canceled.
+ *
+ * Set by calling [cancel], or by handling a "done" event, or an "error" event
+ * when `cancelOnError` is true.
+ */
+ static const int _STATE_CANCELED = 8;
+ /**
+ * Set when either:
+ *
+ * * an error is sent, and [cancelOnError] is true, or
+ * * a done event is sent.
+ *
+ * If the subscription is canceled while _STATE_WAIT_FOR_CANCEL is set, the
+ * state is unset, and no further events must be delivered.
+ */
+ static const int _STATE_WAIT_FOR_CANCEL = 16;
+ static const int _STATE_IN_CALLBACK = 32;
+ static const int _STATE_HAS_PENDING = 64;
+ static const int _STATE_PAUSE_COUNT = 128;
+
+ /* Event handlers provided in constructor. */
+ _DataHandler<T> _onData;
+ Function _onError;
+ _DoneHandler _onDone;
+ final Zone _zone = Zone.current;
+
+ /** Bit vector based on state-constants above. */
+ int _state;
+
+ // TODO(floitsch): reuse another field
+ /** The future [_onCancel] may return. */
+ Future _cancelFuture;
+
+ /**
+ * Queue of pending events.
+ *
+ * Is created when necessary, or set in constructor for preconfigured events.
+ */
+ _PendingEvents<T> _pending;
+
+ _BufferingStreamSubscription(
+ void onData(T data), Function onError, void onDone(), bool cancelOnError)
+ : _state = (cancelOnError ? _STATE_CANCEL_ON_ERROR : 0) {
+ this.onData(onData);
+ this.onError(onError);
+ this.onDone(onDone);
+ }
+
+ /**
+ * Sets the subscription's pending events object.
+ *
+ * This can only be done once. The pending events object is used for the
+ * rest of the subscription's life cycle.
+ */
+ void _setPendingEvents(_PendingEvents<T> pendingEvents) {
+ assert(_pending == null);
+ if (pendingEvents == null) return;
+ _pending = pendingEvents;
+ if (!pendingEvents.isEmpty) {
+ _state |= _STATE_HAS_PENDING;
+ _pending.schedule(this);
+ }
+ }
+
+ // StreamSubscription interface.
+
+ void onData(void handleData(T event)) {
+ handleData ??= _nullDataHandler;
+ // TODO(floitsch): the return type should be 'void', and the type
+ // should be inferred.
+ _onData = _zone.registerUnaryCallback<dynamic, T>(handleData);
+ }
+
+ void onError(Function handleError) {
+ handleError ??= _nullErrorHandler;
+ if (handleError is void Function(Object, StackTrace)) {
+ _onError = _zone
+ .registerBinaryCallback<dynamic, Object, StackTrace>(handleError);
+ } else if (handleError is void Function(Object)) {
+ _onError = _zone.registerUnaryCallback<dynamic, Object>(handleError);
+ } else {
+ throw new ArgumentError("handleError callback must take either an Object "
+ "(the error), or both an Object (the error) and a StackTrace.");
+ }
+ }
+
+ void onDone(void handleDone()) {
+ handleDone ??= _nullDoneHandler;
+ _onDone = _zone.registerCallback(handleDone);
+ }
+
+ void pause([Future resumeSignal]) {
+ if (_isCanceled) return;
+ bool wasPaused = _isPaused;
+ bool wasInputPaused = _isInputPaused;
+ // Increment pause count and mark input paused (if it isn't already).
+ _state = (_state + _STATE_PAUSE_COUNT) | _STATE_INPUT_PAUSED;
+ if (resumeSignal != null) resumeSignal.whenComplete(resume);
+ if (!wasPaused && _pending != null) _pending.cancelSchedule();
+ if (!wasInputPaused && !_inCallback) _guardCallback(_onPause);
+ }
+
+ void resume() {
+ if (_isCanceled) return;
+ if (_isPaused) {
+ _decrementPauseCount();
+ if (!_isPaused) {
+ if (_hasPending && !_pending.isEmpty) {
+ // Input is still paused.
+ _pending.schedule(this);
+ } else {
+ assert(_mayResumeInput);
+ _state &= ~_STATE_INPUT_PAUSED;
+ if (!_inCallback) _guardCallback(_onResume);
+ }
+ }
+ }
+ }
+
+ Future cancel() {
+ // The user doesn't want to receive any further events. If there is an
+ // error or done event pending (waiting for the cancel to be done) discard
+ // that event.
+ _state &= ~_STATE_WAIT_FOR_CANCEL;
+ if (!_isCanceled) {
+ _cancel();
+ }
+ return _cancelFuture ?? Future._nullFuture;
+ }
+
+ Future<E> asFuture<E>([E futureValue]) {
+ _Future<E> result = new _Future<E>();
+
+ // Overwrite the onDone and onError handlers.
+ _onDone = () {
+ result._complete(futureValue);
+ };
+ _onError = (error, StackTrace stackTrace) {
+ Future cancelFuture = cancel();
+ if (!identical(cancelFuture, Future._nullFuture)) {
+ cancelFuture.whenComplete(() {
+ result._completeError(error, stackTrace);
+ });
+ } else {
+ result._completeError(error, stackTrace);
+ }
+ };
+
+ return result;
+ }
+
+ // State management.
+
+ bool get _isInputPaused => (_state & _STATE_INPUT_PAUSED) != 0;
+ bool get _isClosed => (_state & _STATE_CLOSED) != 0;
+ bool get _isCanceled => (_state & _STATE_CANCELED) != 0;
+ bool get _waitsForCancel => (_state & _STATE_WAIT_FOR_CANCEL) != 0;
+ bool get _inCallback => (_state & _STATE_IN_CALLBACK) != 0;
+ bool get _hasPending => (_state & _STATE_HAS_PENDING) != 0;
+ bool get _isPaused => _state >= _STATE_PAUSE_COUNT;
+ bool get _canFire => _state < _STATE_IN_CALLBACK;
+ bool get _mayResumeInput =>
+ !_isPaused && (_pending == null || _pending.isEmpty);
+ bool get _cancelOnError => (_state & _STATE_CANCEL_ON_ERROR) != 0;
+
+ bool get isPaused => _isPaused;
+
+ void _cancel() {
+ _state |= _STATE_CANCELED;
+ if (_hasPending) {
+ _pending.cancelSchedule();
+ }
+ if (!_inCallback) _pending = null;
+ _cancelFuture = _onCancel();
+ }
+
+ /**
+ * Decrements the pause count.
+ *
+ * Does not automatically unpause the input (call [_onResume]) when
+ * the pause count reaches zero. This is handled elsewhere, and only
+ * if there are no pending events buffered.
+ */
+ void _decrementPauseCount() {
+ assert(_isPaused);
+ _state -= _STATE_PAUSE_COUNT;
+ }
+
+ // _EventSink interface.
+
+ void _add(T data) {
+ assert(!_isClosed);
+ if (_isCanceled) return;
+ if (_canFire) {
+ _sendData(data);
+ } else {
+ _addPending(new _DelayedData<T>(data));
+ }
+ }
+
+ void _addError(Object error, StackTrace stackTrace) {
+ if (_isCanceled) return;
+ if (_canFire) {
+ _sendError(error, stackTrace); // Reports cancel after sending.
+ } else {
+ _addPending(new _DelayedError(error, stackTrace));
+ }
+ }
+
+ void _close() {
+ assert(!_isClosed);
+ if (_isCanceled) return;
+ _state |= _STATE_CLOSED;
+ if (_canFire) {
+ _sendDone();
+ } else {
+ _addPending(const _DelayedDone());
+ }
+ }
+
+ // Hooks called when the input is paused, unpaused or canceled.
+ // These must not throw. If overwritten to call user code, include suitable
+ // try/catch wrapping and send any errors to
+ // [_Zone.current.handleUncaughtError].
+ void _onPause() {
+ assert(_isInputPaused);
+ }
+
+ void _onResume() {
+ assert(!_isInputPaused);
+ }
+
+ Future _onCancel() {
+ assert(_isCanceled);
+ return null;
+ }
+
+ // Handle pending events.
+
+ /**
+ * Add a pending event.
+ *
+ * If the subscription is not paused, this also schedules a firing
+ * of pending events later (if necessary).
+ */
+ void _addPending(_DelayedEvent event) {
+ _StreamImplEvents<T> pending = _pending;
+ if (_pending == null) {
+ pending = _pending = new _StreamImplEvents<T>();
+ }
+ pending.add(event);
+ if (!_hasPending) {
+ _state |= _STATE_HAS_PENDING;
+ if (!_isPaused) {
+ _pending.schedule(this);
+ }
+ }
+ }
+
+ /* _EventDispatch interface. */
+
+ void _sendData(T data) {
+ assert(!_isCanceled);
+ assert(!_isPaused);
+ assert(!_inCallback);
+ bool wasInputPaused = _isInputPaused;
+ _state |= _STATE_IN_CALLBACK;
+ _zone.runUnaryGuarded(_onData, data);
+ _state &= ~_STATE_IN_CALLBACK;
+ _checkState(wasInputPaused);
+ }
+
+ void _sendError(Object error, StackTrace stackTrace) {
+ assert(!_isCanceled);
+ assert(!_isPaused);
+ assert(!_inCallback);
+ bool wasInputPaused = _isInputPaused;
+
+ void sendError() {
+ // If the subscription has been canceled while waiting for the cancel
+ // future to finish we must not report the error.
+ if (_isCanceled && !_waitsForCancel) return;
+ _state |= _STATE_IN_CALLBACK;
+ // TODO(floitsch): this dynamic should be 'void'.
+ var onError = _onError;
+ if (onError is void Function(Object, StackTrace)) {
+ _zone.runBinaryGuarded<Object, StackTrace>(onError, error, stackTrace);
+ } else {
+ assert(_onError is void Function(Object));
+ _zone.runUnaryGuarded<Object>(_onError, error);
+ }
+ _state &= ~_STATE_IN_CALLBACK;
+ }
+
+ if (_cancelOnError) {
+ _state |= _STATE_WAIT_FOR_CANCEL;
+ _cancel();
+ if (_cancelFuture != null &&
+ !identical(_cancelFuture, Future._nullFuture)) {
+ _cancelFuture.whenComplete(sendError);
+ } else {
+ sendError();
+ }
+ } else {
+ sendError();
+ // Only check state if not cancelOnError.
+ _checkState(wasInputPaused);
+ }
+ }
+
+ void _sendDone() {
+ assert(!_isCanceled);
+ assert(!_isPaused);
+ assert(!_inCallback);
+
+ void sendDone() {
+ // If the subscription has been canceled while waiting for the cancel
+ // future to finish we must not report the done event.
+ if (!_waitsForCancel) return;
+ _state |= (_STATE_CANCELED | _STATE_CLOSED | _STATE_IN_CALLBACK);
+ _zone.runGuarded(_onDone);
+ _state &= ~_STATE_IN_CALLBACK;
+ }
+
+ _cancel();
+ _state |= _STATE_WAIT_FOR_CANCEL;
+ if (_cancelFuture != null &&
+ !identical(_cancelFuture, Future._nullFuture)) {
+ _cancelFuture.whenComplete(sendDone);
+ } else {
+ sendDone();
+ }
+ }
+
+ /**
+ * Call a hook function.
+ *
+ * The call is properly wrapped in code to avoid other callbacks
+ * during the call, and it checks for state changes after the call
+ * that should cause further callbacks.
+ */
+ void _guardCallback(void callback()) {
+ assert(!_inCallback);
+ bool wasInputPaused = _isInputPaused;
+ _state |= _STATE_IN_CALLBACK;
+ callback();
+ _state &= ~_STATE_IN_CALLBACK;
+ _checkState(wasInputPaused);
+ }
+
+ /**
+ * Check if the input needs to be informed of state changes.
+ *
+ * State changes are pausing, resuming and canceling.
+ *
+ * After canceling, no further callbacks will happen.
+ *
+ * The cancel callback is called after a user cancel, or after
+ * the final done event is sent.
+ */
+ void _checkState(bool wasInputPaused) {
+ assert(!_inCallback);
+ if (_hasPending && _pending.isEmpty) {
+ _state &= ~_STATE_HAS_PENDING;
+ if (_isInputPaused && _mayResumeInput) {
+ _state &= ~_STATE_INPUT_PAUSED;
+ }
+ }
+ // If the state changes during a callback, we immediately
+ // make a new state-change callback. Loop until the state didn't change.
+ while (true) {
+ if (_isCanceled) {
+ _pending = null;
+ return;
+ }
+ bool isInputPaused = _isInputPaused;
+ if (wasInputPaused == isInputPaused) break;
+ _state ^= _STATE_IN_CALLBACK;
+ if (isInputPaused) {
+ _onPause();
+ } else {
+ _onResume();
+ }
+ _state &= ~_STATE_IN_CALLBACK;
+ wasInputPaused = isInputPaused;
+ }
+ if (_hasPending && !_isPaused) {
+ _pending.schedule(this);
+ }
+ }
+}
+
+// -------------------------------------------------------------------
+// Common base class for single and multi-subscription streams.
+// -------------------------------------------------------------------
+abstract class _StreamImpl<T> extends Stream<T> {
+ // ------------------------------------------------------------------
+ // Stream interface.
+
+ StreamSubscription<T> listen(void onData(T data),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ cancelOnError = identical(true, cancelOnError);
+ StreamSubscription<T> subscription =
+ _createSubscription(onData, onError, onDone, cancelOnError);
+ _onListen(subscription);
+ return subscription;
+ }
+
+ // -------------------------------------------------------------------
+ /** Create a subscription object. Called by [subcribe]. */
+ StreamSubscription<T> _createSubscription(void onData(T data),
+ Function onError, void onDone(), bool cancelOnError) {
+ return new _BufferingStreamSubscription<T>(
+ onData, onError, onDone, cancelOnError);
+ }
+
+ /** Hook called when the subscription has been created. */
+ void _onListen(StreamSubscription subscription) {}
+}
+
+typedef _PendingEvents<T> _EventGenerator<T>();
+
+/** Stream that generates its own events. */
+class _GeneratedStreamImpl<T> extends _StreamImpl<T> {
+ final _EventGenerator<T> _pending;
+ bool _isUsed = false;
+ /**
+ * Initializes the stream to have only the events provided by a
+ * [_PendingEvents].
+ *
+ * A new [_PendingEvents] must be generated for each listen.
+ */
+ _GeneratedStreamImpl(this._pending);
+
+ StreamSubscription<T> _createSubscription(void onData(T data),
+ Function onError, void onDone(), bool cancelOnError) {
+ if (_isUsed) throw new StateError("Stream has already been listened to.");
+ _isUsed = true;
+ return new _BufferingStreamSubscription<T>(
+ onData, onError, onDone, cancelOnError)
+ .._setPendingEvents(_pending());
+ }
+}
+
+/** Pending events object that gets its events from an [Iterable]. */
+class _IterablePendingEvents<T> extends _PendingEvents<T> {
+ // The iterator providing data for data events.
+ // Set to null when iteration has completed.
+ Iterator<T> _iterator;
+
+ _IterablePendingEvents(Iterable<T> data) : _iterator = data.iterator;
+
+ bool get isEmpty => _iterator == null;
+
+ void handleNext(_EventDispatch<T> dispatch) {
+ if (_iterator == null) {
+ throw new StateError("No events pending.");
+ }
+ // Send one event per call to moveNext.
+ // If moveNext returns true, send the current element as data.
+ // If current throws, send that error, but keep iterating.
+ // If moveNext returns false, send a done event and clear the _iterator.
+ // If moveNext throws an error, send an error and prepare to send a done
+ // event afterwards.
+ bool hasMore;
+ try {
+ hasMore = _iterator.moveNext();
+ if (hasMore) {
+ dispatch._sendData(_iterator.current);
+ } else {
+ _iterator = null;
+ dispatch._sendDone();
+ }
+ } catch (e, s) {
+ if (hasMore == null) {
+ // Threw in .moveNext().
+ // Ensure that we send a done afterwards.
+ _iterator = const EmptyIterator<Null>();
+ dispatch._sendError(e, s);
+ } else {
+ // Threw in .current.
+ dispatch._sendError(e, s);
+ }
+ }
+ }
+
+ void clear() {
+ if (isScheduled) cancelSchedule();
+ _iterator = null;
+ }
+}
+
+// Internal helpers.
+
+// Types of the different handlers on a stream. Types used to type fields.
+typedef void _DataHandler<T>(T value);
+typedef void _DoneHandler();
+
+/** Default data handler, does nothing. */
+void _nullDataHandler(Object value) {}
+
+/** Default error handler, reports the error to the current zone's handler. */
+void _nullErrorHandler(Object error, [StackTrace stackTrace]) {
+ Zone.current.handleUncaughtError(error, stackTrace);
+}
+
+/** Default done handler, does nothing. */
+void _nullDoneHandler() {}
+
+/** A delayed event on a buffering stream subscription. */
+abstract class _DelayedEvent<T> {
+ /** Added as a linked list on the [StreamController]. */
+ _DelayedEvent next;
+ /** Execute the delayed event on the [StreamController]. */
+ void perform(_EventDispatch<T> dispatch);
+}
+
+/** A delayed data event. */
+class _DelayedData<T> extends _DelayedEvent<T> {
+ final T value;
+ _DelayedData(this.value);
+ void perform(_EventDispatch<T> dispatch) {
+ dispatch._sendData(value);
+ }
+}
+
+/** A delayed error event. */
+class _DelayedError extends _DelayedEvent {
+ final error;
+ final StackTrace stackTrace;
+
+ _DelayedError(this.error, this.stackTrace);
+ void perform(_EventDispatch dispatch) {
+ dispatch._sendError(error, stackTrace);
+ }
+}
+
+/** A delayed done event. */
+class _DelayedDone implements _DelayedEvent {
+ const _DelayedDone();
+ void perform(_EventDispatch dispatch) {
+ dispatch._sendDone();
+ }
+
+ _DelayedEvent get next => null;
+
+ void set next(_DelayedEvent _) {
+ throw new StateError("No events after a done.");
+ }
+}
+
+/** Superclass for provider of pending events. */
+abstract class _PendingEvents<T> {
+ // No async event has been scheduled.
+ static const int _STATE_UNSCHEDULED = 0;
+ // An async event has been scheduled to run a function.
+ static const int _STATE_SCHEDULED = 1;
+ // An async event has been scheduled, but it will do nothing when it runs.
+ // Async events can't be preempted.
+ static const int _STATE_CANCELED = 3;
+
+ /**
+ * State of being scheduled.
+ *
+ * Set to [_STATE_SCHEDULED] when pending events are scheduled for
+ * async dispatch. Since we can't cancel a [scheduleMicrotask] call, if
+ * scheduling is "canceled", the _state is simply set to [_STATE_CANCELED]
+ * which will make the async code do nothing except resetting [_state].
+ *
+ * If events are scheduled while the state is [_STATE_CANCELED], it is
+ * merely switched back to [_STATE_SCHEDULED], but no new call to
+ * [scheduleMicrotask] is performed.
+ */
+ int _state = _STATE_UNSCHEDULED;
+
+ bool get isEmpty;
+
+ bool get isScheduled => _state == _STATE_SCHEDULED;
+ bool get _eventScheduled => _state >= _STATE_SCHEDULED;
+
+ /**
+ * Schedule an event to run later.
+ *
+ * If called more than once, it should be called with the same dispatch as
+ * argument each time. It may reuse an earlier argument in some cases.
+ */
+ void schedule(_EventDispatch<T> dispatch) {
+ if (isScheduled) return;
+ assert(!isEmpty);
+ if (_eventScheduled) {
+ assert(_state == _STATE_CANCELED);
+ _state = _STATE_SCHEDULED;
+ return;
+ }
+ scheduleMicrotask(() {
+ int oldState = _state;
+ _state = _STATE_UNSCHEDULED;
+ if (oldState == _STATE_CANCELED) return;
+ handleNext(dispatch);
+ });
+ _state = _STATE_SCHEDULED;
+ }
+
+ void cancelSchedule() {
+ if (isScheduled) _state = _STATE_CANCELED;
+ }
+
+ void handleNext(_EventDispatch<T> dispatch);
+
+ /** Throw away any pending events and cancel scheduled events. */
+ void clear();
+}
+
+/** Class holding pending events for a [_StreamImpl]. */
+class _StreamImplEvents<T> extends _PendingEvents<T> {
+ /// Single linked list of [_DelayedEvent] objects.
+ _DelayedEvent firstPendingEvent;
+
+ /// Last element in the list of pending events. New events are added after it.
+ _DelayedEvent lastPendingEvent;
+
+ bool get isEmpty => lastPendingEvent == null;
+
+ void add(_DelayedEvent event) {
+ if (lastPendingEvent == null) {
+ firstPendingEvent = lastPendingEvent = event;
+ } else {
+ lastPendingEvent = lastPendingEvent.next = event;
+ }
+ }
+
+ void handleNext(_EventDispatch<T> dispatch) {
+ assert(!isScheduled);
+ _DelayedEvent event = firstPendingEvent;
+ firstPendingEvent = event.next;
+ if (firstPendingEvent == null) {
+ lastPendingEvent = null;
+ }
+ event.perform(dispatch);
+ }
+
+ void clear() {
+ if (isScheduled) cancelSchedule();
+ firstPendingEvent = lastPendingEvent = null;
+ }
+}
+
+typedef void _BroadcastCallback<T>(StreamSubscription<T> subscription);
+
+/**
+ * Done subscription that will send one done event as soon as possible.
+ */
+class _DoneStreamSubscription<T> implements StreamSubscription<T> {
+ static const int _DONE_SENT = 1;
+ static const int _SCHEDULED = 2;
+ static const int _PAUSED = 4;
+
+ final Zone _zone;
+ int _state = 0;
+ _DoneHandler _onDone;
+
+ _DoneStreamSubscription(this._onDone) : _zone = Zone.current {
+ _schedule();
+ }
+
+ bool get _isSent => (_state & _DONE_SENT) != 0;
+ bool get _isScheduled => (_state & _SCHEDULED) != 0;
+ bool get isPaused => _state >= _PAUSED;
+
+ void _schedule() {
+ if (_isScheduled) return;
+ _zone.scheduleMicrotask(_sendDone);
+ _state |= _SCHEDULED;
+ }
+
+ void onData(void handleData(T data)) {}
+ void onError(Function handleError) {}
+ void onDone(void handleDone()) {
+ _onDone = handleDone;
+ }
+
+ void pause([Future resumeSignal]) {
+ _state += _PAUSED;
+ if (resumeSignal != null) resumeSignal.whenComplete(resume);
+ }
+
+ void resume() {
+ if (isPaused) {
+ _state -= _PAUSED;
+ if (!isPaused && !_isSent) {
+ _schedule();
+ }
+ }
+ }
+
+ Future cancel() => Future._nullFuture;
+
+ Future<E> asFuture<E>([E futureValue]) {
+ _Future<E> result = new _Future<E>();
+ _onDone = () {
+ result._completeWithValue(futureValue);
+ };
+ return result;
+ }
+
+ void _sendDone() {
+ _state &= ~_SCHEDULED;
+ if (isPaused) return;
+ _state |= _DONE_SENT;
+ if (_onDone != null) _zone.runGuarded(_onDone);
+ }
+}
+
+class _AsBroadcastStream<T> extends Stream<T> {
+ final Stream<T> _source;
+ final _BroadcastCallback<T> _onListenHandler;
+ final _BroadcastCallback<T> _onCancelHandler;
+ final Zone _zone;
+
+ _AsBroadcastStreamController<T> _controller;
+ StreamSubscription<T> _subscription;
+
+ _AsBroadcastStream(
+ this._source,
+ void onListenHandler(StreamSubscription<T> subscription),
+ void onCancelHandler(StreamSubscription<T> subscription))
+ // TODO(floitsch): the return type should be void and should be
+ // inferred.
+ : _onListenHandler = Zone.current
+ .registerUnaryCallback<dynamic, StreamSubscription<T>>(
+ onListenHandler),
+ _onCancelHandler = Zone.current
+ .registerUnaryCallback<dynamic, StreamSubscription<T>>(
+ onCancelHandler),
+ _zone = Zone.current {
+ _controller = new _AsBroadcastStreamController<T>(_onListen, _onCancel);
+ }
+
+ bool get isBroadcast => true;
+
+ StreamSubscription<T> listen(void onData(T data),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ if (_controller == null || _controller.isClosed) {
+ // Return a dummy subscription backed by nothing, since
+ // it will only ever send one done event.
+ return new _DoneStreamSubscription<T>(onDone);
+ }
+ _subscription ??= _source.listen(_controller.add,
+ onError: _controller.addError, onDone: _controller.close);
+ cancelOnError = identical(true, cancelOnError);
+ return _controller._subscribe(onData, onError, onDone, cancelOnError);
+ }
+
+ void _onCancel() {
+ bool shutdown = (_controller == null) || _controller.isClosed;
+ if (_onCancelHandler != null) {
+ _zone.runUnary(
+ _onCancelHandler, new _BroadcastSubscriptionWrapper<T>(this));
+ }
+ if (shutdown) {
+ if (_subscription != null) {
+ _subscription.cancel();
+ _subscription = null;
+ }
+ }
+ }
+
+ void _onListen() {
+ if (_onListenHandler != null) {
+ _zone.runUnary(
+ _onListenHandler, new _BroadcastSubscriptionWrapper<T>(this));
+ }
+ }
+
+ // Methods called from _BroadcastSubscriptionWrapper.
+ void _cancelSubscription() {
+ if (_subscription == null) return;
+ // Called by [_controller] when it has no subscribers left.
+ StreamSubscription subscription = _subscription;
+ _subscription = null;
+ _controller = null; // Marks the stream as no longer listenable.
+ subscription.cancel();
+ }
+
+ void _pauseSubscription(Future resumeSignal) {
+ if (_subscription == null) return;
+ _subscription.pause(resumeSignal);
+ }
+
+ void _resumeSubscription() {
+ if (_subscription == null) return;
+ _subscription.resume();
+ }
+
+ bool get _isSubscriptionPaused {
+ if (_subscription == null) return false;
+ return _subscription.isPaused;
+ }
+}
+
+/**
+ * Wrapper for subscription that disallows changing handlers.
+ */
+class _BroadcastSubscriptionWrapper<T> implements StreamSubscription<T> {
+ final _AsBroadcastStream _stream;
+
+ _BroadcastSubscriptionWrapper(this._stream);
+
+ void onData(void handleData(T data)) {
+ throw new UnsupportedError(
+ "Cannot change handlers of asBroadcastStream source subscription.");
+ }
+
+ void onError(Function handleError) {
+ throw new UnsupportedError(
+ "Cannot change handlers of asBroadcastStream source subscription.");
+ }
+
+ void onDone(void handleDone()) {
+ throw new UnsupportedError(
+ "Cannot change handlers of asBroadcastStream source subscription.");
+ }
+
+ void pause([Future resumeSignal]) {
+ _stream._pauseSubscription(resumeSignal);
+ }
+
+ void resume() {
+ _stream._resumeSubscription();
+ }
+
+ Future cancel() {
+ _stream._cancelSubscription();
+ return Future._nullFuture;
+ }
+
+ bool get isPaused {
+ return _stream._isSubscriptionPaused;
+ }
+
+ Future<E> asFuture<E>([E futureValue]) {
+ throw new UnsupportedError(
+ "Cannot change handlers of asBroadcastStream source subscription.");
+ }
+}
+
+/**
+ * Simple implementation of [StreamIterator].
+ *
+ * Pauses the stream between calls to [moveNext].
+ */
+class _StreamIterator<T> implements StreamIterator<T> {
+ // The stream iterator is always in one of four states.
+ // The value of the [_stateData] field depends on the state.
+ //
+ // When `_subscription == null` and `_stateData != null`:
+ // The stream iterator has been created, but [moveNext] has not been called
+ // yet. The [_stateData] field contains the stream to listen to on the first
+ // call to [moveNext] and [current] returns `null`.
+ //
+ // When `_subscription != null` and `!_isPaused`:
+ // The user has called [moveNext] and the iterator is waiting for the next
+ // event. The [_stateData] field contains the [_Future] returned by the
+ // [_moveNext] call and [current] returns `null.`
+ //
+ // When `_subscription != null` and `_isPaused`:
+ // The most recent call to [moveNext] has completed with a `true` value
+ // and [current] provides the value of the data event.
+ // The [_stateData] field contains the [current] value.
+ //
+ // When `_subscription == null` and `_stateData == null`:
+ // The stream has completed or been canceled using [cancel].
+ // The stream completes on either a done event or an error event.
+ // The last call to [moveNext] has completed with `false` and [current]
+ // returns `null`.
+
+ /// Subscription being listened to.
+ ///
+ /// Set to `null` when the stream subscription is done or canceled.
+ StreamSubscription _subscription;
+
+ /// Data value depending on the current state.
+ ///
+ /// Before first call to [moveNext]: The stream to listen to.
+ ///
+ /// After calling [moveNext] but before the returned future completes:
+ /// The returned future.
+ ///
+ /// After calling [moveNext] and the returned future has completed
+ /// with `true`: The value of [current].
+ ///
+ /// After calling [moveNext] and the returned future has completed
+ /// with `false`, or after calling [cancel]: `null`.
+ Object _stateData;
+
+ /// Whether the iterator is between calls to `moveNext`.
+ /// This will usually cause the [_subscription] to be paused, but as an
+ /// optimization, we only pause after the [moveNext] future has been
+ /// completed.
+ bool _isPaused = false;
+
+ _StreamIterator(final Stream<T> stream)
+ : _stateData = stream ?? (throw ArgumentError.notNull("stream"));
+
+ T get current {
+ if (_subscription != null && _isPaused) {
+ return _stateData;
+ }
+ return null;
+ }
+
+ Future<bool> moveNext() {
+ if (_subscription != null) {
+ if (_isPaused) {
+ var future = new _Future<bool>();
+ _stateData = future;
+ _isPaused = false;
+ _subscription.resume();
+ return future;
+ }
+ throw new StateError("Already waiting for next.");
+ }
+ return _initializeOrDone();
+ }
+
+ /// Called if there is no active subscription when [moveNext] is called.
+ ///
+ /// Either starts listening on the stream if this is the first call to
+ /// [moveNext], or returns a `false` future because the stream has already
+ /// ended.
+ Future<bool> _initializeOrDone() {
+ assert(_subscription == null);
+ var stateData = _stateData;
+ if (stateData != null) {
+ Stream<T> stream = stateData;
+ _subscription = stream.listen(_onData,
+ onError: _onError, onDone: _onDone, cancelOnError: true);
+ var future = new _Future<bool>();
+ _stateData = future;
+ return future;
+ }
+ return Future._falseFuture;
+ }
+
+ Future cancel() {
+ StreamSubscription<T> subscription = _subscription;
+ Object stateData = _stateData;
+ _stateData = null;
+ if (subscription != null) {
+ _subscription = null;
+ if (!_isPaused) {
+ _Future<bool> future = stateData;
+ future._asyncComplete(false);
+ }
+ return subscription.cancel();
+ }
+ return Future._nullFuture;
+ }
+
+ void _onData(T data) {
+ assert(_subscription != null && !_isPaused);
+ _Future<bool> moveNextFuture = _stateData;
+ _stateData = data;
+ _isPaused = true;
+ moveNextFuture._complete(true);
+ if (_subscription != null && _isPaused) _subscription.pause();
+ }
+
+ void _onError(Object error, [StackTrace stackTrace]) {
+ assert(_subscription != null && !_isPaused);
+ _Future<bool> moveNextFuture = _stateData;
+ _subscription = null;
+ _stateData = null;
+ moveNextFuture._completeError(error, stackTrace);
+ }
+
+ void _onDone() {
+ assert(_subscription != null && !_isPaused);
+ _Future<bool> moveNextFuture = _stateData;
+ _subscription = null;
+ _stateData = null;
+ moveNextFuture._complete(false);
+ }
+}
+
+/** An empty broadcast stream, sending a done event as soon as possible. */
+class _EmptyStream<T> extends Stream<T> {
+ const _EmptyStream() : super._internal();
+ bool get isBroadcast => true;
+ StreamSubscription<T> listen(void onData(T data),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ return new _DoneStreamSubscription<T>(onDone);
+ }
+}
diff --git a/sdk_nnbd/lib/async/stream_pipe.dart b/sdk_nnbd/lib/async/stream_pipe.dart
new file mode 100644
index 0000000..e526179
--- /dev/null
+++ b/sdk_nnbd/lib/async/stream_pipe.dart
@@ -0,0 +1,500 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/** Runs user code and takes actions depending on success or failure. */
+_runUserCode<T>(
+ T userCode(), onSuccess(T value), onError(error, StackTrace stackTrace)) {
+ try {
+ onSuccess(userCode());
+ } catch (e, s) {
+ AsyncError replacement = Zone.current.errorCallback(e, s);
+ if (replacement == null) {
+ onError(e, s);
+ } else {
+ var error = _nonNullError(replacement.error);
+ var stackTrace = replacement.stackTrace;
+ onError(error, stackTrace);
+ }
+ }
+}
+
+/** Helper function to cancel a subscription and wait for the potential future,
+ before completing with an error. */
+void _cancelAndError(StreamSubscription subscription, _Future future, error,
+ StackTrace stackTrace) {
+ var cancelFuture = subscription.cancel();
+ if (cancelFuture != null && !identical(cancelFuture, Future._nullFuture)) {
+ cancelFuture.whenComplete(() => future._completeError(error, stackTrace));
+ } else {
+ future._completeError(error, stackTrace);
+ }
+}
+
+void _cancelAndErrorWithReplacement(StreamSubscription subscription,
+ _Future future, error, StackTrace stackTrace) {
+ AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+ if (replacement != null) {
+ error = _nonNullError(replacement.error);
+ stackTrace = replacement.stackTrace;
+ }
+ _cancelAndError(subscription, future, error, stackTrace);
+}
+
+typedef void _ErrorCallback(error, StackTrace stackTrace);
+
+/** Helper function to make an onError argument to [_runUserCode]. */
+_ErrorCallback _cancelAndErrorClosure(
+ StreamSubscription subscription, _Future future) {
+ return (error, StackTrace stackTrace) {
+ _cancelAndError(subscription, future, error, stackTrace);
+ };
+}
+
+/** Helper function to cancel a subscription and wait for the potential future,
+ before completing with a value. */
+void _cancelAndValue(StreamSubscription subscription, _Future future, value) {
+ var cancelFuture = subscription.cancel();
+ if (cancelFuture != null && !identical(cancelFuture, Future._nullFuture)) {
+ cancelFuture.whenComplete(() => future._complete(value));
+ } else {
+ future._complete(value);
+ }
+}
+
+/**
+ * A [Stream] that forwards subscriptions to another stream.
+ *
+ * This stream implements [Stream], but forwards all subscriptions
+ * to an underlying stream, and wraps the returned subscription to
+ * modify the events on the way.
+ *
+ * This class is intended for internal use only.
+ */
+abstract class _ForwardingStream<S, T> extends Stream<T> {
+ final Stream<S> _source;
+
+ _ForwardingStream(this._source);
+
+ bool get isBroadcast => _source.isBroadcast;
+
+ StreamSubscription<T> listen(void onData(T value),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ cancelOnError = identical(true, cancelOnError);
+ return _createSubscription(onData, onError, onDone, cancelOnError);
+ }
+
+ StreamSubscription<T> _createSubscription(void onData(T data),
+ Function onError, void onDone(), bool cancelOnError) {
+ return new _ForwardingStreamSubscription<S, T>(
+ this, onData, onError, onDone, cancelOnError);
+ }
+
+ // Override the following methods in subclasses to change the behavior.
+
+ void _handleData(S data, _EventSink<T> sink) {
+ sink._add(data as Object);
+ }
+
+ void _handleError(error, StackTrace stackTrace, _EventSink<T> sink) {
+ sink._addError(error, stackTrace);
+ }
+
+ void _handleDone(_EventSink<T> sink) {
+ sink._close();
+ }
+}
+
+/**
+ * Abstract superclass for subscriptions that forward to other subscriptions.
+ */
+class _ForwardingStreamSubscription<S, T>
+ extends _BufferingStreamSubscription<T> {
+ final _ForwardingStream<S, T> _stream;
+
+ StreamSubscription<S> _subscription;
+
+ _ForwardingStreamSubscription(this._stream, void onData(T data),
+ Function onError, void onDone(), bool cancelOnError)
+ : super(onData, onError, onDone, cancelOnError) {
+ _subscription = _stream._source
+ .listen(_handleData, onError: _handleError, onDone: _handleDone);
+ }
+
+ // _StreamSink interface.
+ // Transformers sending more than one event have no way to know if the stream
+ // is canceled or closed after the first, so we just ignore remaining events.
+
+ void _add(T data) {
+ if (_isClosed) return;
+ super._add(data);
+ }
+
+ void _addError(Object error, StackTrace stackTrace) {
+ if (_isClosed) return;
+ super._addError(error, stackTrace);
+ }
+
+ // StreamSubscription callbacks.
+
+ void _onPause() {
+ if (_subscription == null) return;
+ _subscription.pause();
+ }
+
+ void _onResume() {
+ if (_subscription == null) return;
+ _subscription.resume();
+ }
+
+ Future _onCancel() {
+ if (_subscription != null) {
+ StreamSubscription subscription = _subscription;
+ _subscription = null;
+ return subscription.cancel();
+ }
+ return null;
+ }
+
+ // Methods used as listener on source subscription.
+
+ void _handleData(S data) {
+ _stream._handleData(data, this);
+ }
+
+ void _handleError(error, StackTrace stackTrace) {
+ _stream._handleError(error, stackTrace, this);
+ }
+
+ void _handleDone() {
+ _stream._handleDone(this);
+ }
+}
+
+// -------------------------------------------------------------------
+// Stream transformers used by the default Stream implementation.
+// -------------------------------------------------------------------
+
+typedef bool _Predicate<T>(T value);
+
+void _addErrorWithReplacement(_EventSink sink, error, StackTrace stackTrace) {
+ AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
+ if (replacement != null) {
+ error = _nonNullError(replacement.error);
+ stackTrace = replacement.stackTrace;
+ }
+ sink._addError(error, stackTrace);
+}
+
+class _WhereStream<T> extends _ForwardingStream<T, T> {
+ final _Predicate<T> _test;
+
+ _WhereStream(Stream<T> source, bool test(T value))
+ : _test = test,
+ super(source);
+
+ void _handleData(T inputEvent, _EventSink<T> sink) {
+ bool satisfies;
+ try {
+ satisfies = _test(inputEvent);
+ } catch (e, s) {
+ _addErrorWithReplacement(sink, e, s);
+ return;
+ }
+ if (satisfies) {
+ sink._add(inputEvent);
+ }
+ }
+}
+
+typedef T _Transformation<S, T>(S value);
+
+/**
+ * A stream pipe that converts data events before passing them on.
+ */
+class _MapStream<S, T> extends _ForwardingStream<S, T> {
+ final _Transformation<S, T> _transform;
+
+ _MapStream(Stream<S> source, T transform(S event))
+ : this._transform = transform,
+ super(source);
+
+ void _handleData(S inputEvent, _EventSink<T> sink) {
+ T outputEvent;
+ try {
+ outputEvent = _transform(inputEvent);
+ } catch (e, s) {
+ _addErrorWithReplacement(sink, e, s);
+ return;
+ }
+ sink._add(outputEvent);
+ }
+}
+
+/**
+ * A stream pipe that converts data events before passing them on.
+ */
+class _ExpandStream<S, T> extends _ForwardingStream<S, T> {
+ final _Transformation<S, Iterable<T>> _expand;
+
+ _ExpandStream(Stream<S> source, Iterable<T> expand(S event))
+ : this._expand = expand,
+ super(source);
+
+ void _handleData(S inputEvent, _EventSink<T> sink) {
+ try {
+ for (T value in _expand(inputEvent)) {
+ sink._add(value);
+ }
+ } catch (e, s) {
+ // If either _expand or iterating the generated iterator throws,
+ // we abort the iteration.
+ _addErrorWithReplacement(sink, e, s);
+ }
+ }
+}
+
+typedef bool _ErrorTest(error);
+
+/**
+ * A stream pipe that converts or disposes error events
+ * before passing them on.
+ */
+class _HandleErrorStream<T> extends _ForwardingStream<T, T> {
+ final Function _transform;
+ final _ErrorTest _test;
+
+ _HandleErrorStream(Stream<T> source, Function onError, bool test(error))
+ : this._transform = onError,
+ this._test = test,
+ super(source);
+
+ void _handleError(Object error, StackTrace stackTrace, _EventSink<T> sink) {
+ bool matches = true;
+ if (_test != null) {
+ try {
+ matches = _test(error);
+ } catch (e, s) {
+ _addErrorWithReplacement(sink, e, s);
+ return;
+ }
+ }
+ if (matches) {
+ try {
+ _invokeErrorHandler(_transform, error, stackTrace);
+ } catch (e, s) {
+ if (identical(e, error)) {
+ sink._addError(error, stackTrace);
+ } else {
+ _addErrorWithReplacement(sink, e, s);
+ }
+ return;
+ }
+ } else {
+ sink._addError(error, stackTrace);
+ }
+ }
+}
+
+class _TakeStream<T> extends _ForwardingStream<T, T> {
+ final int _count;
+
+ _TakeStream(Stream<T> source, int count)
+ : this._count = count,
+ super(source) {
+ // This test is done early to avoid handling an async error
+ // in the _handleData method.
+ ArgumentError.checkNotNull(count, "count");
+ }
+
+ StreamSubscription<T> _createSubscription(void onData(T data),
+ Function onError, void onDone(), bool cancelOnError) {
+ if (_count == 0) {
+ _source.listen(null).cancel();
+ return new _DoneStreamSubscription<T>(onDone);
+ }
+ return new _StateStreamSubscription<T>(
+ this, onData, onError, onDone, cancelOnError, _count);
+ }
+
+ void _handleData(T inputEvent, _EventSink<T> sink) {
+ _StateStreamSubscription<T> subscription = sink;
+ int count = subscription._count;
+ if (count > 0) {
+ sink._add(inputEvent);
+ count -= 1;
+ subscription._count = count;
+ if (count == 0) {
+ // Closing also unsubscribes all subscribers, which unsubscribes
+ // this from source.
+ sink._close();
+ }
+ }
+ }
+}
+
+/**
+ * A [_ForwardingStreamSubscription] with one extra state field.
+ *
+ * Use by several different classes, storing an integer, bool or general.
+ */
+class _StateStreamSubscription<T> extends _ForwardingStreamSubscription<T, T> {
+ // Raw state field. Typed access provided by getters and setters below.
+ var _sharedState;
+
+ _StateStreamSubscription(_ForwardingStream<T, T> stream, void onData(T data),
+ Function onError, void onDone(), bool cancelOnError, this._sharedState)
+ : super(stream, onData, onError, onDone, cancelOnError);
+
+ bool get _flag => _sharedState;
+ void set _flag(bool flag) {
+ _sharedState = flag;
+ }
+
+ int get _count => _sharedState;
+ void set _count(int count) {
+ _sharedState = count;
+ }
+
+ Object get _value => _sharedState;
+ void set _value(Object value) {
+ _sharedState = value;
+ }
+}
+
+class _TakeWhileStream<T> extends _ForwardingStream<T, T> {
+ final _Predicate<T> _test;
+
+ _TakeWhileStream(Stream<T> source, bool test(T value))
+ : this._test = test,
+ super(source);
+
+ void _handleData(T inputEvent, _EventSink<T> sink) {
+ bool satisfies;
+ try {
+ satisfies = _test(inputEvent);
+ } catch (e, s) {
+ _addErrorWithReplacement(sink, e, s);
+ // The test didn't say true. Didn't say false either, but we stop anyway.
+ sink._close();
+ return;
+ }
+ if (satisfies) {
+ sink._add(inputEvent);
+ } else {
+ sink._close();
+ }
+ }
+}
+
+class _SkipStream<T> extends _ForwardingStream<T, T> {
+ final int _count;
+
+ _SkipStream(Stream<T> source, int count)
+ : this._count = count,
+ super(source) {
+ // This test is done early to avoid handling an async error
+ // in the _handleData method.
+ ArgumentError.checkNotNull(count, "count");
+ RangeError.checkNotNegative(count, "count");
+ }
+
+ StreamSubscription<T> _createSubscription(void onData(T data),
+ Function onError, void onDone(), bool cancelOnError) {
+ return new _StateStreamSubscription<T>(
+ this, onData, onError, onDone, cancelOnError, _count);
+ }
+
+ void _handleData(T inputEvent, _EventSink<T> sink) {
+ _StateStreamSubscription<T> subscription = sink;
+ int count = subscription._count;
+ if (count > 0) {
+ subscription._count = count - 1;
+ return;
+ }
+ sink._add(inputEvent);
+ }
+}
+
+class _SkipWhileStream<T> extends _ForwardingStream<T, T> {
+ final _Predicate<T> _test;
+
+ _SkipWhileStream(Stream<T> source, bool test(T value))
+ : this._test = test,
+ super(source);
+
+ StreamSubscription<T> _createSubscription(void onData(T data),
+ Function onError, void onDone(), bool cancelOnError) {
+ return new _StateStreamSubscription<T>(
+ this, onData, onError, onDone, cancelOnError, false);
+ }
+
+ void _handleData(T inputEvent, _EventSink<T> sink) {
+ _StateStreamSubscription<T> subscription = sink;
+ bool hasFailed = subscription._flag;
+ if (hasFailed) {
+ sink._add(inputEvent);
+ return;
+ }
+ bool satisfies;
+ try {
+ satisfies = _test(inputEvent);
+ } catch (e, s) {
+ _addErrorWithReplacement(sink, e, s);
+ // A failure to return a boolean is considered "not matching".
+ subscription._flag = true;
+ return;
+ }
+ if (!satisfies) {
+ subscription._flag = true;
+ sink._add(inputEvent);
+ }
+ }
+}
+
+typedef bool _Equality<T>(T a, T b);
+
+class _DistinctStream<T> extends _ForwardingStream<T, T> {
+ static final _SENTINEL = new Object();
+
+ final _Equality<T> _equals;
+
+ _DistinctStream(Stream<T> source, bool equals(T a, T b))
+ : _equals = equals,
+ super(source);
+
+ StreamSubscription<T> _createSubscription(void onData(T data),
+ Function onError, void onDone(), bool cancelOnError) {
+ return new _StateStreamSubscription<T>(
+ this, onData, onError, onDone, cancelOnError, _SENTINEL);
+ }
+
+ void _handleData(T inputEvent, _EventSink<T> sink) {
+ _StateStreamSubscription<T> subscription = sink;
+ var previous = subscription._value;
+ if (identical(previous, _SENTINEL)) {
+ // First event.
+ subscription._value = inputEvent;
+ sink._add(inputEvent);
+ } else {
+ T previousEvent = previous;
+ bool isEqual;
+ try {
+ if (_equals == null) {
+ isEqual = (previousEvent == inputEvent);
+ } else {
+ isEqual = _equals(previousEvent, inputEvent);
+ }
+ } catch (e, s) {
+ _addErrorWithReplacement(sink, e, s);
+ return;
+ }
+ if (!isEqual) {
+ sink._add(inputEvent);
+ subscription._value = inputEvent;
+ }
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/async/stream_transformers.dart b/sdk_nnbd/lib/async/stream_transformers.dart
new file mode 100644
index 0000000..9ec13bd
--- /dev/null
+++ b/sdk_nnbd/lib/async/stream_transformers.dart
@@ -0,0 +1,336 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/**
+ * Wraps an [_EventSink] so it exposes only the [EventSink] interface.
+ */
+class _EventSinkWrapper<T> implements EventSink<T> {
+ _EventSink _sink;
+ _EventSinkWrapper(this._sink);
+
+ void add(T data) {
+ _sink._add(data);
+ }
+
+ void addError(error, [StackTrace stackTrace]) {
+ _sink._addError(error, stackTrace);
+ }
+
+ void close() {
+ _sink._close();
+ }
+}
+
+/**
+ * A StreamSubscription that pipes data through a sink.
+ *
+ * The constructor of this class takes a [_SinkMapper] which maps from
+ * [EventSink] to [EventSink]. The input to the mapper is the output of
+ * the transformation. The returned sink is the transformation's input.
+ */
+class _SinkTransformerStreamSubscription<S, T>
+ extends _BufferingStreamSubscription<T> {
+ /// The transformer's input sink.
+ EventSink<S> _transformerSink;
+
+ /// The subscription to the input stream.
+ StreamSubscription<S> _subscription;
+
+ _SinkTransformerStreamSubscription(Stream<S> source, _SinkMapper<S, T> mapper,
+ void onData(T data), Function onError, void onDone(), bool cancelOnError)
+ // We set the adapter's target only when the user is allowed to send data.
+ : super(onData, onError, onDone, cancelOnError) {
+ _EventSinkWrapper<T> eventSink = new _EventSinkWrapper<T>(this);
+ _transformerSink = mapper(eventSink);
+ _subscription =
+ source.listen(_handleData, onError: _handleError, onDone: _handleDone);
+ }
+
+ /** Whether this subscription is still subscribed to its source. */
+ bool get _isSubscribed => _subscription != null;
+
+ // _EventSink interface.
+
+ /**
+ * Adds an event to this subscriptions.
+ *
+ * Contrary to normal [_BufferingStreamSubscription]s we may receive
+ * events when the stream is already closed. Report them as state
+ * error.
+ */
+ void _add(T data) {
+ if (_isClosed) {
+ throw new StateError("Stream is already closed");
+ }
+ super._add(data);
+ }
+
+ /**
+ * Adds an error event to this subscriptions.
+ *
+ * Contrary to normal [_BufferingStreamSubscription]s we may receive
+ * events when the stream is already closed. Report them as state
+ * error.
+ */
+ void _addError(Object error, StackTrace stackTrace) {
+ if (_isClosed) {
+ throw new StateError("Stream is already closed");
+ }
+ super._addError(error, stackTrace);
+ }
+
+ /**
+ * Adds a close event to this subscriptions.
+ *
+ * Contrary to normal [_BufferingStreamSubscription]s we may receive
+ * events when the stream is already closed. Report them as state
+ * error.
+ */
+ void _close() {
+ if (_isClosed) {
+ throw new StateError("Stream is already closed");
+ }
+ super._close();
+ }
+
+ // _BufferingStreamSubscription hooks.
+
+ void _onPause() {
+ if (_isSubscribed) _subscription.pause();
+ }
+
+ void _onResume() {
+ if (_isSubscribed) _subscription.resume();
+ }
+
+ Future _onCancel() {
+ if (_isSubscribed) {
+ StreamSubscription subscription = _subscription;
+ _subscription = null;
+ return subscription.cancel();
+ }
+ return null;
+ }
+
+ void _handleData(S data) {
+ try {
+ _transformerSink.add(data);
+ } catch (e, s) {
+ _addError(e, s);
+ }
+ }
+
+ void _handleError(error, [StackTrace stackTrace]) {
+ try {
+ _transformerSink.addError(error, stackTrace);
+ } catch (e, s) {
+ if (identical(e, error)) {
+ _addError(error, stackTrace);
+ } else {
+ _addError(e, s);
+ }
+ }
+ }
+
+ void _handleDone() {
+ try {
+ _subscription = null;
+ _transformerSink.close();
+ } catch (e, s) {
+ _addError(e, s);
+ }
+ }
+}
+
+typedef EventSink<S> _SinkMapper<S, T>(EventSink<T> output);
+
+/**
+ * A StreamTransformer for Sink-mappers.
+ *
+ * A Sink-mapper takes an [EventSink] (its output) and returns another
+ * EventSink (its input).
+ *
+ * Note that this class can be `const`.
+ */
+class _StreamSinkTransformer<S, T> extends StreamTransformerBase<S, T> {
+ final _SinkMapper<S, T> _sinkMapper;
+ const _StreamSinkTransformer(this._sinkMapper);
+
+ Stream<T> bind(Stream<S> stream) =>
+ new _BoundSinkStream<S, T>(stream, _sinkMapper);
+}
+
+/**
+ * The result of binding a StreamTransformer for Sink-mappers.
+ *
+ * It contains the bound Stream and the sink-mapper. Only when the user starts
+ * listening to this stream is the sink-mapper invoked. The result is used
+ * to create a StreamSubscription that transforms events.
+ */
+class _BoundSinkStream<S, T> extends Stream<T> {
+ final _SinkMapper<S, T> _sinkMapper;
+ final Stream<S> _stream;
+
+ bool get isBroadcast => _stream.isBroadcast;
+
+ _BoundSinkStream(this._stream, this._sinkMapper);
+
+ StreamSubscription<T> listen(void onData(T event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ cancelOnError = identical(true, cancelOnError);
+ StreamSubscription<T> subscription =
+ new _SinkTransformerStreamSubscription<S, T>(
+ _stream, _sinkMapper, onData, onError, onDone, cancelOnError);
+ return subscription;
+ }
+}
+
+/// Data-handler coming from [StreamTransformer.fromHandlers].
+typedef void _TransformDataHandler<S, T>(S data, EventSink<T> sink);
+
+/// Error-handler coming from [StreamTransformer.fromHandlers].
+typedef void _TransformErrorHandler<T>(
+ Object error, StackTrace stackTrace, EventSink<T> sink);
+
+/// Done-handler coming from [StreamTransformer.fromHandlers].
+typedef void _TransformDoneHandler<T>(EventSink<T> sink);
+
+/**
+ * Wraps handlers (from [StreamTransformer.fromHandlers]) into an `EventSink`.
+ *
+ * This way we can reuse the code from [_StreamSinkTransformer].
+ */
+class _HandlerEventSink<S, T> implements EventSink<S> {
+ final _TransformDataHandler<S, T> _handleData;
+ final _TransformErrorHandler<T> _handleError;
+ final _TransformDoneHandler<T> _handleDone;
+
+ /// The output sink where the handlers should send their data into.
+ EventSink<T> _sink;
+
+ _HandlerEventSink(
+ this._handleData, this._handleError, this._handleDone, this._sink) {
+ if (_sink == null) {
+ throw new ArgumentError("The provided sink must not be null.");
+ }
+ }
+
+ bool get _isClosed => _sink == null;
+
+ void add(S data) {
+ if (_isClosed) {
+ throw StateError("Sink is closed");
+ }
+ if (_handleData != null) {
+ _handleData(data, _sink);
+ } else {
+ _sink.add(data as T);
+ }
+ }
+
+ void addError(Object error, [StackTrace stackTrace]) {
+ if (_isClosed) {
+ throw StateError("Sink is closed");
+ }
+ if (_handleError != null) {
+ _handleError(error, stackTrace, _sink);
+ } else {
+ _sink.addError(error, stackTrace);
+ }
+ }
+
+ void close() {
+ if (_isClosed) return;
+ var sink = _sink;
+ _sink = null;
+ if (_handleDone != null) {
+ _handleDone(sink);
+ } else {
+ sink.close();
+ }
+ }
+}
+
+/**
+ * A StreamTransformer that transformers events with the given handlers.
+ *
+ * Note that this transformer can only be used once.
+ */
+class _StreamHandlerTransformer<S, T> extends _StreamSinkTransformer<S, T> {
+ _StreamHandlerTransformer(
+ {void handleData(S data, EventSink<T> sink),
+ void handleError(Object error, StackTrace stackTrace, EventSink<T> sink),
+ void handleDone(EventSink<T> sink)})
+ : super((EventSink<T> outputSink) {
+ return new _HandlerEventSink<S, T>(
+ handleData, handleError, handleDone, outputSink);
+ });
+
+ Stream<T> bind(Stream<S> stream) {
+ return super.bind(stream);
+ }
+}
+
+/**
+ * A StreamTransformer that overrides [StreamTransformer.bind] with a callback.
+ */
+class _StreamBindTransformer<S, T> extends StreamTransformerBase<S, T> {
+ final Stream<T> Function(Stream<S>) _bind;
+ _StreamBindTransformer(this._bind);
+
+ Stream<T> bind(Stream<S> stream) => _bind(stream);
+}
+
+/// A closure mapping a stream and cancelOnError to a StreamSubscription.
+typedef StreamSubscription<T> _SubscriptionTransformer<S, T>(
+ Stream<S> stream, bool cancelOnError);
+
+/**
+ * A [StreamTransformer] that minimizes the number of additional classes.
+ *
+ * Instead of implementing three classes: a [StreamTransformer], a [Stream]
+ * (as the result of a `bind` call) and a [StreamSubscription] (which does the
+ * actual work), this class only requires a function that is invoked when the
+ * last bit (the subscription) of the transformer-workflow is needed.
+ *
+ * The given transformer function maps from Stream and cancelOnError to a
+ * `StreamSubscription`. As such it can also act on `cancel` events, making it
+ * fully general.
+ */
+class _StreamSubscriptionTransformer<S, T> extends StreamTransformerBase<S, T> {
+ final _SubscriptionTransformer<S, T> _onListen;
+
+ const _StreamSubscriptionTransformer(this._onListen);
+
+ Stream<T> bind(Stream<S> stream) =>
+ new _BoundSubscriptionStream<S, T>(stream, _onListen);
+}
+
+/**
+ * A stream transformed by a [_StreamSubscriptionTransformer].
+ *
+ * When this stream is listened to it invokes the [_onListen] function with
+ * the stored [_stream]. Usually the transformer starts listening at this
+ * moment.
+ */
+class _BoundSubscriptionStream<S, T> extends Stream<T> {
+ final _SubscriptionTransformer<S, T> _onListen;
+ final Stream<S> _stream;
+
+ bool get isBroadcast => _stream.isBroadcast;
+
+ _BoundSubscriptionStream(this._stream, this._onListen);
+
+ StreamSubscription<T> listen(void onData(T event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ cancelOnError = identical(true, cancelOnError);
+ StreamSubscription<T> result = _onListen(_stream, cancelOnError);
+ result.onData(onData);
+ result.onError(onError);
+ result.onDone(onDone);
+ return result;
+ }
+}
diff --git a/sdk_nnbd/lib/async/timer.dart b/sdk_nnbd/lib/async/timer.dart
new file mode 100644
index 0000000..aa2f088
--- /dev/null
+++ b/sdk_nnbd/lib/async/timer.dart
@@ -0,0 +1,127 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/**
+ * A count-down timer that can be configured to fire once or repeatedly.
+ *
+ * The timer counts down from the specified duration to 0.
+ * When the timer reaches 0, the timer invokes the specified callback function.
+ * Use a periodic timer to repeatedly count down the same interval.
+ *
+ * A negative duration is treated the same as a duration of 0.
+ * If the duration is statically known to be 0, consider using [run].
+ *
+ * Frequently the duration is either a constant or computed as in the
+ * following example (taking advantage of the multiplication operator of
+ * the [Duration] class):
+ * ```dart
+ * const timeout = const Duration(seconds: 3);
+ * const ms = const Duration(milliseconds: 1);
+ *
+ * startTimeout([int milliseconds]) {
+ * var duration = milliseconds == null ? timeout : ms * milliseconds;
+ * return new Timer(duration, handleTimeout);
+ * }
+ * ...
+ * void handleTimeout() { // callback function
+ * ...
+ * }
+ * ```
+ * Note: If Dart code using Timer is compiled to JavaScript, the finest
+ * granularity available in the browser is 4 milliseconds.
+ *
+ * See [Stopwatch] for measuring elapsed time.
+ */
+abstract class Timer {
+ /**
+ * Creates a new timer.
+ *
+ * The [callback] function is invoked after the given [duration].
+ *
+ */
+ factory Timer(Duration duration, void callback()) {
+ if (Zone.current == Zone.root) {
+ // No need to bind the callback. We know that the root's timer will
+ // be invoked in the root zone.
+ return Zone.current.createTimer(duration, callback);
+ }
+ return Zone.current
+ .createTimer(duration, Zone.current.bindCallbackGuarded(callback));
+ }
+
+ /**
+ * Creates a new repeating timer.
+ *
+ * The [callback] is invoked repeatedly with [duration] intervals until
+ * canceled with the [cancel] function.
+ *
+ * The exact timing depends on the underlying timer implementation.
+ * No more than `n` callbacks will be made in `duration * n` time,
+ * but the time between two consecutive callbacks
+ * can be shorter and longer than `duration`.
+ *
+ * In particular, an implementation may schedule the next callback, e.g.,
+ * a `duration` after either when the previous callback ended,
+ * when the previous callback started, or when the previous callback was
+ * scheduled for - even if the actual callback was delayed.
+ */
+ factory Timer.periodic(Duration duration, void callback(Timer timer)) {
+ if (Zone.current == Zone.root) {
+ // No need to bind the callback. We know that the root's timer will
+ // be invoked in the root zone.
+ return Zone.current.createPeriodicTimer(duration, callback);
+ }
+ var boundCallback = Zone.current.bindUnaryCallbackGuarded<Timer>(callback);
+ return Zone.current.createPeriodicTimer(duration, boundCallback);
+ }
+
+ /**
+ * Runs the given [callback] asynchronously as soon as possible.
+ *
+ * This function is equivalent to `new Timer(Duration.zero, callback)`.
+ */
+ static void run(void callback()) {
+ new Timer(Duration.zero, callback);
+ }
+
+ /**
+ * Cancels the timer.
+ *
+ * Once a [Timer] has been canceled, the callback function will not be called
+ * by the timer. Calling [cancel] more than once on a [Timer] is allowed, and
+ * will have no further effect.
+ */
+ void cancel();
+
+ /**
+ * The number of durations preceding the most recent timer event.
+ *
+ * The value starts at zero and is incremented each time a timer event
+ * occurs, so each callback will see a larger value than the previous one.
+ *
+ * If a periodic timer with a non-zero duration is delayed too much,
+ * so more than one tick should have happened,
+ * all but the last tick in the past are considered "missed",
+ * and no callback is invoked for them.
+ * The [tick] count reflects the number of durations that have passed and
+ * not the number of callback invocations that have happened.
+ */
+ int get tick;
+
+ /**
+ * Returns whether the timer is still active.
+ *
+ * A non-periodic timer is active if the callback has not been executed,
+ * and the timer has not been canceled.
+ *
+ * A periodic timer is active if it has not been canceled.
+ */
+ bool get isActive;
+
+ external static Timer _createTimer(Duration duration, void callback());
+ external static Timer _createPeriodicTimer(
+ Duration duration, void callback(Timer timer));
+}
diff --git a/sdk_nnbd/lib/async/zone.dart b/sdk_nnbd/lib/async/zone.dart
new file mode 100644
index 0000000..911ecff
--- /dev/null
+++ b/sdk_nnbd/lib/async/zone.dart
@@ -0,0 +1,1516 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+typedef R ZoneCallback<R>();
+typedef R ZoneUnaryCallback<R, T>(T arg);
+typedef R ZoneBinaryCallback<R, T1, T2>(T1 arg1, T2 arg2);
+
+typedef HandleUncaughtErrorHandler = void Function(Zone self,
+ ZoneDelegate parent, Zone zone, Object error, StackTrace stackTrace);
+typedef RunHandler = R Function<R>(
+ Zone self, ZoneDelegate parent, Zone zone, R Function() f);
+typedef RunUnaryHandler = R Function<R, T>(
+ Zone self, ZoneDelegate parent, Zone zone, R Function(T arg) f, T arg);
+typedef RunBinaryHandler = R Function<R, T1, T2>(Zone self, ZoneDelegate parent,
+ Zone zone, R Function(T1 arg1, T2 arg2) f, T1 arg1, T2 arg2);
+typedef RegisterCallbackHandler = ZoneCallback<R> Function<R>(
+ Zone self, ZoneDelegate parent, Zone zone, R Function() f);
+typedef RegisterUnaryCallbackHandler = ZoneUnaryCallback<R, T> Function<R, T>(
+ Zone self, ZoneDelegate parent, Zone zone, R Function(T arg) f);
+typedef RegisterBinaryCallbackHandler
+ = ZoneBinaryCallback<R, T1, T2> Function<R, T1, T2>(Zone self,
+ ZoneDelegate parent, Zone zone, R Function(T1 arg1, T2 arg2) f);
+typedef AsyncError ErrorCallbackHandler(Zone self, ZoneDelegate parent,
+ Zone zone, Object error, StackTrace stackTrace);
+typedef void ScheduleMicrotaskHandler(
+ Zone self, ZoneDelegate parent, Zone zone, void f());
+typedef Timer CreateTimerHandler(
+ Zone self, ZoneDelegate parent, Zone zone, Duration duration, void f());
+typedef Timer CreatePeriodicTimerHandler(Zone self, ZoneDelegate parent,
+ Zone zone, Duration period, void f(Timer timer));
+typedef void PrintHandler(
+ Zone self, ZoneDelegate parent, Zone zone, String line);
+typedef Zone ForkHandler(Zone self, ZoneDelegate parent, Zone zone,
+ ZoneSpecification specification, Map zoneValues);
+
+/** Pair of error and stack trace. Returned by [Zone.errorCallback]. */
+class AsyncError implements Error {
+ final Object error;
+ final StackTrace stackTrace;
+
+ AsyncError(this.error, this.stackTrace);
+
+ String toString() => '$error';
+}
+
+class _ZoneFunction<T extends Function> {
+ final _Zone zone;
+ final T function;
+ const _ZoneFunction(this.zone, this.function);
+}
+
+/**
+ * This class provides the specification for a forked zone.
+ *
+ * When forking a new zone (see [Zone.fork]) one can override the default
+ * behavior of the zone by providing callbacks. These callbacks must be
+ * given in an instance of this class.
+ *
+ * Handlers have the same signature as the same-named methods on [Zone] but
+ * receive three additional arguments:
+ *
+ * 1. the zone the handlers are attached to (the "self" zone).
+ * 2. a [ZoneDelegate] to the parent zone.
+ * 3. the zone that first received the request (before the request was
+ * bubbled up).
+ *
+ * Handlers can either stop propagation the request (by simply not calling the
+ * parent handler), or forward to the parent zone, potentially modifying the
+ * arguments on the way.
+ */
+abstract class ZoneSpecification {
+ /**
+ * Creates a specification with the provided handlers.
+ */
+ const factory ZoneSpecification(
+ {HandleUncaughtErrorHandler handleUncaughtError,
+ RunHandler run,
+ RunUnaryHandler runUnary,
+ RunBinaryHandler runBinary,
+ RegisterCallbackHandler registerCallback,
+ RegisterUnaryCallbackHandler registerUnaryCallback,
+ RegisterBinaryCallbackHandler registerBinaryCallback,
+ ErrorCallbackHandler errorCallback,
+ ScheduleMicrotaskHandler scheduleMicrotask,
+ CreateTimerHandler createTimer,
+ CreatePeriodicTimerHandler createPeriodicTimer,
+ PrintHandler print,
+ ForkHandler fork}) = _ZoneSpecification;
+
+ /**
+ * Creates a specification from [other] with the provided handlers overriding
+ * the ones in [other].
+ */
+ factory ZoneSpecification.from(ZoneSpecification other,
+ {HandleUncaughtErrorHandler handleUncaughtError,
+ RunHandler run,
+ RunUnaryHandler runUnary,
+ RunBinaryHandler runBinary,
+ RegisterCallbackHandler registerCallback,
+ RegisterUnaryCallbackHandler registerUnaryCallback,
+ RegisterBinaryCallbackHandler registerBinaryCallback,
+ ErrorCallbackHandler errorCallback,
+ ScheduleMicrotaskHandler scheduleMicrotask,
+ CreateTimerHandler createTimer,
+ CreatePeriodicTimerHandler createPeriodicTimer,
+ PrintHandler print,
+ ForkHandler fork}) {
+ return new ZoneSpecification(
+ handleUncaughtError: handleUncaughtError ?? other.handleUncaughtError,
+ run: run ?? other.run,
+ runUnary: runUnary ?? other.runUnary,
+ runBinary: runBinary ?? other.runBinary,
+ registerCallback: registerCallback ?? other.registerCallback,
+ registerUnaryCallback:
+ registerUnaryCallback ?? other.registerUnaryCallback,
+ registerBinaryCallback:
+ registerBinaryCallback ?? other.registerBinaryCallback,
+ errorCallback: errorCallback ?? other.errorCallback,
+ scheduleMicrotask: scheduleMicrotask ?? other.scheduleMicrotask,
+ createTimer: createTimer ?? other.createTimer,
+ createPeriodicTimer: createPeriodicTimer ?? other.createPeriodicTimer,
+ print: print ?? other.print,
+ fork: fork ?? other.fork);
+ }
+
+ HandleUncaughtErrorHandler get handleUncaughtError;
+ RunHandler get run;
+ RunUnaryHandler get runUnary;
+ RunBinaryHandler get runBinary;
+ RegisterCallbackHandler get registerCallback;
+ RegisterUnaryCallbackHandler get registerUnaryCallback;
+ RegisterBinaryCallbackHandler get registerBinaryCallback;
+ ErrorCallbackHandler get errorCallback;
+ ScheduleMicrotaskHandler get scheduleMicrotask;
+ CreateTimerHandler get createTimer;
+ CreatePeriodicTimerHandler get createPeriodicTimer;
+ PrintHandler get print;
+ ForkHandler get fork;
+}
+
+/**
+ * Internal [ZoneSpecification] class.
+ *
+ * The implementation wants to rely on the fact that the getters cannot change
+ * dynamically. We thus require users to go through the redirecting
+ * [ZoneSpecification] constructor which instantiates this class.
+ */
+class _ZoneSpecification implements ZoneSpecification {
+ const _ZoneSpecification(
+ {this.handleUncaughtError,
+ this.run,
+ this.runUnary,
+ this.runBinary,
+ this.registerCallback,
+ this.registerUnaryCallback,
+ this.registerBinaryCallback,
+ this.errorCallback,
+ this.scheduleMicrotask,
+ this.createTimer,
+ this.createPeriodicTimer,
+ this.print,
+ this.fork});
+
+ final HandleUncaughtErrorHandler handleUncaughtError;
+ final RunHandler run;
+ final RunUnaryHandler runUnary;
+ final RunBinaryHandler runBinary;
+ final RegisterCallbackHandler registerCallback;
+ final RegisterUnaryCallbackHandler registerUnaryCallback;
+ final RegisterBinaryCallbackHandler registerBinaryCallback;
+ final ErrorCallbackHandler errorCallback;
+ final ScheduleMicrotaskHandler scheduleMicrotask;
+ final CreateTimerHandler createTimer;
+ final CreatePeriodicTimerHandler createPeriodicTimer;
+ final PrintHandler print;
+ final ForkHandler fork;
+}
+
+/**
+ * An adapted view of the parent zone.
+ *
+ * This class allows the implementation of a zone method to invoke methods on
+ * the parent zone while retaining knowledge of the originating zone.
+ *
+ * Custom zones (created through [Zone.fork] or [runZoned]) can provide
+ * implementations of most methods of zones. This is similar to overriding
+ * methods on [Zone], except that this mechanism doesn't require subclassing.
+ *
+ * A custom zone function (provided through a [ZoneSpecification]) typically
+ * records or wraps its parameters and then delegates the operation to its
+ * parent zone using the provided [ZoneDelegate].
+ *
+ * While zones have access to their parent zone (through [Zone.parent]) it is
+ * recommended to call the methods on the provided parent delegate for two
+ * reasons:
+ * 1. the delegate methods take an additional `zone` argument which is the
+ * zone the action has been initiated in.
+ * 2. delegate calls are more efficient, since the implementation knows how
+ * to skip zones that would just delegate to their parents.
+ */
+abstract class ZoneDelegate {
+ void handleUncaughtError(Zone zone, error, StackTrace stackTrace);
+ R run<R>(Zone zone, R f());
+ R runUnary<R, T>(Zone zone, R f(T arg), T arg);
+ R runBinary<R, T1, T2>(Zone zone, R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2);
+ ZoneCallback<R> registerCallback<R>(Zone zone, R f());
+ ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(Zone zone, R f(T arg));
+ ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
+ Zone zone, R f(T1 arg1, T2 arg2));
+ AsyncError errorCallback(Zone zone, Object error, StackTrace stackTrace);
+ void scheduleMicrotask(Zone zone, void f());
+ Timer createTimer(Zone zone, Duration duration, void f());
+ Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer));
+ void print(Zone zone, String line);
+ Zone fork(Zone zone, ZoneSpecification specification, Map zoneValues);
+}
+
+/**
+ * A zone represents an environment that remains stable across asynchronous
+ * calls.
+ *
+ * Code is always executed in the context of a zone, available as
+ * [Zone.current]. The initial `main` function runs in the context of the
+ * default zone ([Zone.root]). Code can be run in a different zone using either
+ * [runZoned], to create a new zone, or [Zone.run] to run code in the context of
+ * an existing zone likely created using [Zone.fork].
+ *
+ * Developers can create a new zone that overrides some of the functionality of
+ * an existing zone. For example, custom zones can replace of modify the
+ * behavior of `print`, timers, microtasks or how uncaught errors are handled.
+ *
+ * The [Zone] class is not subclassable, but users can provide custom zones by
+ * forking an existing zone (usually [Zone.current]) with a [ZoneSpecification].
+ * This is similar to creating a new class that extends the base `Zone` class
+ * and that overrides some methods, except without actually creating a new
+ * class. Instead the overriding methods are provided as functions that
+ * explicitly take the equivalent of their own class, the "super" class and the
+ * `this` object as parameters.
+ *
+ * Asynchronous callbacks always run in the context of the zone where they were
+ * scheduled. This is implemented using two steps:
+ * 1. the callback is first registered using one of [registerCallback],
+ * [registerUnaryCallback], or [registerBinaryCallback]. This allows the zone
+ * to record that a callback exists and potentially modify it (by returning a
+ * different callback). The code doing the registration (e.g., `Future.then`)
+ * also remembers the current zone so that it can later run the callback in
+ * that zone.
+ * 2. At a later point the registered callback is run in the remembered zone.
+ *
+ * This is all handled internally by the platform code and most users don't need
+ * to worry about it. However, developers of new asynchronous operations,
+ * provided by the underlying system or through native extensions, must follow
+ * the protocol to be zone compatible.
+ *
+ * For convenience, zones provide [bindCallback] (and the corresponding
+ * [bindUnaryCallback] and [bindBinaryCallback]) to make it easier to respect
+ * the zone contract: these functions first invoke the corresponding `register`
+ * functions and then wrap the returned function so that it runs in the current
+ * zone when it is later asynchronously invoked.
+ *
+ * Similarly, zones provide [bindCallbackGuarded] (and the corresponding
+ * [bindUnaryCallbackGuarded] and [bindBinaryCallbackGuarded]), when the
+ * callback should be invoked through [Zone.runGuarded].
+ */
+abstract class Zone {
+ // Private constructor so that it is not possible instantiate a Zone class.
+ Zone._();
+
+ /**
+ * The root zone.
+ *
+ * All isolate entry functions (`main` or spawned functions) start running in
+ * the root zone (that is, [Zone.current] is identical to [Zone.root] when the
+ * entry function is called). If no custom zone is created, the rest of the
+ * program always runs in the root zone.
+ *
+ * The root zone implements the default behavior of all zone operations.
+ * Many methods, like [registerCallback] do the bare minimum required of the
+ * function, and are only provided as a hook for custom zones. Others, like
+ * [scheduleMicrotask], interact with the underlying system to implement the
+ * desired behavior.
+ */
+ static const Zone root = _rootZone;
+
+ /** The currently running zone. */
+ static Zone _current = _rootZone;
+
+ /** The zone that is currently active. */
+ static Zone get current => _current;
+
+ /**
+ * Handles uncaught asynchronous errors.
+ *
+ * There are two kind of asynchronous errors that are handled by this
+ * function:
+ * 1. Uncaught errors that were thrown in asynchronous callbacks, for example,
+ * a `throw` in the function passed to [Timer.run].
+ * 2. Asynchronous errors that are pushed through [Future] and [Stream]
+ * chains, but for which no child registered an error handler.
+ * Most asynchronous classes, like [Future] or [Stream] push errors to their
+ * listeners. Errors are propagated this way until either a listener handles
+ * the error (for example with [Future.catchError]), or no listener is
+ * available anymore. In the latter case, futures and streams invoke the
+ * zone's [handleUncaughtError].
+ *
+ * By default, when handled by the root zone, uncaught asynchronous errors are
+ * treated like uncaught synchronous exceptions.
+ */
+ void handleUncaughtError(error, StackTrace stackTrace);
+
+ /**
+ * The parent zone of the this zone.
+ *
+ * Is `null` if `this` is the [root] zone.
+ *
+ * Zones are created by [fork] on an existing zone, or by [runZoned] which
+ * forks the [current] zone. The new zone's parent zone is the zone it was
+ * forked from.
+ */
+ Zone get parent;
+
+ /**
+ * The error zone is the one that is responsible for dealing with uncaught
+ * errors.
+ *
+ * This is the closest parent zone of this zone that provides a
+ * [handleUncaughtError] method.
+ *
+ * Asynchronous errors never cross zone boundaries between zones with
+ * different error handlers.
+ *
+ * Example:
+ * ```
+ * import 'dart:async';
+ *
+ * main() {
+ * var future;
+ * runZoned(() {
+ * // The asynchronous error is caught by the custom zone which prints
+ * // 'asynchronous error'.
+ * future = new Future.error("asynchronous error");
+ * }, onError: (e) { print(e); }); // Creates a zone with an error handler.
+ * // The following `catchError` handler is never invoked, because the
+ * // custom zone created by the call to `runZoned` provides an
+ * // error handler.
+ * future.catchError((e) { throw "is never reached"; });
+ * }
+ * ```
+ *
+ * Note that errors cannot enter a child zone with a different error handler
+ * either:
+ * ```
+ * import 'dart:async';
+ *
+ * main() {
+ * runZoned(() {
+ * // The following asynchronous error is *not* caught by the `catchError`
+ * // in the nested zone, since errors are not to cross zone boundaries
+ * // with different error handlers.
+ * // Instead the error is handled by the current error handler,
+ * // printing "Caught by outer zone: asynchronous error".
+ * var future = new Future.error("asynchronous error");
+ * runZoned(() {
+ * future.catchError((e) { throw "is never reached"; });
+ * }, onError: (e) { throw "is never reached"; });
+ * }, onError: (e) { print("Caught by outer zone: $e"); });
+ * }
+ * ```
+ */
+ Zone get errorZone;
+
+ /**
+ * Returns true if `this` and [otherZone] are in the same error zone.
+ *
+ * Two zones are in the same error zone if they have the same [errorZone].
+ */
+ bool inSameErrorZone(Zone otherZone);
+
+ /**
+ * Creates a new zone as a child of `this`.
+ *
+ * The new zone uses the closures in the given [specification] to override
+ * the current's zone behavior. All specification entries that are `null`
+ * inherit the behavior from the parent zone (`this`).
+ *
+ * The new zone inherits the stored values (accessed through [operator []])
+ * of this zone and updates them with values from [zoneValues], which either
+ * adds new values or overrides existing ones.
+ *
+ * Note that the fork operation is interceptible. A zone can thus change
+ * the zone specification (or zone values), giving the forking zone full
+ * control over the child zone.
+ */
+ Zone fork({ZoneSpecification specification, Map zoneValues});
+
+ /**
+ * Executes [action] in this zone.
+ *
+ * By default (as implemented in the [root] zone), runs [action]
+ * with [current] set to this zone.
+ *
+ * If [action] throws, the synchronous exception is not caught by the zone's
+ * error handler. Use [runGuarded] to achieve that.
+ *
+ * Since the root zone is the only zone that can modify the value of
+ * [current], custom zones intercepting run should always delegate to their
+ * parent zone. They may take actions before and after the call.
+ */
+ R run<R>(R action());
+
+ /**
+ * Executes the given [action] with [argument] in this zone.
+ *
+ * As [run] except that [action] is called with one [argument] instead of
+ * none.
+ */
+ R runUnary<R, T>(R action(T argument), T argument);
+
+ /**
+ * Executes the given [action] with [argument1] and [argument2] in this
+ * zone.
+ *
+ * As [run] except that [action] is called with two arguments instead of none.
+ */
+ R runBinary<R, T1, T2>(
+ R action(T1 argument1, T2 argument2), T1 argument1, T2 argument2);
+
+ /**
+ * Executes the given [action] in this zone and catches synchronous
+ * errors.
+ *
+ * This function is equivalent to:
+ * ```
+ * try {
+ * this.run(action);
+ * } catch (e, s) {
+ * this.handleUncaughtError(e, s);
+ * }
+ * ```
+ *
+ * See [run].
+ */
+ void runGuarded(void action());
+
+ /**
+ * Executes the given [action] with [argument] in this zone and
+ * catches synchronous errors.
+ *
+ * See [runGuarded].
+ */
+ void runUnaryGuarded<T>(void action(T argument), T argument);
+
+ /**
+ * Executes the given [action] with [argument1] and [argument2] in this
+ * zone and catches synchronous errors.
+ *
+ * See [runGuarded].
+ */
+ void runBinaryGuarded<T1, T2>(
+ void action(T1 argument1, T2 argument2), T1 argument1, T2 argument2);
+
+ /**
+ * Registers the given callback in this zone.
+ *
+ * When implementing an asynchronous primitive that uses callbacks, the
+ * callback must be registered using [registerCallback] at the point where the
+ * user provides the callback. This allows zones to record other information
+ * that they need at the same time, perhaps even wrapping the callback, so
+ * that the callback is prepared when it is later run in the same zones
+ * (using [run]). For example, a zone may decide
+ * to store the stack trace (at the time of the registration) with the
+ * callback.
+ *
+ * Returns the callback that should be used in place of the provided
+ * [callback]. Frequently zones simply return the original callback.
+ *
+ * Custom zones may intercept this operation. The default implementation in
+ * [Zone.root] returns the original callback unchanged.
+ */
+ ZoneCallback<R> registerCallback<R>(R callback());
+
+ /**
+ * Registers the given callback in this zone.
+ *
+ * Similar to [registerCallback] but with a unary callback.
+ */
+ ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(R callback(T arg));
+
+ /**
+ * Registers the given callback in this zone.
+ *
+ * Similar to [registerCallback] but with a unary callback.
+ */
+ ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
+ R callback(T1 arg1, T2 arg2));
+
+ /**
+ * Registers the provided [callback] and returns a function that will
+ * execute in this zone.
+ *
+ * Equivalent to:
+ *
+ * ZoneCallback registered = this.registerCallback(callback);
+ * return () => this.run(registered);
+ *
+ */
+ ZoneCallback<R> bindCallback<R>(R callback());
+
+ /**
+ * Registers the provided [callback] and returns a function that will
+ * execute in this zone.
+ *
+ * Equivalent to:
+ *
+ * ZoneCallback registered = this.registerUnaryCallback(callback);
+ * return (arg) => thin.runUnary(registered, arg);
+ */
+ ZoneUnaryCallback<R, T> bindUnaryCallback<R, T>(R callback(T argument));
+
+ /**
+ * Registers the provided [callback] and returns a function that will
+ * execute in this zone.
+ *
+ * Equivalent to:
+ *
+ * ZoneCallback registered = registerBinaryCallback(callback);
+ * return (arg1, arg2) => thin.runBinary(registered, arg1, arg2);
+ */
+ ZoneBinaryCallback<R, T1, T2> bindBinaryCallback<R, T1, T2>(
+ R callback(T1 argument1, T2 argument2));
+
+ /**
+ * Registers the provided [callback] and returns a function that will
+ * execute in this zone.
+ *
+ * When the function executes, errors are caught and treated as uncaught
+ * errors.
+ *
+ * Equivalent to:
+ *
+ * ZoneCallback registered = this.registerCallback(callback);
+ * return () => this.runGuarded(registered);
+ *
+ */
+ void Function() bindCallbackGuarded(void callback());
+
+ /**
+ * Registers the provided [callback] and returns a function that will
+ * execute in this zone.
+ *
+ * When the function executes, errors are caught and treated as uncaught
+ * errors.
+ *
+ * Equivalent to:
+ *
+ * ZoneCallback registered = this.registerUnaryCallback(callback);
+ * return (arg) => this.runUnaryGuarded(registered, arg);
+ */
+ void Function(T) bindUnaryCallbackGuarded<T>(void callback(T argument));
+
+ /**
+ * Registers the provided [callback] and returns a function that will
+ * execute in this zone.
+ *
+ * Equivalent to:
+ *
+ * ZoneCallback registered = registerBinaryCallback(callback);
+ * return (arg1, arg2) => this.runBinaryGuarded(registered, arg1, arg2);
+ */
+ void Function(T1, T2) bindBinaryCallbackGuarded<T1, T2>(
+ void callback(T1 argument1, T2 argument2));
+
+ /**
+ * Intercepts errors when added programmatically to a `Future` or `Stream`.
+ *
+ * When calling [Completer.completeError], [StreamController.addError],
+ * or some [Future] constructors, the current zone is allowed to intercept
+ * and replace the error.
+ *
+ * Future constructors invoke this function when the error is received
+ * directly, for example with [Future.error], or when the error is caught
+ * synchronously, for example with [Future.sync].
+ *
+ * There is no guarantee that an error is only sent through [errorCallback]
+ * once. Libraries that use intermediate controllers or completers might
+ * end up invoking [errorCallback] multiple times.
+ *
+ * Returns `null` if no replacement is desired. Otherwise returns an instance
+ * of [AsyncError] holding the new pair of error and stack trace.
+ *
+ * Although not recommended, the returned instance may have its `error` member
+ * ([AsyncError.error]) be equal to `null` in which case the error should be
+ * replaced by a [NullThrownError].
+ *
+ * Custom zones may intercept this operation.
+ *
+ * Implementations of a new asynchronous primitive that converts synchronous
+ * errors to asynchronous errors rarely need to invoke [errorCallback], since
+ * errors are usually reported through future completers or stream
+ * controllers.
+ */
+ AsyncError errorCallback(Object error, StackTrace stackTrace);
+
+ /**
+ * Runs [callback] asynchronously in this zone.
+ *
+ * The global `scheduleMicrotask` delegates to the current zone's
+ * [scheduleMicrotask]. The root zone's implementation interacts with the
+ * underlying system to schedule the given callback as a microtask.
+ *
+ * Custom zones may intercept this operation (for example to wrap the given
+ * [callback]).
+ */
+ void scheduleMicrotask(void callback());
+
+ /**
+ * Creates a Timer where the callback is executed in this zone.
+ */
+ Timer createTimer(Duration duration, void callback());
+
+ /**
+ * Creates a periodic Timer where the callback is executed in this zone.
+ */
+ Timer createPeriodicTimer(Duration period, void callback(Timer timer));
+
+ /**
+ * Prints the given [line].
+ *
+ * The global `print` function delegates to the current zone's [print]
+ * function which makes it possible to intercept printing.
+ *
+ * Example:
+ * ```
+ * import 'dart:async';
+ *
+ * main() {
+ * runZoned(() {
+ * // Ends up printing: "Intercepted: in zone".
+ * print("in zone");
+ * }, zoneSpecification: new ZoneSpecification(
+ * print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
+ * parent.print(zone, "Intercepted: $line");
+ * }));
+ * }
+ * ```
+ */
+ void print(String line);
+
+ /**
+ * Call to enter the Zone.
+ *
+ * The previous current zone is returned.
+ */
+ static Zone _enter(Zone zone) {
+ assert(zone != null);
+ assert(!identical(zone, _current));
+ Zone previous = _current;
+ _current = zone;
+ return previous;
+ }
+
+ /**
+ * Call to leave the Zone.
+ *
+ * The previous Zone must be provided as `previous`.
+ */
+ static void _leave(Zone previous) {
+ assert(previous != null);
+ Zone._current = previous;
+ }
+
+ /**
+ * Retrieves the zone-value associated with [key].
+ *
+ * If this zone does not contain the value looks up the same key in the
+ * parent zone. If the [key] is not found returns `null`.
+ *
+ * Any object can be used as key, as long as it has compatible `operator ==`
+ * and `hashCode` implementations.
+ * By controlling access to the key, a zone can grant or deny access to the
+ * zone value.
+ */
+ operator [](Object key);
+}
+
+ZoneDelegate _parentDelegate(_Zone zone) {
+ if (zone.parent == null) return null;
+ return zone.parent._delegate;
+}
+
+class _ZoneDelegate implements ZoneDelegate {
+ final _Zone _delegationTarget;
+
+ _ZoneDelegate(this._delegationTarget);
+
+ void handleUncaughtError(Zone zone, error, StackTrace stackTrace) {
+ var implementation = _delegationTarget._handleUncaughtError;
+ _Zone implZone = implementation.zone;
+ HandleUncaughtErrorHandler handler = implementation.function;
+ return handler(
+ implZone, _parentDelegate(implZone), zone, error, stackTrace);
+ }
+
+ R run<R>(Zone zone, R f()) {
+ var implementation = _delegationTarget._run;
+ _Zone implZone = implementation.zone;
+ RunHandler handler = implementation.function;
+ return handler(implZone, _parentDelegate(implZone), zone, f);
+ }
+
+ R runUnary<R, T>(Zone zone, R f(T arg), T arg) {
+ var implementation = _delegationTarget._runUnary;
+ _Zone implZone = implementation.zone;
+ RunUnaryHandler handler = implementation.function;
+ return handler(implZone, _parentDelegate(implZone), zone, f, arg);
+ }
+
+ R runBinary<R, T1, T2>(Zone zone, R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2) {
+ var implementation = _delegationTarget._runBinary;
+ _Zone implZone = implementation.zone;
+ RunBinaryHandler handler = implementation.function;
+ return handler(implZone, _parentDelegate(implZone), zone, f, arg1, arg2);
+ }
+
+ ZoneCallback<R> registerCallback<R>(Zone zone, R f()) {
+ var implementation = _delegationTarget._registerCallback;
+ _Zone implZone = implementation.zone;
+ RegisterCallbackHandler handler = implementation.function;
+ return handler(implZone, _parentDelegate(implZone), zone, f);
+ }
+
+ ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(Zone zone, R f(T arg)) {
+ var implementation = _delegationTarget._registerUnaryCallback;
+ _Zone implZone = implementation.zone;
+ RegisterUnaryCallbackHandler handler = implementation.function;
+ return handler(implZone, _parentDelegate(implZone), zone, f);
+ }
+
+ ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
+ Zone zone, R f(T1 arg1, T2 arg2)) {
+ var implementation = _delegationTarget._registerBinaryCallback;
+ _Zone implZone = implementation.zone;
+ RegisterBinaryCallbackHandler handler = implementation.function;
+ return handler(implZone, _parentDelegate(implZone), zone, f);
+ }
+
+ AsyncError errorCallback(Zone zone, Object error, StackTrace stackTrace) {
+ var implementation = _delegationTarget._errorCallback;
+ _Zone implZone = implementation.zone;
+ if (identical(implZone, _rootZone)) return null;
+ ErrorCallbackHandler handler = implementation.function;
+ return handler(
+ implZone, _parentDelegate(implZone), zone, error, stackTrace);
+ }
+
+ void scheduleMicrotask(Zone zone, f()) {
+ var implementation = _delegationTarget._scheduleMicrotask;
+ _Zone implZone = implementation.zone;
+ ScheduleMicrotaskHandler handler = implementation.function;
+ handler(implZone, _parentDelegate(implZone), zone, f);
+ }
+
+ Timer createTimer(Zone zone, Duration duration, void f()) {
+ var implementation = _delegationTarget._createTimer;
+ _Zone implZone = implementation.zone;
+ CreateTimerHandler handler = implementation.function;
+ return handler(implZone, _parentDelegate(implZone), zone, duration, f);
+ }
+
+ Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer)) {
+ var implementation = _delegationTarget._createPeriodicTimer;
+ _Zone implZone = implementation.zone;
+ CreatePeriodicTimerHandler handler = implementation.function;
+ return handler(implZone, _parentDelegate(implZone), zone, period, f);
+ }
+
+ void print(Zone zone, String line) {
+ var implementation = _delegationTarget._print;
+ _Zone implZone = implementation.zone;
+ PrintHandler handler = implementation.function;
+ handler(implZone, _parentDelegate(implZone), zone, line);
+ }
+
+ Zone fork(Zone zone, ZoneSpecification specification, Map zoneValues) {
+ var implementation = _delegationTarget._fork;
+ _Zone implZone = implementation.zone;
+ ForkHandler handler = implementation.function;
+ return handler(
+ implZone, _parentDelegate(implZone), zone, specification, zoneValues);
+ }
+}
+
+/**
+ * Base class for Zone implementations.
+ */
+abstract class _Zone implements Zone {
+ const _Zone();
+
+ // TODO(floitsch): the types of the `_ZoneFunction`s should have a type for
+ // all fields.
+ _ZoneFunction<Function> get _run;
+ _ZoneFunction<Function> get _runUnary;
+ _ZoneFunction<Function> get _runBinary;
+ _ZoneFunction<Function> get _registerCallback;
+ _ZoneFunction<Function> get _registerUnaryCallback;
+ _ZoneFunction<Function> get _registerBinaryCallback;
+ _ZoneFunction<ErrorCallbackHandler> get _errorCallback;
+ _ZoneFunction<ScheduleMicrotaskHandler> get _scheduleMicrotask;
+ _ZoneFunction<CreateTimerHandler> get _createTimer;
+ _ZoneFunction<CreatePeriodicTimerHandler> get _createPeriodicTimer;
+ _ZoneFunction<PrintHandler> get _print;
+ _ZoneFunction<ForkHandler> get _fork;
+ _ZoneFunction<HandleUncaughtErrorHandler> get _handleUncaughtError;
+ _Zone get parent;
+ ZoneDelegate get _delegate;
+ Map get _map;
+
+ bool inSameErrorZone(Zone otherZone) {
+ return identical(this, otherZone) ||
+ identical(errorZone, otherZone.errorZone);
+ }
+}
+
+class _CustomZone extends _Zone {
+ // The actual zone and implementation of each of these
+ // inheritable zone functions.
+ // TODO(floitsch): the types of the `_ZoneFunction`s should have a type for
+ // all fields.
+ _ZoneFunction<Function> _run;
+ _ZoneFunction<Function> _runUnary;
+ _ZoneFunction<Function> _runBinary;
+ _ZoneFunction<Function> _registerCallback;
+ _ZoneFunction<Function> _registerUnaryCallback;
+ _ZoneFunction<Function> _registerBinaryCallback;
+ _ZoneFunction<ErrorCallbackHandler> _errorCallback;
+ _ZoneFunction<ScheduleMicrotaskHandler> _scheduleMicrotask;
+ _ZoneFunction<CreateTimerHandler> _createTimer;
+ _ZoneFunction<CreatePeriodicTimerHandler> _createPeriodicTimer;
+ _ZoneFunction<PrintHandler> _print;
+ _ZoneFunction<ForkHandler> _fork;
+ _ZoneFunction<HandleUncaughtErrorHandler> _handleUncaughtError;
+
+ // A cached delegate to this zone.
+ ZoneDelegate _delegateCache;
+
+ /// The parent zone.
+ final _Zone parent;
+
+ /// The zone's scoped value declaration map.
+ ///
+ /// This is always a [HashMap].
+ final Map _map;
+
+ ZoneDelegate get _delegate {
+ if (_delegateCache != null) return _delegateCache;
+ _delegateCache = new _ZoneDelegate(this);
+ return _delegateCache;
+ }
+
+ _CustomZone(this.parent, ZoneSpecification specification, this._map) {
+ // The root zone will have implementations of all parts of the
+ // specification, so it will never try to access the (null) parent.
+ // All other zones have a non-null parent.
+ _run = (specification.run != null)
+ ? new _ZoneFunction<Function>(this, specification.run)
+ : parent._run;
+ _runUnary = (specification.runUnary != null)
+ ? new _ZoneFunction<Function>(this, specification.runUnary)
+ : parent._runUnary;
+ _runBinary = (specification.runBinary != null)
+ ? new _ZoneFunction<Function>(this, specification.runBinary)
+ : parent._runBinary;
+ _registerCallback = (specification.registerCallback != null)
+ ? new _ZoneFunction<Function>(this, specification.registerCallback)
+ : parent._registerCallback;
+ _registerUnaryCallback = (specification.registerUnaryCallback != null)
+ ? new _ZoneFunction<Function>(this, specification.registerUnaryCallback)
+ : parent._registerUnaryCallback;
+ _registerBinaryCallback = (specification.registerBinaryCallback != null)
+ ? new _ZoneFunction<Function>(
+ this, specification.registerBinaryCallback)
+ : parent._registerBinaryCallback;
+ _errorCallback = (specification.errorCallback != null)
+ ? new _ZoneFunction<ErrorCallbackHandler>(
+ this, specification.errorCallback)
+ : parent._errorCallback;
+ _scheduleMicrotask = (specification.scheduleMicrotask != null)
+ ? new _ZoneFunction<ScheduleMicrotaskHandler>(
+ this, specification.scheduleMicrotask)
+ : parent._scheduleMicrotask;
+ _createTimer = (specification.createTimer != null)
+ ? new _ZoneFunction<CreateTimerHandler>(this, specification.createTimer)
+ : parent._createTimer;
+ _createPeriodicTimer = (specification.createPeriodicTimer != null)
+ ? new _ZoneFunction<CreatePeriodicTimerHandler>(
+ this, specification.createPeriodicTimer)
+ : parent._createPeriodicTimer;
+ _print = (specification.print != null)
+ ? new _ZoneFunction<PrintHandler>(this, specification.print)
+ : parent._print;
+ _fork = (specification.fork != null)
+ ? new _ZoneFunction<ForkHandler>(this, specification.fork)
+ : parent._fork;
+ _handleUncaughtError = (specification.handleUncaughtError != null)
+ ? new _ZoneFunction<HandleUncaughtErrorHandler>(
+ this, specification.handleUncaughtError)
+ : parent._handleUncaughtError;
+ }
+
+ /**
+ * The closest error-handling zone.
+ *
+ * Returns `this` if `this` has an error-handler. Otherwise returns the
+ * parent's error-zone.
+ */
+ Zone get errorZone => _handleUncaughtError.zone;
+
+ void runGuarded(void f()) {
+ try {
+ run(f);
+ } catch (e, s) {
+ handleUncaughtError(e, s);
+ }
+ }
+
+ void runUnaryGuarded<T>(void f(T arg), T arg) {
+ try {
+ runUnary(f, arg);
+ } catch (e, s) {
+ handleUncaughtError(e, s);
+ }
+ }
+
+ void runBinaryGuarded<T1, T2>(void f(T1 arg1, T2 arg2), T1 arg1, T2 arg2) {
+ try {
+ runBinary(f, arg1, arg2);
+ } catch (e, s) {
+ handleUncaughtError(e, s);
+ }
+ }
+
+ ZoneCallback<R> bindCallback<R>(R f()) {
+ var registered = registerCallback(f);
+ return () => this.run(registered);
+ }
+
+ ZoneUnaryCallback<R, T> bindUnaryCallback<R, T>(R f(T arg)) {
+ var registered = registerUnaryCallback(f);
+ return (arg) => this.runUnary(registered, arg);
+ }
+
+ ZoneBinaryCallback<R, T1, T2> bindBinaryCallback<R, T1, T2>(
+ R f(T1 arg1, T2 arg2)) {
+ var registered = registerBinaryCallback(f);
+ return (arg1, arg2) => this.runBinary(registered, arg1, arg2);
+ }
+
+ void Function() bindCallbackGuarded(void f()) {
+ var registered = registerCallback(f);
+ return () => this.runGuarded(registered);
+ }
+
+ void Function(T) bindUnaryCallbackGuarded<T>(void f(T arg)) {
+ var registered = registerUnaryCallback(f);
+ return (arg) => this.runUnaryGuarded(registered, arg);
+ }
+
+ void Function(T1, T2) bindBinaryCallbackGuarded<T1, T2>(
+ void f(T1 arg1, T2 arg2)) {
+ var registered = registerBinaryCallback(f);
+ return (arg1, arg2) => this.runBinaryGuarded(registered, arg1, arg2);
+ }
+
+ operator [](Object key) {
+ var result = _map[key];
+ if (result != null || _map.containsKey(key)) return result;
+ // If we are not the root zone, look up in the parent zone.
+ if (parent != null) {
+ // We do not optimize for repeatedly looking up a key which isn't
+ // there. That would require storing the key and keeping it alive.
+ // Copying the key/value from the parent does not keep any new values
+ // alive.
+ var value = parent[key];
+ if (value != null) {
+ _map[key] = value;
+ }
+ return value;
+ }
+ assert(this == _rootZone);
+ return null;
+ }
+
+ // Methods that can be customized by the zone specification.
+
+ void handleUncaughtError(error, StackTrace stackTrace) {
+ var implementation = this._handleUncaughtError;
+ assert(implementation != null);
+ ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+ HandleUncaughtErrorHandler handler = implementation.function;
+ return handler(
+ implementation.zone, parentDelegate, this, error, stackTrace);
+ }
+
+ Zone fork({ZoneSpecification specification, Map zoneValues}) {
+ var implementation = this._fork;
+ assert(implementation != null);
+ ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+ ForkHandler handler = implementation.function;
+ return handler(
+ implementation.zone, parentDelegate, this, specification, zoneValues);
+ }
+
+ R run<R>(R f()) {
+ var implementation = this._run;
+ assert(implementation != null);
+ ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+ RunHandler handler = implementation.function;
+ return handler(implementation.zone, parentDelegate, this, f);
+ }
+
+ R runUnary<R, T>(R f(T arg), T arg) {
+ var implementation = this._runUnary;
+ assert(implementation != null);
+ ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+ RunUnaryHandler handler = implementation.function;
+ return handler(implementation.zone, parentDelegate, this, f, arg);
+ }
+
+ R runBinary<R, T1, T2>(R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2) {
+ var implementation = this._runBinary;
+ assert(implementation != null);
+ ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+ RunBinaryHandler handler = implementation.function;
+ return handler(implementation.zone, parentDelegate, this, f, arg1, arg2);
+ }
+
+ ZoneCallback<R> registerCallback<R>(R callback()) {
+ var implementation = this._registerCallback;
+ assert(implementation != null);
+ ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+ RegisterCallbackHandler handler = implementation.function;
+ return handler(implementation.zone, parentDelegate, this, callback);
+ }
+
+ ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(R callback(T arg)) {
+ var implementation = this._registerUnaryCallback;
+ assert(implementation != null);
+ ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+ RegisterUnaryCallbackHandler handler = implementation.function;
+ return handler(implementation.zone, parentDelegate, this, callback);
+ }
+
+ ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
+ R callback(T1 arg1, T2 arg2)) {
+ var implementation = this._registerBinaryCallback;
+ assert(implementation != null);
+ ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+ RegisterBinaryCallbackHandler handler = implementation.function;
+ return handler(implementation.zone, parentDelegate, this, callback);
+ }
+
+ AsyncError errorCallback(Object error, StackTrace stackTrace) {
+ var implementation = this._errorCallback;
+ assert(implementation != null);
+ final Zone implementationZone = implementation.zone;
+ if (identical(implementationZone, _rootZone)) return null;
+ final ZoneDelegate parentDelegate = _parentDelegate(implementationZone);
+ ErrorCallbackHandler handler = implementation.function;
+ return handler(implementationZone, parentDelegate, this, error, stackTrace);
+ }
+
+ void scheduleMicrotask(void f()) {
+ var implementation = this._scheduleMicrotask;
+ assert(implementation != null);
+ ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+ ScheduleMicrotaskHandler handler = implementation.function;
+ return handler(implementation.zone, parentDelegate, this, f);
+ }
+
+ Timer createTimer(Duration duration, void f()) {
+ var implementation = this._createTimer;
+ assert(implementation != null);
+ ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+ CreateTimerHandler handler = implementation.function;
+ return handler(implementation.zone, parentDelegate, this, duration, f);
+ }
+
+ Timer createPeriodicTimer(Duration duration, void f(Timer timer)) {
+ var implementation = this._createPeriodicTimer;
+ assert(implementation != null);
+ ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+ CreatePeriodicTimerHandler handler = implementation.function;
+ return handler(implementation.zone, parentDelegate, this, duration, f);
+ }
+
+ void print(String line) {
+ var implementation = this._print;
+ assert(implementation != null);
+ ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
+ PrintHandler handler = implementation.function;
+ return handler(implementation.zone, parentDelegate, this, line);
+ }
+}
+
+void _rootHandleUncaughtError(
+ Zone self, ZoneDelegate parent, Zone zone, error, StackTrace stackTrace) {
+ _schedulePriorityAsyncCallback(() {
+ error ??= new NullThrownError();
+ if (stackTrace == null) throw error;
+ _rethrow(error, stackTrace);
+ });
+}
+
+external void _rethrow(Object error, StackTrace stackTrace);
+
+R _rootRun<R>(Zone self, ZoneDelegate parent, Zone zone, R f()) {
+ if (Zone._current == zone) return f();
+
+ Zone old = Zone._enter(zone);
+ try {
+ return f();
+ } finally {
+ Zone._leave(old);
+ }
+}
+
+R _rootRunUnary<R, T>(
+ Zone self, ZoneDelegate parent, Zone zone, R f(T arg), T arg) {
+ if (Zone._current == zone) return f(arg);
+
+ Zone old = Zone._enter(zone);
+ try {
+ return f(arg);
+ } finally {
+ Zone._leave(old);
+ }
+}
+
+R _rootRunBinary<R, T1, T2>(Zone self, ZoneDelegate parent, Zone zone,
+ R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2) {
+ if (Zone._current == zone) return f(arg1, arg2);
+
+ Zone old = Zone._enter(zone);
+ try {
+ return f(arg1, arg2);
+ } finally {
+ Zone._leave(old);
+ }
+}
+
+ZoneCallback<R> _rootRegisterCallback<R>(
+ Zone self, ZoneDelegate parent, Zone zone, R f()) {
+ return f;
+}
+
+ZoneUnaryCallback<R, T> _rootRegisterUnaryCallback<R, T>(
+ Zone self, ZoneDelegate parent, Zone zone, R f(T arg)) {
+ return f;
+}
+
+ZoneBinaryCallback<R, T1, T2> _rootRegisterBinaryCallback<R, T1, T2>(
+ Zone self, ZoneDelegate parent, Zone zone, R f(T1 arg1, T2 arg2)) {
+ return f;
+}
+
+AsyncError _rootErrorCallback(Zone self, ZoneDelegate parent, Zone zone,
+ Object error, StackTrace stackTrace) =>
+ null;
+
+void _rootScheduleMicrotask(
+ Zone self, ZoneDelegate parent, Zone zone, void f()) {
+ if (!identical(_rootZone, zone)) {
+ bool hasErrorHandler = !_rootZone.inSameErrorZone(zone);
+ if (hasErrorHandler) {
+ f = zone.bindCallbackGuarded(f);
+ } else {
+ f = zone.bindCallback(f);
+ }
+ // Use root zone as event zone if the function is already bound.
+ zone = _rootZone;
+ }
+ _scheduleAsyncCallback(f);
+}
+
+Timer _rootCreateTimer(Zone self, ZoneDelegate parent, Zone zone,
+ Duration duration, void callback()) {
+ if (!identical(_rootZone, zone)) {
+ callback = zone.bindCallback(callback);
+ }
+ return Timer._createTimer(duration, callback);
+}
+
+Timer _rootCreatePeriodicTimer(Zone self, ZoneDelegate parent, Zone zone,
+ Duration duration, void callback(Timer timer)) {
+ if (!identical(_rootZone, zone)) {
+ // TODO(floitsch): the return type should be 'void'.
+ callback = zone.bindUnaryCallback<dynamic, Timer>(callback);
+ }
+ return Timer._createPeriodicTimer(duration, callback);
+}
+
+void _rootPrint(Zone self, ZoneDelegate parent, Zone zone, String line) {
+ printToConsole(line);
+}
+
+void _printToZone(String line) {
+ Zone.current.print(line);
+}
+
+Zone _rootFork(Zone self, ZoneDelegate parent, Zone zone,
+ ZoneSpecification specification, Map zoneValues) {
+ // TODO(floitsch): it would be nice if we could get rid of this hack.
+ // Change the static zoneOrDirectPrint function to go through zones
+ // from now on.
+ printToZone = _printToZone;
+
+ if (specification == null) {
+ specification = const ZoneSpecification();
+ } else if (specification is! _ZoneSpecification) {
+ throw new ArgumentError("ZoneSpecifications must be instantiated"
+ " with the provided constructor.");
+ }
+ Map valueMap;
+ if (zoneValues == null) {
+ if (zone is _Zone) {
+ valueMap = zone._map;
+ } else {
+ valueMap = new HashMap();
+ }
+ } else {
+ valueMap = new HashMap.from(zoneValues);
+ }
+ return new _CustomZone(zone, specification, valueMap);
+}
+
+class _RootZone extends _Zone {
+ const _RootZone();
+
+ _ZoneFunction<Function> get _run =>
+ const _ZoneFunction<Function>(_rootZone, _rootRun);
+ _ZoneFunction<Function> get _runUnary =>
+ const _ZoneFunction<Function>(_rootZone, _rootRunUnary);
+ _ZoneFunction<Function> get _runBinary =>
+ const _ZoneFunction<Function>(_rootZone, _rootRunBinary);
+ _ZoneFunction<Function> get _registerCallback =>
+ const _ZoneFunction<Function>(_rootZone, _rootRegisterCallback);
+ _ZoneFunction<Function> get _registerUnaryCallback =>
+ const _ZoneFunction<Function>(_rootZone, _rootRegisterUnaryCallback);
+ _ZoneFunction<Function> get _registerBinaryCallback =>
+ const _ZoneFunction<Function>(_rootZone, _rootRegisterBinaryCallback);
+ _ZoneFunction<ErrorCallbackHandler> get _errorCallback =>
+ const _ZoneFunction<ErrorCallbackHandler>(_rootZone, _rootErrorCallback);
+ _ZoneFunction<ScheduleMicrotaskHandler> get _scheduleMicrotask =>
+ const _ZoneFunction<ScheduleMicrotaskHandler>(
+ _rootZone, _rootScheduleMicrotask);
+ _ZoneFunction<CreateTimerHandler> get _createTimer =>
+ const _ZoneFunction<CreateTimerHandler>(_rootZone, _rootCreateTimer);
+ _ZoneFunction<CreatePeriodicTimerHandler> get _createPeriodicTimer =>
+ const _ZoneFunction<CreatePeriodicTimerHandler>(
+ _rootZone, _rootCreatePeriodicTimer);
+ _ZoneFunction<PrintHandler> get _print =>
+ const _ZoneFunction<PrintHandler>(_rootZone, _rootPrint);
+ _ZoneFunction<ForkHandler> get _fork =>
+ const _ZoneFunction<ForkHandler>(_rootZone, _rootFork);
+ _ZoneFunction<HandleUncaughtErrorHandler> get _handleUncaughtError =>
+ const _ZoneFunction<HandleUncaughtErrorHandler>(
+ _rootZone, _rootHandleUncaughtError);
+
+ // The parent zone.
+ _Zone get parent => null;
+
+ /// The zone's scoped value declaration map.
+ ///
+ /// This is always a [HashMap].
+ Map get _map => _rootMap;
+
+ static final _rootMap = new HashMap();
+
+ static ZoneDelegate _rootDelegate;
+
+ ZoneDelegate get _delegate {
+ if (_rootDelegate != null) return _rootDelegate;
+ return _rootDelegate = new _ZoneDelegate(this);
+ }
+
+ /**
+ * The closest error-handling zone.
+ *
+ * Returns `this` if `this` has an error-handler. Otherwise returns the
+ * parent's error-zone.
+ */
+ Zone get errorZone => this;
+
+ // Zone interface.
+
+ void runGuarded(void f()) {
+ try {
+ if (identical(_rootZone, Zone._current)) {
+ f();
+ return;
+ }
+ _rootRun(null, null, this, f);
+ } catch (e, s) {
+ handleUncaughtError(e, s);
+ }
+ }
+
+ void runUnaryGuarded<T>(void f(T arg), T arg) {
+ try {
+ if (identical(_rootZone, Zone._current)) {
+ f(arg);
+ return;
+ }
+ _rootRunUnary(null, null, this, f, arg);
+ } catch (e, s) {
+ handleUncaughtError(e, s);
+ }
+ }
+
+ void runBinaryGuarded<T1, T2>(void f(T1 arg1, T2 arg2), T1 arg1, T2 arg2) {
+ try {
+ if (identical(_rootZone, Zone._current)) {
+ f(arg1, arg2);
+ return;
+ }
+ _rootRunBinary(null, null, this, f, arg1, arg2);
+ } catch (e, s) {
+ handleUncaughtError(e, s);
+ }
+ }
+
+ ZoneCallback<R> bindCallback<R>(R f()) {
+ return () => this.run<R>(f);
+ }
+
+ ZoneUnaryCallback<R, T> bindUnaryCallback<R, T>(R f(T arg)) {
+ return (arg) => this.runUnary<R, T>(f, arg);
+ }
+
+ ZoneBinaryCallback<R, T1, T2> bindBinaryCallback<R, T1, T2>(
+ R f(T1 arg1, T2 arg2)) {
+ return (arg1, arg2) => this.runBinary<R, T1, T2>(f, arg1, arg2);
+ }
+
+ void Function() bindCallbackGuarded(void f()) {
+ return () => this.runGuarded(f);
+ }
+
+ void Function(T) bindUnaryCallbackGuarded<T>(void f(T arg)) {
+ return (arg) => this.runUnaryGuarded(f, arg);
+ }
+
+ void Function(T1, T2) bindBinaryCallbackGuarded<T1, T2>(
+ void f(T1 arg1, T2 arg2)) {
+ return (arg1, arg2) => this.runBinaryGuarded(f, arg1, arg2);
+ }
+
+ operator [](Object key) => null;
+
+ // Methods that can be customized by the zone specification.
+
+ void handleUncaughtError(error, StackTrace stackTrace) {
+ _rootHandleUncaughtError(null, null, this, error, stackTrace);
+ }
+
+ Zone fork({ZoneSpecification specification, Map zoneValues}) {
+ return _rootFork(null, null, this, specification, zoneValues);
+ }
+
+ R run<R>(R f()) {
+ if (identical(Zone._current, _rootZone)) return f();
+ return _rootRun(null, null, this, f);
+ }
+
+ R runUnary<R, T>(R f(T arg), T arg) {
+ if (identical(Zone._current, _rootZone)) return f(arg);
+ return _rootRunUnary(null, null, this, f, arg);
+ }
+
+ R runBinary<R, T1, T2>(R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2) {
+ if (identical(Zone._current, _rootZone)) return f(arg1, arg2);
+ return _rootRunBinary(null, null, this, f, arg1, arg2);
+ }
+
+ ZoneCallback<R> registerCallback<R>(R f()) => f;
+
+ ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(R f(T arg)) => f;
+
+ ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
+ R f(T1 arg1, T2 arg2)) =>
+ f;
+
+ AsyncError errorCallback(Object error, StackTrace stackTrace) => null;
+
+ void scheduleMicrotask(void f()) {
+ _rootScheduleMicrotask(null, null, this, f);
+ }
+
+ Timer createTimer(Duration duration, void f()) {
+ return Timer._createTimer(duration, f);
+ }
+
+ Timer createPeriodicTimer(Duration duration, void f(Timer timer)) {
+ return Timer._createPeriodicTimer(duration, f);
+ }
+
+ void print(String line) {
+ printToConsole(line);
+ }
+}
+
+const _rootZone = const _RootZone();
+
+/**
+ * Runs [body] in its own zone.
+ *
+ * Creates a new zone using [Zone.fork] based on [zoneSpecification] and
+ * [zoneValues], then runs [body] in that zone and returns the result.
+ *
+ * If [onError] is provided, it must have one of the types
+ * * `void Function(Object)`
+ * * `void Function(Object, StackTrace)`
+ * and the [onError] handler is used *both* to handle asynchronous errors
+ * by overriding [ZoneSpecification.handleUncaughtError] in [zoneSpecification],
+ * if any, *and* to handle errors thrown synchronously by the call to [body].
+ *
+ * If an error occurs synchronously in [body],
+ * then throwing in the [onError] handler
+ * makes the call to `runZone` throw that error,
+ * and otherwise the call to `runZoned` returns `null`.
+ *
+ * If the zone specification has a `handleUncaughtError` value or the [onError]
+ * parameter is provided, the zone becomes an error-zone.
+ *
+ * Errors will never cross error-zone boundaries by themselves.
+ * Errors that try to cross error-zone boundaries are considered uncaught in
+ * their originating error zone.
+ *
+ * var future = new Future.value(499);
+ * runZoned(() {
+ * var future2 = future.then((_) { throw "error in first error-zone"; });
+ * runZoned(() {
+ * var future3 = future2.catchError((e) { print("Never reached!"); });
+ * }, onError: (e) { print("unused error handler"); });
+ * }, onError: (e) { print("catches error of first error-zone."); });
+ *
+ * Example:
+ *
+ * runZoned(() {
+ * new Future(() { throw "asynchronous error"; });
+ * }, onError: print); // Will print "asynchronous error".
+ *
+ * It is possible to manually pass an error from one error zone to another
+ * by re-throwing it in the new zone. If [onError] throws, that error will
+ * occur in the original zone where [runZoned] was called.
+ */
+R runZoned<R>(R body(),
+ {Map zoneValues, ZoneSpecification zoneSpecification, Function onError}) {
+ if (onError == null) {
+ return _runZoned<R>(body, zoneValues, zoneSpecification);
+ }
+ void Function(Object) unaryOnError;
+ void Function(Object, StackTrace) binaryOnError;
+ if (onError is void Function(Object, StackTrace)) {
+ binaryOnError = onError;
+ } else if (onError is void Function(Object)) {
+ unaryOnError = onError;
+ } else {
+ throw new ArgumentError("onError callback must take either an Object "
+ "(the error), or both an Object (the error) and a StackTrace.");
+ }
+ HandleUncaughtErrorHandler errorHandler = (Zone self, ZoneDelegate parent,
+ Zone zone, error, StackTrace stackTrace) {
+ try {
+ if (binaryOnError != null) {
+ self.parent.runBinary(binaryOnError, error, stackTrace);
+ } else {
+ assert(unaryOnError != null);
+ self.parent.runUnary(unaryOnError, error);
+ }
+ } catch (e, s) {
+ if (identical(e, error)) {
+ parent.handleUncaughtError(zone, error, stackTrace);
+ } else {
+ parent.handleUncaughtError(zone, e, s);
+ }
+ }
+ };
+ if (zoneSpecification == null) {
+ zoneSpecification =
+ new ZoneSpecification(handleUncaughtError: errorHandler);
+ } else {
+ zoneSpecification = new ZoneSpecification.from(zoneSpecification,
+ handleUncaughtError: errorHandler);
+ }
+ try {
+ return _runZoned<R>(body, zoneValues, zoneSpecification);
+ } catch (e, stackTrace) {
+ if (binaryOnError != null) {
+ binaryOnError(e, stackTrace);
+ } else {
+ assert(unaryOnError != null);
+ unaryOnError(e);
+ }
+ }
+ return null;
+}
+
+/// Runs [body] in a new zone based on [zoneValues] and [specification].
+R _runZoned<R>(R body(), Map zoneValues, ZoneSpecification specification) =>
+ Zone.current
+ .fork(specification: specification, zoneValues: zoneValues)
+ .run<R>(body);
diff --git a/sdk_nnbd/lib/cli/cli.dart b/sdk_nnbd/lib/cli/cli.dart
new file mode 100644
index 0000000..9c19c3a
--- /dev/null
+++ b/sdk_nnbd/lib/cli/cli.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// {@category VM}
+library dart.cli;
+
+import 'dart:async';
+import 'dart:math';
+
+part 'wait_for.dart';
diff --git a/sdk_nnbd/lib/cli/cli_sources.gni b/sdk_nnbd/lib/cli/cli_sources.gni
new file mode 100644
index 0000000..e90e1de
--- /dev/null
+++ b/sdk_nnbd/lib/cli/cli_sources.gni
@@ -0,0 +1,10 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+cli_sdk_sources = [
+ "cli.dart",
+
+ # The above file needs to be first if additional parts are added to the lib.
+ "wait_for.dart",
+]
diff --git a/sdk_nnbd/lib/cli/wait_for.dart b/sdk_nnbd/lib/cli/wait_for.dart
new file mode 100644
index 0000000..1886ff1
--- /dev/null
+++ b/sdk_nnbd/lib/cli/wait_for.dart
@@ -0,0 +1,152 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.cli;
+
+/**
+ * Synchronously blocks the calling isolate to wait for asynchronous events to
+ * complete.
+ *
+ * If the [timeout] parameter is supplied, [waitForEvent] will return after
+ * the specified timeout even if no events have occurred.
+ *
+ * This call does the following:
+ * - suspends the current execution stack,
+ * - runs the microtask queue until it is empty,
+ * - waits until the message queue is not empty,
+ * - handles messages on the message queue, plus their associated microtasks,
+ * until the message queue is empty,
+ * - resumes the original stack.
+ *
+ * This function breaks the usual promise offered by Dart semantics that
+ * message handlers and microtasks run to completion before the next message
+ * handler or microtask begins to run. Of particular note is that use of this
+ * function in a finally block will allow microtasks and message handlers to
+ * run before all finally blocks for an exception have completed, possibly
+ * breaking invariants in your program.
+ *
+ * This function will synchronously throw the first unhandled exception it
+ * encounters in running the microtasks and message handlers as though the
+ * throwing microtask or message handler was the only Dart invocation on the
+ * stack. That is, unhandled exceptions in a microtask or message handler will
+ * skip over stacks suspended in a call to [waitForEvent].
+ *
+ * Calls to this function may be nested. Earlier invocations will not
+ * be able to complete until subsequent ones do. Messages that arrive after
+ * a subsequent invocation are "consumed" by that invocation, and do not
+ * unblock an earlier invocation. Please be aware that nesting calls to
+ * [waitForEvent] can lead to deadlock when subsequent calls block to wait for
+ * a condition that is only satisfied after an earlier call returns.
+ *
+ * Please note that this call is only available in the standalone command-line
+ * Dart VM. Further, because it suspends the current execution stack until the
+ * message queue is empty, even when running in the standalone command-line VM
+ * there exists a risk that the current execution stack will be starved.
+ */
+external void _waitForEvent(int timeoutMillis);
+
+@pragma("vm:entry-point")
+void Function(int) _getWaitForEvent() => _waitForEvent;
+
+// This should be set from C++ code by the embedder to wire up waitFor() to the
+// native implementation. In the standalone VM this is set to _waitForEvent()
+// above. If it is null, calling waitFor() will throw an UnsupportedError.
+@pragma("vm:entry-point")
+void Function(int) _waitForEventClosure;
+
+class _WaitForUtils {
+ static void waitForEvent({Duration timeout}) {
+ if (_waitForEventClosure == null) {
+ throw new UnsupportedError("waitFor is not supported by this embedder");
+ }
+ _waitForEventClosure(timeout == null ? 0 : max(1, timeout.inMilliseconds));
+ }
+}
+
+/**
+ * Suspends the stack, runs microtasks, and handles incoming events until
+ * [future] completes.
+ *
+ * WARNING: EXPERIMENTAL. USE AT YOUR OWN RISK.
+ *
+ * This call does the following:
+ * - While [future] is not completed:
+ * - suspends the current execution stack,
+ * - runs the microtask queue until it is empty,
+ * - waits until the message queue is not empty,
+ * - handles messages on the message queue, plus their associated microtasks,
+ * until the message queue is empty,
+ * - resumes the original stack.
+ *
+ * This function breaks the usual promise offered by Dart semantics that
+ * message handlers and microtasks run to completion before the next message
+ * handler or microtask begins to run. Of particular note is that use of this
+ * function in a finally block will allow microtasks and message handlers to
+ * run before all finally blocks for an exception have completed, possibly
+ * breaking invariants in your program.
+ *
+ * Use of this function should be considered a last resort when it is not
+ * possible to convert a Dart program entirely to an asynchronous style using
+ * `async` and `await`.
+ *
+ * If the [Future] completes normally, its result is returned. If the [Future]
+ * completes with an error, the error and stack trace are wrapped in an
+ * [AsyncError] and thrown. If a microtask or message handler run during this
+ * call results in an unhandled exception, that exception will be propagated
+ * as though the microtask or message handler was the only Dart invocation on
+ * the stack. That is, unhandled exceptions in a microtask or message handler
+ * will skip over stacks suspended in a call to [waitFor].
+ *
+ * If the optional `timeout` parameter is passed, [waitFor] throws a
+ * [TimeoutException] if the [Future] is not completed within the specified
+ * period.
+ *
+ * Calls to [waitFor] may be nested. Earlier invocations will not complete
+ * until subsequent ones do, but the completion of a subsequent invocation will
+ * cause the previous invocation to wake up and check its [Future] for
+ * completion.
+ *
+ * Please be aware that nesting calls to [waitFor] can lead to deadlock if
+ * subsequent calls block waiting for a condition that is only satisfied when
+ * an earlier call returns.
+ */
+T waitFor<T>(Future<T> future, {Duration timeout}) {
+ T result;
+ bool futureCompleted = false;
+ Object error;
+ StackTrace stacktrace;
+ future.then((r) {
+ futureCompleted = true;
+ result = r;
+ }, onError: (e, st) {
+ error = e;
+ stacktrace = st;
+ });
+
+ Stopwatch s;
+ if (timeout != null) {
+ s = new Stopwatch()..start();
+ }
+ Timer.run(() {}); // Enusre there is at least one message.
+ while (!futureCompleted && (error == null)) {
+ Duration remaining;
+ if (timeout != null) {
+ if (s.elapsed >= timeout) {
+ throw new TimeoutException("waitFor() timed out", timeout);
+ }
+ remaining = timeout - s.elapsed;
+ }
+ _WaitForUtils.waitForEvent(timeout: remaining);
+ }
+ if (timeout != null) {
+ s.stop();
+ }
+ Timer.run(() {}); // Ensure that previous calls to waitFor are woken up.
+
+ if (error != null) {
+ throw new AsyncError(error, stacktrace);
+ }
+
+ return result;
+}
diff --git a/sdk_nnbd/lib/collection/collection.dart b/sdk_nnbd/lib/collection/collection.dart
new file mode 100644
index 0000000..b050a48
--- /dev/null
+++ b/sdk_nnbd/lib/collection/collection.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Classes and utilities that supplement the collection support in dart:core.
+///
+/// To use this library in your code:
+///
+/// import 'dart:collection';
+///
+/// {@category Core}
+library dart.collection;
+
+import 'dart:_internal' hide Symbol;
+import 'dart:math' show Random; // Used by ListMixin.shuffle.
+
+part 'collections.dart';
+part 'hash_map.dart';
+part 'hash_set.dart';
+part 'iterable.dart';
+part 'iterator.dart';
+part 'linked_hash_map.dart';
+part 'linked_hash_set.dart';
+part 'linked_list.dart';
+part 'list.dart';
+part 'maps.dart';
+part 'queue.dart';
+part 'set.dart';
+part 'splay_tree.dart';
diff --git a/sdk_nnbd/lib/collection/collection_sources.gni b/sdk_nnbd/lib/collection/collection_sources.gni
new file mode 100644
index 0000000..3f2f19e
--- /dev/null
+++ b/sdk_nnbd/lib/collection/collection_sources.gni
@@ -0,0 +1,23 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# This file contains all sources for the dart:collection library.
+collection_sdk_sources = [
+ "collection.dart",
+
+ # The above file needs to be first as it lists the parts below.
+ "collections.dart",
+ "hash_map.dart",
+ "hash_set.dart",
+ "iterable.dart",
+ "iterator.dart",
+ "linked_hash_map.dart",
+ "linked_hash_set.dart",
+ "linked_list.dart",
+ "list.dart",
+ "maps.dart",
+ "queue.dart",
+ "set.dart",
+ "splay_tree.dart",
+]
diff --git a/sdk_nnbd/lib/collection/collections.dart b/sdk_nnbd/lib/collection/collections.dart
new file mode 100644
index 0000000..9b43996
--- /dev/null
+++ b/sdk_nnbd/lib/collection/collections.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// An unmodifiable [List] view of another List.
+///
+/// The source of the elements may be a [List] or any [Iterable] with
+/// efficient [Iterable.length] and [Iterable.elementAt].
+class UnmodifiableListView<E> extends UnmodifiableListBase<E> {
+ final Iterable<E> _source;
+
+ /// Creates an unmodifiable list backed by [source].
+ ///
+ /// The [source] of the elements may be a [List] or any [Iterable] with
+ /// efficient [Iterable.length] and [Iterable.elementAt].
+ UnmodifiableListView(Iterable<E> source) : _source = source;
+
+ List<R> cast<R>() => UnmodifiableListView(_source.cast<R>());
+ int get length => _source.length;
+
+ E operator [](int index) => _source.elementAt(index);
+}
diff --git a/sdk_nnbd/lib/collection/hash_map.dart b/sdk_nnbd/lib/collection/hash_map.dart
new file mode 100644
index 0000000..525f43a
--- /dev/null
+++ b/sdk_nnbd/lib/collection/hash_map.dart
@@ -0,0 +1,156 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// Default function for equality comparison in customized HashMaps
+bool _defaultEquals(a, b) => a == b;
+
+/// Default function for hash-code computation in customized HashMaps
+int _defaultHashCode(a) => a.hashCode;
+
+/// Type of custom equality function
+typedef _Equality<K> = bool Function(K a, K b);
+
+/// Type of custom hash code function.
+typedef _Hasher<K> = int Function(K object);
+
+/// A hash-table based implementation of [Map].
+///
+/// The keys of a `HashMap` must have consistent [Object.==]
+/// and [Object.hashCode] implementations. This means that the `==` operator
+/// must define a stable equivalence relation on the keys (reflexive,
+/// symmetric, transitive, and consistent over time), and that `hashCode`
+/// must be the same for objects that are considered equal by `==`.
+///
+/// The map allows `null` as a key.
+///
+/// Iterating the map's keys, values or entries (through [forEach])
+/// may happen in any order.
+/// The iteration order only changes when the map is modified.
+/// Values are iterated in the same order as their associated keys,
+/// so iterating the [keys] and [values] in parallel
+/// will give matching key and value pairs.
+abstract class HashMap<K, V> implements Map<K, V> {
+ /// Creates an unordered hash-table based [Map].
+ ///
+ /// The created map is not ordered in any way. When iterating the keys or
+ /// values, the iteration order is unspecified except that it will stay the
+ /// same as long as the map isn't changed.
+ ///
+ /// If [equals] is provided, it is used to compare the keys in the table with
+ /// new keys. If [equals] is omitted, the key's own [Object.==] is used
+ /// instead.
+ ///
+ /// Similar, if [hashCode] is provided, it is used to produce a hash value
+ /// for keys in order to place them in the hash table. If it is omitted, the
+ /// key's own [Object.hashCode] is used.
+ ///
+ /// If using methods like [operator []], [remove] and [containsKey] together
+ /// with a custom equality and hashcode, an extra `isValidKey` function
+ /// can be supplied. This function is called before calling [equals] or
+ /// [hashCode] with an argument that may not be a [K] instance, and if the
+ /// call returns false, the key is assumed to not be in the set.
+ /// The [isValidKey] function defaults to just testing if the object is a
+ /// [K] instance.
+ ///
+ /// Example:
+ ///
+ /// new HashMap<int,int>(equals: (int a, int b) => (b - a) % 5 == 0,
+ /// hashCode: (int e) => e % 5)
+ ///
+ /// This example map does not need an `isValidKey` function to be passed.
+ /// The default function accepts only `int` values, which can safely be
+ /// passed to both the `equals` and `hashCode` functions.
+ ///
+ /// If neither `equals`, `hashCode`, nor `isValidKey` is provided,
+ /// the default `isValidKey` instead accepts all keys.
+ /// The default equality and hashcode operations are assumed to work on all
+ /// objects.
+ ///
+ /// Likewise, if `equals` is [identical], `hashCode` is [identityHashCode]
+ /// and `isValidKey` is omitted, the resulting map is identity based,
+ /// and the `isValidKey` defaults to accepting all keys.
+ /// Such a map can be created directly using [HashMap.identity].
+ ///
+ /// The used `equals` and `hashCode` method should always be consistent,
+ /// so that if `equals(a, b)` then `hashCode(a) == hashCode(b)`. The hash
+ /// of an object, or what it compares equal to, should not change while the
+ /// object is a key in the map. If it does change, the result is
+ /// unpredictable.
+ ///
+ /// If you supply one of [equals] and [hashCode],
+ /// you should generally also to supply the other.
+ external factory HashMap(
+ {bool equals(K key1, K key2),
+ int hashCode(K key),
+ bool isValidKey(potentialKey)});
+
+ /// Creates an unordered identity-based map.
+ ///
+ /// Effectively a shorthand for:
+ ///
+ /// new HashMap<K, V>(equals: identical,
+ /// hashCode: identityHashCode)
+ external factory HashMap.identity();
+
+ /// Creates a [HashMap] that contains all key/value pairs of [other].
+ ///
+ /// The keys must all be instances of [K] and the values of [V].
+ /// The [other] map itself can have any type.
+ factory HashMap.from(Map other) {
+ Map<K, V> result = HashMap<K, V>();
+ other.forEach((k, v) {
+ result[k] = v;
+ });
+ return result;
+ }
+
+ /// Creates a [HashMap] that contains all key/value pairs of [other].
+ factory HashMap.of(Map<K, V> other) => HashMap<K, V>()..addAll(other);
+
+ /// Creates a [HashMap] where the keys and values are computed from the
+ /// [iterable].
+ ///
+ /// For each element of the [iterable] this constructor computes a key/value
+ /// pair, by applying [key] and [value] respectively.
+ ///
+ /// The keys of the key/value pairs do not need to be unique. The last
+ /// occurrence of a key will simply overwrite any previous value.
+ ///
+ /// If no values are specified for [key] and [value] the default is the
+ /// identity function.
+ factory HashMap.fromIterable(Iterable iterable,
+ {K key(element), V value(element)}) {
+ Map<K, V> map = HashMap<K, V>();
+ MapBase._fillMapWithMappedIterable(map, iterable, key, value);
+ return map;
+ }
+
+ /// Creates a [HashMap] associating the given [keys] to [values].
+ ///
+ /// This constructor iterates over [keys] and [values] and maps each element
+ /// of [keys] to the corresponding element of [values].
+ ///
+ /// If [keys] contains the same object multiple times, the last occurrence
+ /// overwrites the previous value.
+ ///
+ /// It is an error if the two [Iterable]s don't have the same length.
+ factory HashMap.fromIterables(Iterable<K> keys, Iterable<V> values) {
+ Map<K, V> map = HashMap<K, V>();
+ MapBase._fillMapWithIterables(map, keys, values);
+ return map;
+ }
+
+ /// Creates a [HashMap] containing the entries of [entries].
+ ///
+ /// Returns a new `HashMap<K, V>` where all entries of [entries]
+ /// have been added in iteration order.
+ ///
+ /// If multiple [entries] have the same key,
+ /// later occurrences overwrite the earlier ones.
+ @Since("2.1")
+ factory HashMap.fromEntries(Iterable<MapEntry<K, V>> entries) =>
+ HashMap<K, V>()..addEntries(entries);
+}
diff --git a/sdk_nnbd/lib/collection/hash_set.dart b/sdk_nnbd/lib/collection/hash_set.dart
new file mode 100644
index 0000000..3fd00fe
--- /dev/null
+++ b/sdk_nnbd/lib/collection/hash_set.dart
@@ -0,0 +1,115 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// An unordered hash-table based [Set] implementation.
+///
+/// The elements of a `HashSet` must have consistent equality
+/// and hashCode implementations. This means that the equals operation
+/// must define a stable equivalence relation on the elements (reflexive,
+/// symmetric, transitive, and consistent over time), and that the hashCode
+/// must consistent with equality, so that the same for objects that are
+/// considered equal.
+///
+/// The set allows `null` as an element.
+///
+/// Most simple operations on `HashSet` are done in (potentially amortized)
+/// constant time: [add], [contains], [remove], and [length], provided the hash
+/// codes of objects are well distributed.
+///
+/// The iteration order of the set is not specified and depends on
+/// the hashcodes of the provided elements. However, the order is stable:
+/// multiple iterations over the same set produce the same order, as long as
+/// the set is not modified.
+abstract class HashSet<E> implements Set<E> {
+ /// Create a hash set using the provided [equals] as equality.
+ ///
+ /// The provided [equals] must define a stable equivalence relation, and
+ /// [hashCode] must be consistent with [equals]. If the [equals] or [hashCode]
+ /// methods won't work on all objects, but only on some instances of E, the
+ /// [isValidKey] predicate can be used to restrict the keys that the functions
+ /// are applied to.
+ /// Any key for which [isValidKey] returns false is automatically assumed
+ /// to not be in the set when asking `contains`.
+ ///
+ /// If [equals] or [hashCode] are omitted, the set uses
+ /// the elements' intrinsic [Object.==] and [Object.hashCode].
+ ///
+ /// If you supply one of [equals] and [hashCode],
+ /// you should generally also to supply the other.
+ ///
+ /// If the supplied `equals` or `hashCode` functions won't work on all [E]
+ /// objects, and the map will be used in a setting where a non-`E` object
+ /// is passed to, e.g., `contains`, then the [isValidKey] function should
+ /// also be supplied.
+ ///
+ /// If [isValidKey] is omitted, it defaults to testing if the object is an
+ /// [E] instance. That means that:
+ ///
+ /// new HashSet<int>(equals: (int e1, int e2) => (e1 - e2) % 5 == 0,
+ /// hashCode: (int e) => e % 5)
+ ///
+ /// does not need an `isValidKey` argument, because it defaults to only
+ /// accepting `int` values which are accepted by both `equals` and `hashCode`.
+ ///
+ /// If neither `equals`, `hashCode`, nor `isValidKey` is provided,
+ /// the default `isValidKey` instead accepts all values.
+ /// The default equality and hashcode operations are assumed to work on all
+ /// objects.
+ ///
+ /// Likewise, if `equals` is [identical], `hashCode` is [identityHashCode]
+ /// and `isValidKey` is omitted, the resulting set is identity based,
+ /// and the `isValidKey` defaults to accepting all keys.
+ /// Such a map can be created directly using [HashSet.identity].
+ external factory HashSet(
+ {bool equals(E e1, E e2),
+ int hashCode(E e),
+ bool isValidKey(potentialKey)});
+
+ /// Creates an unordered identity-based set.
+ ///
+ /// Effectively a shorthand for:
+ ///
+ /// new HashSet<E>(equals: identical,
+ /// hashCode: identityHashCode)
+ external factory HashSet.identity();
+
+ /// Create a hash set containing all [elements].
+ ///
+ /// Creates a hash set as by `new HashSet<E>()` and adds all given [elements]
+ /// to the set. The elements are added in order. If [elements] contains
+ /// two entries that are equal, but not identical, then the first one is
+ /// the one in the resulting set.
+ ///
+ /// All the [elements] should be instances of [E].
+ /// The `elements` iterable itself may have any element type, so this
+ /// constructor can be used to down-cast a `Set`, for example as:
+ /// ```dart
+ /// Set<SuperType> superSet = ...;
+ /// Set<SubType> subSet =
+ /// new HashSet<SubType>.from(superSet.whereType<SubType>());
+ /// ```
+ factory HashSet.from(Iterable elements) {
+ HashSet<E> result = HashSet<E>();
+ for (final e in elements) {
+ result.add(e);
+ }
+ return result;
+ }
+
+ /// Create a hash set containing all [elements].
+ ///
+ /// Creates a hash set as by `new HashSet<E>()` and adds all given [elements]
+ /// to the set. The elements are added in order. If [elements] contains
+ /// two entries that are equal, but not identical, then the first one is
+ /// the one in the resulting set.
+ factory HashSet.of(Iterable<E> elements) => HashSet<E>()..addAll(elements);
+
+ /// Provides an iterator that iterates over the elements of this set.
+ ///
+ /// The order of iteration is unspecified,
+ /// but consistent between changes to the set.
+ Iterator<E> get iterator;
+}
diff --git a/sdk_nnbd/lib/collection/iterable.dart b/sdk_nnbd/lib/collection/iterable.dart
new file mode 100644
index 0000000..14e7226
--- /dev/null
+++ b/sdk_nnbd/lib/collection/iterable.dart
@@ -0,0 +1,402 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// This [Iterable] mixin implements all [Iterable] members except `iterator`.
+///
+/// All other methods are implemented in terms of `iterator`.
+abstract class IterableMixin<E> implements Iterable<E> {
+ // This class has methods copied verbatim into:
+ // - IterableBase
+ // - SetMixin
+ // If changing a method here, also change the other copies.
+
+ Iterable<R> cast<R>() => Iterable.castFrom<E, R>(this);
+ Iterable<T> map<T>(T f(E element)) => MappedIterable<E, T>(this, f);
+
+ Iterable<E> where(bool f(E element)) => WhereIterable<E>(this, f);
+
+ Iterable<T> whereType<T>() => WhereTypeIterable<T>(this);
+
+ Iterable<T> expand<T>(Iterable<T> f(E element)) =>
+ ExpandIterable<E, T>(this, f);
+
+ Iterable<E> followedBy(Iterable<E> other) {
+ // Type workaround because IterableMixin<E> doesn't promote
+ // to EfficientLengthIterable<E>.
+ Iterable<E> self = this;
+ if (self is EfficientLengthIterable<E>) {
+ return FollowedByIterable<E>.firstEfficient(self, other);
+ }
+ return FollowedByIterable<E>(this, other);
+ }
+
+ bool contains(Object element) {
+ for (E e in this) {
+ if (e == element) return true;
+ }
+ return false;
+ }
+
+ void forEach(void f(E element)) {
+ for (E element in this) f(element);
+ }
+
+ E reduce(E combine(E value, E element)) {
+ Iterator<E> iterator = this.iterator;
+ if (!iterator.moveNext()) {
+ throw IterableElementError.noElement();
+ }
+ E value = iterator.current;
+ while (iterator.moveNext()) {
+ value = combine(value, iterator.current);
+ }
+ return value;
+ }
+
+ T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+ var value = initialValue;
+ for (E element in this) value = combine(value, element);
+ return value;
+ }
+
+ bool every(bool f(E element)) {
+ for (E element in this) {
+ if (!f(element)) return false;
+ }
+ return true;
+ }
+
+ String join([String separator = ""]) {
+ Iterator<E> iterator = this.iterator;
+ if (!iterator.moveNext()) return "";
+ StringBuffer buffer = StringBuffer();
+ if (separator == null || separator == "") {
+ do {
+ buffer.write("${iterator.current}");
+ } while (iterator.moveNext());
+ } else {
+ buffer.write("${iterator.current}");
+ while (iterator.moveNext()) {
+ buffer.write(separator);
+ buffer.write("${iterator.current}");
+ }
+ }
+ return buffer.toString();
+ }
+
+ bool any(bool test(E element)) {
+ for (E element in this) {
+ if (test(element)) return true;
+ }
+ return false;
+ }
+
+ List<E> toList({bool growable = true}) =>
+ List<E>.from(this, growable: growable);
+
+ Set<E> toSet() => Set<E>.from(this);
+
+ int get length {
+ assert(this is! EfficientLengthIterable);
+ int count = 0;
+ Iterator it = iterator;
+ while (it.moveNext()) {
+ count++;
+ }
+ return count;
+ }
+
+ bool get isEmpty => !iterator.moveNext();
+
+ bool get isNotEmpty => !isEmpty;
+
+ Iterable<E> take(int count) {
+ return TakeIterable<E>(this, count);
+ }
+
+ Iterable<E> takeWhile(bool test(E value)) {
+ return TakeWhileIterable<E>(this, test);
+ }
+
+ Iterable<E> skip(int count) {
+ return SkipIterable<E>(this, count);
+ }
+
+ Iterable<E> skipWhile(bool test(E value)) {
+ return SkipWhileIterable<E>(this, test);
+ }
+
+ E get first {
+ Iterator<E> it = iterator;
+ if (!it.moveNext()) {
+ throw IterableElementError.noElement();
+ }
+ return it.current;
+ }
+
+ E get last {
+ Iterator<E> it = iterator;
+ if (!it.moveNext()) {
+ throw IterableElementError.noElement();
+ }
+ E result;
+ do {
+ result = it.current;
+ } while (it.moveNext());
+ return result;
+ }
+
+ E get single {
+ Iterator<E> it = iterator;
+ if (!it.moveNext()) throw IterableElementError.noElement();
+ E result = it.current;
+ if (it.moveNext()) throw IterableElementError.tooMany();
+ return result;
+ }
+
+ E firstWhere(bool test(E value), {E orElse()}) {
+ for (E element in this) {
+ if (test(element)) return element;
+ }
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E lastWhere(bool test(E value), {E orElse()}) {
+ E result;
+ bool foundMatching = false;
+ for (E element in this) {
+ if (test(element)) {
+ result = element;
+ foundMatching = true;
+ }
+ }
+ if (foundMatching) return result;
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E singleWhere(bool test(E element), {E orElse()}) {
+ E result;
+ bool foundMatching = false;
+ for (E element in this) {
+ if (test(element)) {
+ if (foundMatching) {
+ throw IterableElementError.tooMany();
+ }
+ result = element;
+ foundMatching = true;
+ }
+ }
+ if (foundMatching) return result;
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E elementAt(int index) {
+ ArgumentError.checkNotNull(index, "index");
+ RangeError.checkNotNegative(index, "index");
+ int elementIndex = 0;
+ for (E element in this) {
+ if (index == elementIndex) return element;
+ elementIndex++;
+ }
+ throw RangeError.index(index, this, "index", null, elementIndex);
+ }
+
+ String toString() => IterableBase.iterableToShortString(this, '(', ')');
+}
+
+/// Base class for implementing [Iterable].
+///
+/// This class implements all methods of [Iterable], except [Iterable.iterator],
+/// in terms of `iterator`.
+abstract class IterableBase<E> extends Iterable<E> {
+ const IterableBase();
+
+ /// Convert an `Iterable` to a string like [IterableBase.toString].
+ ///
+ /// Allows using other delimiters than '(' and ')'.
+ ///
+ /// Handles circular references where converting one of the elements
+ /// to a string ends up converting [iterable] to a string again.
+ static String iterableToShortString(Iterable iterable,
+ [String leftDelimiter = '(', String rightDelimiter = ')']) {
+ if (_isToStringVisiting(iterable)) {
+ if (leftDelimiter == "(" && rightDelimiter == ")") {
+ // Avoid creating a new string in the "common" case.
+ return "(...)";
+ }
+ return "$leftDelimiter...$rightDelimiter";
+ }
+ List<String> parts = <String>[];
+ _toStringVisiting.add(iterable);
+ try {
+ _iterablePartsToStrings(iterable, parts);
+ } finally {
+ assert(identical(_toStringVisiting.last, iterable));
+ _toStringVisiting.removeLast();
+ }
+ return (StringBuffer(leftDelimiter)
+ ..writeAll(parts, ", ")
+ ..write(rightDelimiter))
+ .toString();
+ }
+
+ /// Converts an `Iterable` to a string.
+ ///
+ /// Converts each elements to a string, and separates the results by ", ".
+ /// Then wraps the result in [leftDelimiter] and [rightDelimiter].
+ ///
+ /// Unlike [iterableToShortString], this conversion doesn't omit any
+ /// elements or puts any limit on the size of the result.
+ ///
+ /// Handles circular references where converting one of the elements
+ /// to a string ends up converting [iterable] to a string again.
+ static String iterableToFullString(Iterable iterable,
+ [String leftDelimiter = '(', String rightDelimiter = ')']) {
+ if (_isToStringVisiting(iterable)) {
+ return "$leftDelimiter...$rightDelimiter";
+ }
+ StringBuffer buffer = StringBuffer(leftDelimiter);
+ _toStringVisiting.add(iterable);
+ try {
+ buffer.writeAll(iterable, ", ");
+ } finally {
+ assert(identical(_toStringVisiting.last, iterable));
+ _toStringVisiting.removeLast();
+ }
+ buffer.write(rightDelimiter);
+ return buffer.toString();
+ }
+}
+
+/// A collection used to identify cyclic lists during toString() calls.
+final List _toStringVisiting = [];
+
+/// Check if we are currently visiting `o` in a toString call.
+bool _isToStringVisiting(Object o) {
+ for (int i = 0; i < _toStringVisiting.length; i++) {
+ if (identical(o, _toStringVisiting[i])) return true;
+ }
+ return false;
+}
+
+/// Convert elements of [iterable] to strings and store them in [parts].
+void _iterablePartsToStrings(Iterable iterable, List<String> parts) {
+ /*
+ * This is the complicated part of [iterableToShortString].
+ * It is extracted as a separate function to avoid having too much code
+ * inside the try/finally.
+ */
+ /// Try to stay below this many characters.
+ const int lengthLimit = 80;
+
+ /// Always at least this many elements at the start.
+ const int headCount = 3;
+
+ /// Always at least this many elements at the end.
+ const int tailCount = 2;
+
+ /// Stop iterating after this many elements. Iterables can be infinite.
+ const int maxCount = 100;
+ // Per entry length overhead. It's for ", " for all after the first entry,
+ // and for "(" and ")" for the initial entry. By pure luck, that's the same
+ // number.
+ const int overhead = 2;
+ const int ellipsisSize = 3; // "...".length.
+
+ int length = 0;
+ int count = 0;
+ Iterator it = iterable.iterator;
+ // Initial run of elements, at least headCount, and then continue until
+ // passing at most lengthLimit characters.
+ while (length < lengthLimit || count < headCount) {
+ if (!it.moveNext()) return;
+ String next = "${it.current}";
+ parts.add(next);
+ length += next.length + overhead;
+ count++;
+ }
+
+ String penultimateString;
+ String ultimateString;
+
+ // Find last two elements. One or more of them may already be in the
+ // parts array. Include their length in `length`.
+ Object penultimate;
+ Object ultimate;
+ if (!it.moveNext()) {
+ if (count <= headCount + tailCount) return;
+ ultimateString = parts.removeLast();
+ penultimateString = parts.removeLast();
+ } else {
+ penultimate = it.current;
+ count++;
+ if (!it.moveNext()) {
+ if (count <= headCount + 1) {
+ parts.add("$penultimate");
+ return;
+ }
+ ultimateString = "$penultimate";
+ penultimateString = parts.removeLast();
+ length += ultimateString.length + overhead;
+ } else {
+ ultimate = it.current;
+ count++;
+ // Then keep looping, keeping the last two elements in variables.
+ assert(count < maxCount);
+ while (it.moveNext()) {
+ penultimate = ultimate;
+ ultimate = it.current;
+ count++;
+ if (count > maxCount) {
+ // If we haven't found the end before maxCount, give up.
+ // This cannot happen in the code above because each entry
+ // increases length by at least two, so there is no way to
+ // visit more than ~40 elements before this loop.
+
+ // Remove any surplus elements until length, including ", ...)",
+ // is at most lengthLimit.
+ while (length > lengthLimit - ellipsisSize - overhead &&
+ count > headCount) {
+ length -= parts.removeLast().length + overhead;
+ count--;
+ }
+ parts.add("...");
+ return;
+ }
+ }
+ penultimateString = "$penultimate";
+ ultimateString = "$ultimate";
+ length += ultimateString.length + penultimateString.length + 2 * overhead;
+ }
+ }
+
+ // If there is a gap between the initial run and the last two,
+ // prepare to add an ellipsis.
+ String elision;
+ if (count > parts.length + tailCount) {
+ elision = "...";
+ length += ellipsisSize + overhead;
+ }
+
+ // If the last two elements were very long, and we have more than
+ // headCount elements in the initial run, drop some to make room for
+ // the last two.
+ while (length > lengthLimit && parts.length > headCount) {
+ length -= parts.removeLast().length + overhead;
+ if (elision == null) {
+ elision = "...";
+ length += ellipsisSize + overhead;
+ }
+ }
+ if (elision != null) {
+ parts.add(elision);
+ }
+ parts.add(penultimateString);
+ parts.add(ultimateString);
+}
diff --git a/sdk_nnbd/lib/collection/iterator.dart b/sdk_nnbd/lib/collection/iterator.dart
new file mode 100644
index 0000000..671f0ee
--- /dev/null
+++ b/sdk_nnbd/lib/collection/iterator.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// The [HasNextIterator] class wraps an [Iterator] and provides methods to
+/// iterate over an object using `hasNext` and `next`.
+///
+/// An [HasNextIterator] does not implement the [Iterator] interface.
+class HasNextIterator<E> {
+ static const int _HAS_NEXT_AND_NEXT_IN_CURRENT = 0;
+ static const int _NO_NEXT = 1;
+ static const int _NOT_MOVED_YET = 2;
+
+ Iterator<E> _iterator;
+ int _state = _NOT_MOVED_YET;
+
+ HasNextIterator(this._iterator);
+
+ bool get hasNext {
+ if (_state == _NOT_MOVED_YET) _move();
+ return _state == _HAS_NEXT_AND_NEXT_IN_CURRENT;
+ }
+
+ E next() {
+ // Call to hasNext is necessary to make sure we are positioned at the first
+ // element when we start iterating.
+ if (!hasNext) throw StateError("No more elements");
+ assert(_state == _HAS_NEXT_AND_NEXT_IN_CURRENT);
+ E result = _iterator.current;
+ _move();
+ return result;
+ }
+
+ void _move() {
+ if (_iterator.moveNext()) {
+ _state = _HAS_NEXT_AND_NEXT_IN_CURRENT;
+ } else {
+ _state = _NO_NEXT;
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/collection/linked_hash_map.dart b/sdk_nnbd/lib/collection/linked_hash_map.dart
new file mode 100644
index 0000000..e3a650d
--- /dev/null
+++ b/sdk_nnbd/lib/collection/linked_hash_map.dart
@@ -0,0 +1,141 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// A hash-table based implementation of [Map].
+///
+/// The insertion order of keys is remembered,
+/// and keys are iterated in the order they were inserted into the map.
+/// Values are iterated in their corresponding key's order.
+/// Changing a key's value, when the key is already in the map,
+/// does not change the iteration order,
+/// but removing the key and adding it again
+/// will make it be last in the iteration order.
+///
+/// The keys of a `LinkedHashMap` must have consistent [Object.==]
+/// and [Object.hashCode] implementations. This means that the `==` operator
+/// must define a stable equivalence relation on the keys (reflexive,
+/// symmetric, transitive, and consistent over time), and that `hashCode`
+/// must be the same for objects that are considered equal by `==`.
+///
+/// The map allows `null` as a key.
+abstract class LinkedHashMap<K, V> implements Map<K, V> {
+ /// Creates an insertion-ordered hash-table based [Map].
+ ///
+ /// If [equals] is provided, it is used to compare the keys in the table with
+ /// new keys. If [equals] is omitted, the key's own [Object.==] is used
+ /// instead.
+ ///
+ /// Similar, if [hashCode] is provided, it is used to produce a hash value
+ /// for keys in order to place them in the hash table. If it is omitted, the
+ /// key's own [Object.hashCode] is used.
+ ///
+ /// If using methods like [operator []], [remove] and [containsKey] together
+ /// with a custom equality and hashcode, an extra `isValidKey` function
+ /// can be supplied. This function is called before calling [equals] or
+ /// [hashCode] with an argument that may not be a [K] instance, and if the
+ /// call returns false, the key is assumed to not be in the set.
+ /// The [isValidKey] function defaults to just testing if the object is a
+ /// [K] instance.
+ ///
+ /// Example:
+ ///
+ /// new LinkedHashMap<int,int>(equals: (int a, int b) => (b - a) % 5 == 0,
+ /// hashCode: (int e) => e % 5)
+ ///
+ /// This example map does not need an `isValidKey` function to be passed.
+ /// The default function accepts only `int` values, which can safely be
+ /// passed to both the `equals` and `hashCode` functions.
+ ///
+ /// If neither `equals`, `hashCode`, nor `isValidKey` is provided,
+ /// the default `isValidKey` instead accepts all keys.
+ /// The default equality and hashcode operations are assumed to work on all
+ /// objects.
+ ///
+ /// Likewise, if `equals` is [identical], `hashCode` is [identityHashCode]
+ /// and `isValidKey` is omitted, the resulting map is identity based,
+ /// and the `isValidKey` defaults to accepting all keys.
+ /// Such a map can be created directly using [LinkedHashMap.identity].
+ ///
+ /// The used `equals` and `hashCode` method should always be consistent,
+ /// so that if `equals(a, b)` then `hashCode(a) == hashCode(b)`. The hash
+ /// of an object, or what it compares equal to, should not change while the
+ /// object is in the table. If it does change, the result is unpredictable.
+ ///
+ /// If you supply one of [equals] and [hashCode],
+ /// you should generally also to supply the other.
+ external factory LinkedHashMap(
+ {bool equals(K key1, K key2),
+ int hashCode(K key),
+ bool isValidKey(potentialKey)});
+
+ /// Creates an insertion-ordered identity-based map.
+ ///
+ /// Effectively a shorthand for:
+ ///
+ /// new LinkedHashMap<K, V>(equals: identical,
+ /// hashCode: identityHashCode)
+ external factory LinkedHashMap.identity();
+
+ /// Creates a [LinkedHashMap] that contains all key value pairs of [other].
+ ///
+ /// The keys must all be instances of [K] and the values to [V].
+ /// The [other] map itself can have any type.
+ factory LinkedHashMap.from(Map other) {
+ LinkedHashMap<K, V> result = LinkedHashMap<K, V>();
+ other.forEach((k, v) {
+ result[k] = v;
+ });
+ return result;
+ }
+
+ /// Creates a [LinkedHashMap] that contains all key value pairs of [other].
+ factory LinkedHashMap.of(Map<K, V> other) =>
+ LinkedHashMap<K, V>()..addAll(other);
+
+ /// Creates a [LinkedHashMap] where the keys and values are computed from the
+ /// [iterable].
+ ///
+ /// For each element of the [iterable] this constructor computes a key/value
+ /// pair, by applying [key] and [value] respectively.
+ ///
+ /// The keys of the key/value pairs do not need to be unique. The last
+ /// occurrence of a key will simply overwrite any previous value.
+ ///
+ /// If no values are specified for [key] and [value] the default is the
+ /// identity function.
+ factory LinkedHashMap.fromIterable(Iterable iterable,
+ {K key(element), V value(element)}) {
+ LinkedHashMap<K, V> map = LinkedHashMap<K, V>();
+ MapBase._fillMapWithMappedIterable(map, iterable, key, value);
+ return map;
+ }
+
+ /// Creates a [LinkedHashMap] associating the given [keys] to [values].
+ ///
+ /// This constructor iterates over [keys] and [values] and maps each element of
+ /// [keys] to the corresponding element of [values].
+ ///
+ /// If [keys] contains the same object multiple times, the last occurrence
+ /// overwrites the previous value.
+ ///
+ /// It is an error if the two [Iterable]s don't have the same length.
+ factory LinkedHashMap.fromIterables(Iterable<K> keys, Iterable<V> values) {
+ LinkedHashMap<K, V> map = LinkedHashMap<K, V>();
+ MapBase._fillMapWithIterables(map, keys, values);
+ return map;
+ }
+
+ /// Creates a [LinkedHashMap] containing the entries of [entries].
+ ///
+ /// Returns a new `LinkedHashMap<K, V>` where all entries of [entries]
+ /// have been added in iteration order.
+ ///
+ /// If multiple [entries] have the same key,
+ /// later occurrences overwrite the earlier ones.
+ @Since("2.1")
+ factory LinkedHashMap.fromEntries(Iterable<MapEntry<K, V>> entries) =>
+ <K, V>{}..addEntries(entries);
+}
diff --git a/sdk_nnbd/lib/collection/linked_hash_set.dart b/sdk_nnbd/lib/collection/linked_hash_set.dart
new file mode 100644
index 0000000..a058b5e
--- /dev/null
+++ b/sdk_nnbd/lib/collection/linked_hash_set.dart
@@ -0,0 +1,120 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// A [LinkedHashSet] is a hash-table based [Set] implementation.
+///
+/// The `LinkedHashSet` also keep track of the order that elements were inserted
+/// in, and iteration happens in first-to-last insertion order.
+///
+/// The elements of a `LinkedHashSet` must have consistent [Object.==]
+/// and [Object.hashCode] implementations. This means that the `==` operator
+/// must define a stable equivalence relation on the elements (reflexive,
+/// symmetric, transitive, and consistent over time), and that `hashCode`
+/// must be the same for objects that are considered equal by `==`.
+///
+/// The set allows `null` as an element.
+///
+/// Iteration of elements is done in element insertion order.
+/// An element that was added after another will occur later in the iteration.
+/// Adding an element that is already in the set
+/// does not change its position in the iteration order,
+/// but removing an element and adding it again,
+/// will make it the last element of an iteration.
+///
+/// Most simple operations on `HashSet` are done in (potentially amortized)
+/// constant time: [add], [contains], [remove], and [length], provided the hash
+/// codes of objects are well distributed..
+abstract class LinkedHashSet<E> implements Set<E> {
+ /// Create an insertion-ordered hash set using the provided
+ /// [equals] and [hashCode].
+ ///
+ /// The provided [equals] must define a stable equivalence relation, and
+ /// [hashCode] must be consistent with [equals]. If the [equals] or [hashCode]
+ /// methods won't work on all objects, but only on some instances of E, the
+ /// [isValidKey] predicate can be used to restrict the keys that the functions
+ /// are applied to.
+ /// Any key for which [isValidKey] returns false is automatically assumed
+ /// to not be in the set when asking `contains`.
+ ///
+ /// If [equals] or [hashCode] are omitted, the set uses
+ /// the elements' intrinsic [Object.==] and [Object.hashCode],
+ /// and [isValidKey] is ignored since these operations are assumed
+ /// to work on all objects.
+ ///
+ /// If you supply one of [equals] and [hashCode],
+ /// you should generally also to supply the other.
+ ///
+ /// If the supplied `equals` or `hashCode` functions won't work on all [E]
+ /// objects, and the map will be used in a setting where a non-`E` object
+ /// is passed to, e.g., `contains`, then the [isValidKey] function should
+ /// also be supplied.
+ ///
+ /// If [isValidKey] is omitted, it defaults to testing if the object is an
+ /// [E] instance. That means that:
+ ///
+ /// new LinkedHashSet<int>(equals: (int e1, int e2) => (e1 - e2) % 5 == 0,
+ /// hashCode: (int e) => e % 5)
+ ///
+ /// does not need an `isValidKey` argument, because it defaults to only
+ /// accepting `int` values which are accepted by both `equals` and `hashCode`.
+ ///
+ /// If neither `equals`, `hashCode`, nor `isValidKey` is provided,
+ /// the default `isValidKey` instead accepts all values.
+ /// The default equality and hashcode operations are assumed to work on all
+ /// objects.
+ ///
+ /// Likewise, if `equals` is [identical], `hashCode` is [identityHashCode]
+ /// and `isValidKey` is omitted, the resulting set is identity based,
+ /// and the `isValidKey` defaults to accepting all keys.
+ /// Such a map can be created directly using [LinkedHashSet.identity].
+ external factory LinkedHashSet(
+ {bool equals(E e1, E e2),
+ int hashCode(E e),
+ bool isValidKey(potentialKey)});
+
+ /// Creates an insertion-ordered identity-based set.
+ ///
+ /// Effectively a shorthand for:
+ ///
+ /// new LinkedHashSet<E>(equals: identical,
+ /// hashCode: identityHashCode)
+ external factory LinkedHashSet.identity();
+
+ /// Create a linked hash set containing all [elements].
+ ///
+ /// Creates a linked hash set as by `new LinkedHashSet<E>()` and adds each
+ /// element of `elements` to this set in the order they are iterated.
+ ///
+ /// All the [elements] should be instances of [E].
+ /// The `elements` iterable itself may have any element type,
+ /// so this constructor can be used to down-cast a `Set`, for example as:
+ ///
+ /// Set<SuperType> superSet = ...;
+ /// Iterable<SuperType> tmp = superSet.where((e) => e is SubType);
+ /// Set<SubType> subSet = new LinkedHashSet<SubType>.from(tmp);
+ factory LinkedHashSet.from(Iterable elements) {
+ LinkedHashSet<E> result = LinkedHashSet<E>();
+ for (final element in elements) {
+ result.add(element);
+ }
+ return result;
+ }
+
+ /// Create a linked hash set from [elements].
+ ///
+ /// Creates a linked hash set as by `new LinkedHashSet<E>()` and adds each
+ /// element of `elements` to this set in the order they are iterated.
+ factory LinkedHashSet.of(Iterable<E> elements) =>
+ LinkedHashSet<E>()..addAll(elements);
+
+ /// Executes a function on each element of the set.
+ ///
+ /// The elements are iterated in insertion order.
+ void forEach(void action(E element));
+
+ /// Provides an iterator that iterates over the elements in insertion order.
+ Iterator<E> get iterator;
+}
diff --git a/sdk_nnbd/lib/collection/linked_list.dart b/sdk_nnbd/lib/collection/linked_list.dart
new file mode 100644
index 0000000..91461cb
--- /dev/null
+++ b/sdk_nnbd/lib/collection/linked_list.dart
@@ -0,0 +1,263 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// A specialized double-linked list of elements that extends [LinkedListEntry].
+///
+/// This is not a generic data structure. It only accepts elements that extend
+/// the [LinkedListEntry] class. See the [Queue] implementations for generic
+/// collections that allow constant time adding and removing at the ends.
+///
+/// This is not a [List] implementation. Despite its name, this class does not
+/// implement the [List] interface. It does not allow constant time lookup by
+/// index.
+///
+/// Because the elements themselves contain the links of this linked list,
+/// each element can be in only one list at a time. To add an element to another
+/// list, it must first be removed from its current list (if any).
+///
+/// In return, each element knows its own place in the linked list, as well as
+/// which list it is in. This allows constant time
+/// [LinkedListEntry.insertAfter], [LinkedListEntry.insertBefore] and
+/// [LinkedListEntry.unlink] operations when all you have is the element.
+///
+/// A `LinkedList` also allows constant time adding and removing at either end,
+/// and a constant time length getter.
+class LinkedList<E extends LinkedListEntry<E>> extends Iterable<E> {
+ int _modificationCount = 0;
+ int _length = 0;
+ E _first;
+
+ /// Construct a new empty linked list.
+ LinkedList();
+
+ /// Add [entry] to the beginning of the linked list.
+ void addFirst(E entry) {
+ _insertBefore(_first, entry, updateFirst: true);
+ _first = entry;
+ }
+
+ /// Add [entry] to the end of the linked list.
+ void add(E entry) {
+ _insertBefore(_first, entry, updateFirst: false);
+ }
+
+ /// Add [entries] to the end of the linked list.
+ void addAll(Iterable<E> entries) {
+ entries.forEach(add);
+ }
+
+ /// Remove [entry] from the linked list.
+ ///
+ /// Returns false and does nothing if [entry] is not in this linked list.
+ ///
+ /// This is equivalent to calling `entry.unlink()` if the entry is in this
+ /// list.
+ bool remove(E entry) {
+ if (entry._list != this) return false;
+ _unlink(entry); // Unlink will decrement length.
+ return true;
+ }
+
+ Iterator<E> get iterator => _LinkedListIterator<E>(this);
+
+ int get length => _length;
+
+ /// Remove all elements from this linked list.
+ void clear() {
+ _modificationCount++;
+ if (isEmpty) return;
+
+ E next = _first;
+ do {
+ E entry = next;
+ next = entry._next;
+ entry._next = entry._previous = entry._list = null;
+ } while (!identical(next, _first));
+
+ _first = null;
+ _length = 0;
+ }
+
+ E get first {
+ if (isEmpty) {
+ throw StateError('No such element');
+ }
+ return _first;
+ }
+
+ E get last {
+ if (isEmpty) {
+ throw StateError('No such element');
+ }
+ return _first._previous;
+ }
+
+ E get single {
+ if (isEmpty) {
+ throw StateError('No such element');
+ }
+ if (_length > 1) {
+ throw StateError('Too many elements');
+ }
+ return _first;
+ }
+
+ /// Call [action] with each entry in this linked list.
+ ///
+ /// It's an error if [action] modify the linked list.
+ void forEach(void action(E entry)) {
+ int modificationCount = _modificationCount;
+ if (isEmpty) return;
+
+ E current = _first;
+ do {
+ action(current);
+ if (modificationCount != _modificationCount) {
+ throw ConcurrentModificationError(this);
+ }
+ current = current._next;
+ } while (!identical(current, _first));
+ }
+
+ bool get isEmpty => _length == 0;
+
+ /// Inserts [newEntry] as last entry of the list.
+ ///
+ /// If [updateFirst] is true and [entry] is the first entry in the list,
+ /// updates the [_first] field to point to the [newEntry] as first entry.
+ void _insertBefore(E entry, E newEntry, {bool updateFirst}) {
+ if (newEntry.list != null) {
+ throw StateError('LinkedListEntry is already in a LinkedList');
+ }
+ _modificationCount++;
+
+ newEntry._list = this;
+ if (isEmpty) {
+ assert(entry == null);
+ newEntry._previous = newEntry._next = newEntry;
+ _first = newEntry;
+ _length++;
+ return;
+ }
+ E predecessor = entry._previous;
+ E successor = entry;
+ newEntry._previous = predecessor;
+ newEntry._next = successor;
+ predecessor._next = newEntry;
+ successor._previous = newEntry;
+ if (updateFirst && identical(entry, _first)) {
+ _first = newEntry;
+ }
+ _length++;
+ }
+
+ void _unlink(E entry) {
+ _modificationCount++;
+ entry._next._previous = entry._previous;
+ E next = entry._previous._next = entry._next;
+ _length--;
+ entry._list = entry._next = entry._previous = null;
+ if (isEmpty) {
+ _first = null;
+ } else if (identical(entry, _first)) {
+ _first = next;
+ }
+ }
+}
+
+class _LinkedListIterator<E extends LinkedListEntry<E>> implements Iterator<E> {
+ final LinkedList<E> _list;
+ final int _modificationCount;
+ E _current;
+ LinkedListEntry<E> _next;
+ bool _visitedFirst;
+
+ _LinkedListIterator(LinkedList<E> list)
+ : _list = list,
+ _modificationCount = list._modificationCount,
+ _next = list._first,
+ _visitedFirst = false;
+
+ E get current => _current;
+
+ bool moveNext() {
+ if (_modificationCount != _list._modificationCount) {
+ throw ConcurrentModificationError(this);
+ }
+ if (_list.isEmpty || (_visitedFirst && identical(_next, _list.first))) {
+ _current = null;
+ return false;
+ }
+ _visitedFirst = true;
+ _current = _next;
+ _next = _next._next;
+ return true;
+ }
+}
+
+/// An object that can be an element in a [LinkedList].
+///
+/// All elements of a `LinkedList` must extend this class.
+/// The class provides the internal links that link elements together
+/// in the `LinkedList`, and a reference to the linked list itself
+/// that an element is currently part of.
+///
+/// An entry can be in at most one linked list at a time.
+/// While an entry is in a linked list, the [list] property points to that
+/// linked list, and otherwise the `list` property is `null`.
+///
+/// When created, an entry is not in any linked list.
+abstract class LinkedListEntry<E extends LinkedListEntry<E>> {
+ LinkedList<E> _list;
+ E _next;
+ E _previous;
+
+ /// Get the linked list containing this element.
+ ///
+ /// Returns `null` if this entry is not currently in any list.
+ LinkedList<E> get list => _list;
+
+ /// Unlink the element from its linked list.
+ ///
+ /// The entry must currently be in a linked list when this method is called.
+ void unlink() {
+ _list._unlink(this);
+ }
+
+ /// Return the successor of this element in its linked list.
+ ///
+ /// Returns `null` if there is no successor in the linked list, or if this
+ /// entry is not currently in any list.
+ E get next {
+ if (_list == null || identical(_list.first, _next)) return null;
+ return _next;
+ }
+
+ /// Return the predecessor of this element in its linked list.
+ ///
+ /// Returns `null` if there is no predecessor in the linked list, or if this
+ /// entry is not currently in any list.
+ E get previous {
+ if (_list == null || identical(this, _list.first)) return null;
+ return _previous;
+ }
+
+ /// Insert an element after this element in this element's linked list.
+ ///
+ /// This entry must be in a linked list when this method is called.
+ /// The [entry] must not be in a linked list.
+ void insertAfter(E entry) {
+ _list._insertBefore(_next, entry, updateFirst: false);
+ }
+
+ /// Insert an element before this element in this element's linked list.
+ ///
+ /// This entry must be in a linked list when this method is called.
+ /// The [entry] must not be in a linked list.
+ void insertBefore(E entry) {
+ _list._insertBefore(this, entry, updateFirst: true);
+ }
+}
diff --git a/sdk_nnbd/lib/collection/list.dart b/sdk_nnbd/lib/collection/list.dart
new file mode 100644
index 0000000..1d83aa4
--- /dev/null
+++ b/sdk_nnbd/lib/collection/list.dart
@@ -0,0 +1,535 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// Abstract implementation of a list.
+///
+/// `ListBase` can be used as a base class for implementing the `List`
+/// interface.
+///
+/// All operations are defined in terms of `length`, `operator[]`,
+/// `operator[]=` and `length=`, which need to be implemented.
+///
+/// *NOTICE*: Forwarding just these four operations to a normal growable [List]
+/// (as created by `new List()`) will give very bad performance for `add` and
+/// `addAll` operations of `ListBase`. These operations are implemented by
+/// increasing the length of the list by one for each `add` operation, and
+/// repeatedly increasing the length of a growable list is not efficient.
+/// To avoid this, either override 'add' and 'addAll' to also forward directly
+/// to the growable list, or, preferably, use `DelegatingList` from
+/// "package:collection/wrappers.dart" instead.
+abstract class ListBase<E> extends Object with ListMixin<E> {
+ /// Convert a `List` to a string as `[each, element, as, string]`.
+ ///
+ /// Handles circular references where converting one of the elements
+ /// to a string ends up converting [list] to a string again.
+ static String listToString(List list) =>
+ IterableBase.iterableToFullString(list, '[', ']');
+}
+
+/// Base implementation of a [List] class.
+///
+/// `ListMixin` can be used as a mixin to make a class implement
+/// the `List` interface.
+///
+/// This implements all read operations using only the `length` and
+/// `operator[]` members. It implements write operations using those and
+/// `length=` and `operator[]=`
+///
+/// *NOTICE*: Forwarding just these four operations to a normal growable [List]
+/// (as created by `new List()`) will give very bad performance for `add` and
+/// `addAll` operations of `ListBase`. These operations are implemented by
+/// increasing the length of the list by one for each `add` operation, and
+/// repeatedly increasing the length of a growable list is not efficient.
+/// To avoid this, either override 'add' and 'addAll' to also forward directly
+/// to the growable list, or, if possible, use `DelegatingList` from
+/// "package:collection/wrappers.dart" instead.
+abstract class ListMixin<E> implements List<E> {
+ // Iterable interface.
+ // TODO(lrn): When we get composable mixins, reuse IterableMixin instead
+ // of redaclating everything.
+ Iterator<E> get iterator => ListIterator<E>(this);
+
+ E elementAt(int index) => this[index];
+
+ Iterable<E> followedBy(Iterable<E> other) =>
+ FollowedByIterable<E>.firstEfficient(this, other);
+
+ void forEach(void action(E element)) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ action(this[i]);
+ if (length != this.length) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ }
+
+ @pragma("vm:prefer-inline")
+ bool get isEmpty => length == 0;
+
+ bool get isNotEmpty => !isEmpty;
+
+ E get first {
+ if (length == 0) throw IterableElementError.noElement();
+ return this[0];
+ }
+
+ void set first(E value) {
+ if (length == 0) throw IterableElementError.noElement();
+ this[0] = value;
+ }
+
+ E get last {
+ if (length == 0) throw IterableElementError.noElement();
+ return this[length - 1];
+ }
+
+ void set last(E value) {
+ if (length == 0) throw IterableElementError.noElement();
+ this[length - 1] = value;
+ }
+
+ E get single {
+ if (length == 0) throw IterableElementError.noElement();
+ if (length > 1) throw IterableElementError.tooMany();
+ return this[0];
+ }
+
+ bool contains(Object element) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ if (this[i] == element) return true;
+ if (length != this.length) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ return false;
+ }
+
+ bool every(bool test(E element)) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ if (!test(this[i])) return false;
+ if (length != this.length) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ return true;
+ }
+
+ bool any(bool test(E element)) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ if (test(this[i])) return true;
+ if (length != this.length) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ return false;
+ }
+
+ E firstWhere(bool test(E element), {E orElse()}) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ E element = this[i];
+ if (test(element)) return element;
+ if (length != this.length) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E lastWhere(bool test(E element), {E orElse()}) {
+ int length = this.length;
+ for (int i = length - 1; i >= 0; i--) {
+ E element = this[i];
+ if (test(element)) return element;
+ if (length != this.length) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E singleWhere(bool test(E element), {E orElse()}) {
+ int length = this.length;
+ E match;
+ bool matchFound = false;
+ for (int i = 0; i < length; i++) {
+ E element = this[i];
+ if (test(element)) {
+ if (matchFound) {
+ throw IterableElementError.tooMany();
+ }
+ matchFound = true;
+ match = element;
+ }
+ if (length != this.length) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ if (matchFound) return match;
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ String join([String separator = ""]) {
+ if (length == 0) return "";
+ StringBuffer buffer = StringBuffer()..writeAll(this, separator);
+ return buffer.toString();
+ }
+
+ Iterable<E> where(bool test(E element)) => WhereIterable<E>(this, test);
+
+ Iterable<T> whereType<T>() => WhereTypeIterable<T>(this);
+
+ Iterable<T> map<T>(T f(E element)) => MappedListIterable<E, T>(this, f);
+
+ Iterable<T> expand<T>(Iterable<T> f(E element)) =>
+ ExpandIterable<E, T>(this, f);
+
+ E reduce(E combine(E previousValue, E element)) {
+ int length = this.length;
+ if (length == 0) throw IterableElementError.noElement();
+ E value = this[0];
+ for (int i = 1; i < length; i++) {
+ value = combine(value, this[i]);
+ if (length != this.length) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ return value;
+ }
+
+ T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+ var value = initialValue;
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ value = combine(value, this[i]);
+ if (length != this.length) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ return value;
+ }
+
+ Iterable<E> skip(int count) => SubListIterable<E>(this, count, null);
+
+ Iterable<E> skipWhile(bool test(E element)) {
+ return SkipWhileIterable<E>(this, test);
+ }
+
+ Iterable<E> take(int count) => SubListIterable<E>(this, 0, count);
+
+ Iterable<E> takeWhile(bool test(E element)) {
+ return TakeWhileIterable<E>(this, test);
+ }
+
+ List<E> toList({bool growable = true}) {
+ List<E> result;
+ if (growable) {
+ result = <E>[]..length = length;
+ } else {
+ result = List<E>(length);
+ }
+ for (int i = 0; i < length; i++) {
+ result[i] = this[i];
+ }
+ return result;
+ }
+
+ Set<E> toSet() {
+ Set<E> result = Set<E>();
+ for (int i = 0; i < length; i++) {
+ result.add(this[i]);
+ }
+ return result;
+ }
+
+ // List interface.
+ void add(E element) {
+ this[this.length++] = element;
+ }
+
+ void addAll(Iterable<E> iterable) {
+ int i = this.length;
+ for (E element in iterable) {
+ assert(this.length == i || (throw ConcurrentModificationError(this)));
+ this.length = i + 1;
+ this[i] = element;
+ i++;
+ }
+ }
+
+ bool remove(Object element) {
+ for (int i = 0; i < this.length; i++) {
+ if (this[i] == element) {
+ this._closeGap(i, i + 1);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// Removes elements from the list starting at [start] up to but not including
+ /// [end]. Arguments are pre-validated.
+ void _closeGap(int start, int end) {
+ int length = this.length;
+ assert(0 <= start);
+ assert(start < end);
+ assert(end <= length);
+ int size = end - start;
+ for (int i = end; i < length; i++) {
+ this[i - size] = this[i];
+ }
+ this.length = length - size;
+ }
+
+ void removeWhere(bool test(E element)) {
+ _filter(test, false);
+ }
+
+ void retainWhere(bool test(E element)) {
+ _filter(test, true);
+ }
+
+ void _filter(bool test(E element), bool retainMatching) {
+ List<E> retained = <E>[];
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ var element = this[i];
+ if (test(element) == retainMatching) {
+ retained.add(element);
+ }
+ if (length != this.length) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+ if (retained.length != this.length) {
+ this.setRange(0, retained.length, retained);
+ this.length = retained.length;
+ }
+ }
+
+ void clear() {
+ this.length = 0;
+ }
+
+ List<R> cast<R>() => List.castFrom<E, R>(this);
+ E removeLast() {
+ if (length == 0) {
+ throw IterableElementError.noElement();
+ }
+ E result = this[length - 1];
+ length--;
+ return result;
+ }
+
+ void sort([int compare(E a, E b)]) {
+ Sort.sort(this, compare ?? _compareAny);
+ }
+
+ static int _compareAny(a, b) {
+ // In strong mode Comparable.compare requires an implicit cast to ensure
+ // `a` and `b` are Comparable.
+ return Comparable.compare(a, b);
+ }
+
+ void shuffle([Random random]) {
+ random ??= Random();
+ int length = this.length;
+ while (length > 1) {
+ int pos = random.nextInt(length);
+ length -= 1;
+ var tmp = this[length];
+ this[length] = this[pos];
+ this[pos] = tmp;
+ }
+ }
+
+ Map<int, E> asMap() {
+ return ListMapView<E>(this);
+ }
+
+ List<E> operator +(List<E> other) {
+ var result = <E>[]..length = (this.length + other.length);
+ result.setRange(0, this.length, this);
+ result.setRange(this.length, result.length, other);
+ return result;
+ }
+
+ List<E> sublist(int start, [int end]) {
+ int listLength = this.length;
+ end ??= listLength;
+ RangeError.checkValidRange(start, end, listLength);
+ int length = end - start;
+ List<E> result = <E>[]..length = length;
+ for (int i = 0; i < length; i++) {
+ result[i] = this[start + i];
+ }
+ return result;
+ }
+
+ Iterable<E> getRange(int start, int end) {
+ RangeError.checkValidRange(start, end, this.length);
+ return SubListIterable<E>(this, start, end);
+ }
+
+ void removeRange(int start, int end) {
+ RangeError.checkValidRange(start, end, this.length);
+ if (end > start) {
+ _closeGap(start, end);
+ }
+ }
+
+ void fillRange(int start, int end, [E fill]) {
+ RangeError.checkValidRange(start, end, this.length);
+ for (int i = start; i < end; i++) {
+ this[i] = fill;
+ }
+ }
+
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+ RangeError.checkValidRange(start, end, this.length);
+ int length = end - start;
+ if (length == 0) return;
+ RangeError.checkNotNegative(skipCount, "skipCount");
+
+ List<E> otherList;
+ int otherStart;
+ // TODO(floitsch): Make this accept more.
+ if (iterable is List<E>) {
+ otherList = iterable;
+ otherStart = skipCount;
+ } else {
+ otherList = iterable.skip(skipCount).toList(growable: false);
+ otherStart = 0;
+ }
+ if (otherStart + length > otherList.length) {
+ throw IterableElementError.tooFew();
+ }
+ if (otherStart < start) {
+ // Copy backwards to ensure correct copy if [from] is this.
+ for (int i = length - 1; i >= 0; i--) {
+ this[start + i] = otherList[otherStart + i];
+ }
+ } else {
+ for (int i = 0; i < length; i++) {
+ this[start + i] = otherList[otherStart + i];
+ }
+ }
+ }
+
+ void replaceRange(int start, int end, Iterable<E> newContents) {
+ RangeError.checkValidRange(start, end, this.length);
+ if (newContents is! EfficientLengthIterable) {
+ newContents = newContents.toList();
+ }
+ int removeLength = end - start;
+ int insertLength = newContents.length;
+ if (removeLength >= insertLength) {
+ int insertEnd = start + insertLength;
+ this.setRange(start, insertEnd, newContents);
+ if (removeLength > insertLength) {
+ _closeGap(insertEnd, end);
+ }
+ } else {
+ int delta = insertLength - removeLength;
+ int newLength = this.length + delta;
+ int insertEnd = start + insertLength; // aka. end + delta.
+ this.length = newLength;
+ this.setRange(insertEnd, newLength, this, end);
+ this.setRange(start, insertEnd, newContents);
+ }
+ }
+
+ int indexOf(Object element, [int start = 0]) {
+ if (start < 0) start = 0;
+ for (int i = start; i < this.length; i++) {
+ if (this[i] == element) return i;
+ }
+ return -1;
+ }
+
+ int indexWhere(bool test(E element), [int start = 0]) {
+ if (start < 0) start = 0;
+ for (int i = start; i < this.length; i++) {
+ if (test(this[i])) return i;
+ }
+ return -1;
+ }
+
+ int lastIndexOf(Object element, [int start]) {
+ if (start == null || start >= this.length) start = this.length - 1;
+ for (int i = start; i >= 0; i--) {
+ if (this[i] == element) return i;
+ }
+ return -1;
+ }
+
+ int lastIndexWhere(bool test(E element), [int start]) {
+ if (start == null || start >= this.length) start = this.length - 1;
+ for (int i = start; i >= 0; i--) {
+ if (test(this[i])) return i;
+ }
+ return -1;
+ }
+
+ void insert(int index, E element) {
+ ArgumentError.checkNotNull(index, "index");
+ RangeError.checkValueInInterval(index, 0, length, "index");
+ if (index == this.length) {
+ add(element);
+ return;
+ }
+ this.length++;
+ setRange(index + 1, this.length, this, index);
+ this[index] = element;
+ }
+
+ E removeAt(int index) {
+ E result = this[index];
+ _closeGap(index, index + 1);
+ return result;
+ }
+
+ void insertAll(int index, Iterable<E> iterable) {
+ RangeError.checkValueInInterval(index, 0, length, "index");
+ if (iterable is! EfficientLengthIterable || identical(iterable, this)) {
+ iterable = iterable.toList();
+ }
+ int insertionLength = iterable.length;
+ // There might be errors after the length change, in which case the list
+ // will end up being modified but the operation not complete. Unless we
+ // always go through a "toList" we can't really avoid that.
+ this.length += insertionLength;
+ if (iterable.length != insertionLength) {
+ // If the iterable's length is linked to this list's length somehow,
+ // we can't insert one in the other.
+ this.length -= insertionLength;
+ throw ConcurrentModificationError(iterable);
+ }
+ setRange(index + insertionLength, this.length, this, index);
+ setAll(index, iterable);
+ }
+
+ void setAll(int index, Iterable<E> iterable) {
+ if (iterable is List) {
+ setRange(index, index + iterable.length, iterable);
+ } else {
+ for (E element in iterable) {
+ this[index++] = element;
+ }
+ }
+ }
+
+ Iterable<E> get reversed => ReversedListIterable<E>(this);
+
+ String toString() => IterableBase.iterableToFullString(this, '[', ']');
+}
diff --git a/sdk_nnbd/lib/collection/maps.dart b/sdk_nnbd/lib/collection/maps.dart
new file mode 100644
index 0000000..8159342
--- /dev/null
+++ b/sdk_nnbd/lib/collection/maps.dart
@@ -0,0 +1,378 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// Base class for implementing a [Map].
+///
+/// This class has a basic implementation of all but five of the members of
+/// [Map].
+/// A basic `Map` class can be implemented by extending this class and
+/// implementing `keys`, `operator[]`, `operator[]=`, `remove` and `clear`.
+/// The remaining operations are implemented in terms of these five.
+///
+/// The `keys` iterable should have efficient [Iterable.length] and
+/// [Iterable.contains] operations, and it should catch concurrent modifications
+/// of the keys while iterating.
+///
+/// A more efficient implementation is usually possible by overriding
+/// some of the other members as well.
+abstract class MapBase<K, V> extends MapMixin<K, V> {
+ static String mapToString(Map m) {
+ // Reuses the list in IterableBase for detecting toString cycles.
+ if (_isToStringVisiting(m)) {
+ return '{...}';
+ }
+
+ var result = StringBuffer();
+ try {
+ _toStringVisiting.add(m);
+ result.write('{');
+ bool first = true;
+ m.forEach((k, v) {
+ if (!first) {
+ result.write(', ');
+ }
+ first = false;
+ result.write(k);
+ result.write(': ');
+ result.write(v);
+ });
+ result.write('}');
+ } finally {
+ assert(identical(_toStringVisiting.last, m));
+ _toStringVisiting.removeLast();
+ }
+
+ return result.toString();
+ }
+
+ static _id(x) => x;
+
+ /// Fills a [Map] with key/value pairs computed from [iterable].
+ ///
+ /// This method is used by [Map] classes in the named constructor
+ /// `fromIterable`.
+ static void _fillMapWithMappedIterable(
+ Map map, Iterable iterable, key(element), value(element)) {
+ key ??= _id;
+ value ??= _id;
+
+ for (var element in iterable) {
+ map[key(element)] = value(element);
+ }
+ }
+
+ /// Fills a map by associating the [keys] to [values].
+ ///
+ /// This method is used by [Map] classes in the named constructor
+ /// `fromIterables`.
+ static void _fillMapWithIterables(Map map, Iterable keys, Iterable values) {
+ Iterator keyIterator = keys.iterator;
+ Iterator valueIterator = values.iterator;
+
+ bool hasNextKey = keyIterator.moveNext();
+ bool hasNextValue = valueIterator.moveNext();
+
+ while (hasNextKey && hasNextValue) {
+ map[keyIterator.current] = valueIterator.current;
+ hasNextKey = keyIterator.moveNext();
+ hasNextValue = valueIterator.moveNext();
+ }
+
+ if (hasNextKey || hasNextValue) {
+ throw ArgumentError("Iterables do not have same length.");
+ }
+ }
+}
+
+/// Mixin implementing a [Map].
+///
+/// This mixin has a basic implementation of all but five of the members of
+/// [Map].
+/// A basic `Map` class can be implemented by mixin in this class and
+/// implementing `keys`, `operator[]`, `operator[]=`, `remove` and `clear`.
+/// The remaining operations are implemented in terms of these five.
+///
+/// The `keys` iterable should have efficient [Iterable.length] and
+/// [Iterable.contains] operations, and it should catch concurrent modifications
+/// of the keys while iterating.
+///
+/// A more efficient implementation is usually possible by overriding
+/// some of the other members as well.
+abstract class MapMixin<K, V> implements Map<K, V> {
+ Iterable<K> get keys;
+ V operator [](Object key);
+ operator []=(K key, V value);
+ V remove(Object key);
+ // The `clear` operation should not be based on `remove`.
+ // It should clear the map even if some keys are not equal to themselves.
+ void clear();
+
+ Map<RK, RV> cast<RK, RV>() => Map.castFrom<K, V, RK, RV>(this);
+ void forEach(void action(K key, V value)) {
+ for (K key in keys) {
+ action(key, this[key]);
+ }
+ }
+
+ void addAll(Map<K, V> other) {
+ for (K key in other.keys) {
+ this[key] = other[key];
+ }
+ }
+
+ bool containsValue(Object value) {
+ for (K key in keys) {
+ if (this[key] == value) return true;
+ }
+ return false;
+ }
+
+ V putIfAbsent(K key, V ifAbsent()) {
+ if (containsKey(key)) {
+ return this[key];
+ }
+ return this[key] = ifAbsent();
+ }
+
+ V update(K key, V update(V value), {V ifAbsent()}) {
+ if (this.containsKey(key)) {
+ return this[key] = update(this[key]);
+ }
+ if (ifAbsent != null) {
+ return this[key] = ifAbsent();
+ }
+ throw ArgumentError.value(key, "key", "Key not in map.");
+ }
+
+ void updateAll(V update(K key, V value)) {
+ for (var key in this.keys) {
+ this[key] = update(key, this[key]);
+ }
+ }
+
+ Iterable<MapEntry<K, V>> get entries {
+ return keys.map((K key) => MapEntry<K, V>(key, this[key]));
+ }
+
+ Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> transform(K key, V value)) {
+ var result = <K2, V2>{};
+ for (var key in this.keys) {
+ var entry = transform(key, this[key]);
+ result[entry.key] = entry.value;
+ }
+ return result;
+ }
+
+ void addEntries(Iterable<MapEntry<K, V>> newEntries) {
+ for (var entry in newEntries) {
+ this[entry.key] = entry.value;
+ }
+ }
+
+ void removeWhere(bool test(K key, V value)) {
+ var keysToRemove = <K>[];
+ for (var key in keys) {
+ if (test(key, this[key])) keysToRemove.add(key);
+ }
+ for (var key in keysToRemove) {
+ this.remove(key);
+ }
+ }
+
+ bool containsKey(Object key) => keys.contains(key);
+ int get length => keys.length;
+ bool get isEmpty => keys.isEmpty;
+ bool get isNotEmpty => keys.isNotEmpty;
+ Iterable<V> get values => _MapBaseValueIterable<K, V>(this);
+ String toString() => MapBase.mapToString(this);
+}
+
+/// Basic implementation of an unmodifiable [Map].
+///
+/// This class has a basic implementation of all but two of the members of
+/// an umodifiable [Map].
+/// A simple unmodifiable `Map` class can be implemented by extending this
+/// class and implementing `keys` and `operator[]`.
+///
+/// Modifying operations throw when used.
+/// The remaining non-modifying operations are implemented in terms of `keys`
+/// and `operator[]`.
+///
+/// The `keys` iterable should have efficient [Iterable.length] and
+/// [Iterable.contains] operations, and it should catch concurrent modifications
+/// of the keys while iterating.
+///
+/// A more efficient implementation is usually possible by overriding
+/// some of the other members as well.
+abstract class UnmodifiableMapBase<K, V> = MapBase<K, V>
+ with _UnmodifiableMapMixin<K, V>;
+
+/// Implementation of [Map.values] based on the map and its [Map.keys] iterable.
+///
+/// Iterable that iterates over the values of a `Map`.
+/// It accesses the values by iterating over the keys of the map, and using the
+/// map's `operator[]` to lookup the keys.
+class _MapBaseValueIterable<K, V> extends EfficientLengthIterable<V> {
+ final Map<K, V> _map;
+ _MapBaseValueIterable(this._map);
+
+ int get length => _map.length;
+ bool get isEmpty => _map.isEmpty;
+ bool get isNotEmpty => _map.isNotEmpty;
+ V get first => _map[_map.keys.first];
+ V get single => _map[_map.keys.single];
+ V get last => _map[_map.keys.last];
+
+ Iterator<V> get iterator => _MapBaseValueIterator<K, V>(_map);
+}
+
+/// Iterator created by [_MapBaseValueIterable].
+///
+/// Iterates over the values of a map by iterating its keys and lookup up the
+/// values.
+class _MapBaseValueIterator<K, V> implements Iterator<V> {
+ final Iterator<K> _keys;
+ final Map<K, V> _map;
+ V _current;
+
+ _MapBaseValueIterator(Map<K, V> map)
+ : _map = map,
+ _keys = map.keys.iterator;
+
+ bool moveNext() {
+ if (_keys.moveNext()) {
+ _current = _map[_keys.current];
+ return true;
+ }
+ _current = null;
+ return false;
+ }
+
+ V get current => _current;
+}
+
+/// Mixin that overrides mutating map operations with implementations that
+/// throw.
+abstract class _UnmodifiableMapMixin<K, V> implements Map<K, V> {
+ /// This operation is not supported by an unmodifiable map.
+ void operator []=(K key, V value) {
+ throw UnsupportedError("Cannot modify unmodifiable map");
+ }
+
+ /// This operation is not supported by an unmodifiable map.
+ void addAll(Map<K, V> other) {
+ throw UnsupportedError("Cannot modify unmodifiable map");
+ }
+
+ /// This operation is not supported by an unmodifiable map.
+ void addEntries(Iterable<MapEntry<K, V>> entries) {
+ throw UnsupportedError("Cannot modify unmodifiable map");
+ }
+
+ /// This operation is not supported by an unmodifiable map.
+ void clear() {
+ throw UnsupportedError("Cannot modify unmodifiable map");
+ }
+
+ /// This operation is not supported by an unmodifiable map.
+ V remove(Object key) {
+ throw UnsupportedError("Cannot modify unmodifiable map");
+ }
+
+ /// This operation is not supported by an unmodifiable map.
+ void removeWhere(bool test(K key, V value)) {
+ throw UnsupportedError("Cannot modify unmodifiable map");
+ }
+
+ /// This operation is not supported by an unmodifiable map.
+ V putIfAbsent(K key, V ifAbsent()) {
+ throw UnsupportedError("Cannot modify unmodifiable map");
+ }
+
+ /// This operation is not supported by an unmodifiable map.
+ V update(K key, V update(V value), {V ifAbsent()}) {
+ throw UnsupportedError("Cannot modify unmodifiable map");
+ }
+
+ /// This operation is not supported by an unmodifiable map.
+ void updateAll(V update(K key, V value)) {
+ throw UnsupportedError("Cannot modify unmodifiable map");
+ }
+}
+
+/// Wrapper around a class that implements [Map] that only exposes `Map`
+/// members.
+///
+/// A simple wrapper that delegates all `Map` members to the map provided in the
+/// constructor.
+///
+/// Base for delegating map implementations like [UnmodifiableMapView].
+class MapView<K, V> implements Map<K, V> {
+ final Map<K, V> _map;
+ const MapView(Map<K, V> map) : _map = map;
+
+ Map<RK, RV> cast<RK, RV>() => _map.cast<RK, RV>();
+ V operator [](Object key) => _map[key];
+ void operator []=(K key, V value) {
+ _map[key] = value;
+ }
+
+ void addAll(Map<K, V> other) {
+ _map.addAll(other);
+ }
+
+ void clear() {
+ _map.clear();
+ }
+
+ V putIfAbsent(K key, V ifAbsent()) => _map.putIfAbsent(key, ifAbsent);
+ bool containsKey(Object key) => _map.containsKey(key);
+ bool containsValue(Object value) => _map.containsValue(value);
+ void forEach(void action(K key, V value)) {
+ _map.forEach(action);
+ }
+
+ bool get isEmpty => _map.isEmpty;
+ bool get isNotEmpty => _map.isNotEmpty;
+ int get length => _map.length;
+ Iterable<K> get keys => _map.keys;
+ V remove(Object key) => _map.remove(key);
+ String toString() => _map.toString();
+ Iterable<V> get values => _map.values;
+
+ Iterable<MapEntry<K, V>> get entries => _map.entries;
+
+ void addEntries(Iterable<MapEntry<K, V>> entries) {
+ _map.addEntries(entries);
+ }
+
+ Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> transform(K key, V value)) =>
+ _map.map<K2, V2>(transform);
+
+ V update(K key, V update(V value), {V ifAbsent()}) =>
+ _map.update(key, update, ifAbsent: ifAbsent);
+
+ void updateAll(V update(K key, V value)) {
+ _map.updateAll(update);
+ }
+
+ void removeWhere(bool test(K key, V value)) {
+ _map.removeWhere(test);
+ }
+}
+
+/// View of a [Map] that disallow modifying the map.
+///
+/// A wrapper around a `Map` that forwards all members to the map provided in
+/// the constructor, except for operations that modify the map.
+/// Modifying operations throw instead.
+class UnmodifiableMapView<K, V> extends MapView<K, V>
+ with _UnmodifiableMapMixin<K, V> {
+ UnmodifiableMapView(Map<K, V> map) : super(map);
+
+ Map<RK, RV> cast<RK, RV>() =>
+ UnmodifiableMapView<RK, RV>(_map.cast<RK, RV>());
+}
diff --git a/sdk_nnbd/lib/collection/queue.dart b/sdk_nnbd/lib/collection/queue.dart
new file mode 100644
index 0000000..62994b9
--- /dev/null
+++ b/sdk_nnbd/lib/collection/queue.dart
@@ -0,0 +1,887 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+/// A [Queue] is a collection that can be manipulated at both ends. One
+/// can iterate over the elements of a queue through [forEach] or with
+/// an [Iterator].
+///
+/// It is generally not allowed to modify the queue (add or remove entries)
+/// while an operation on the queue is being performed, for example during a
+/// call to [forEach].
+/// Modifying the queue while it is being iterated will most likely break the
+/// iteration.
+/// This goes both for using the [iterator] directly, or for iterating an
+/// `Iterable` returned by a method like [map] or [where].
+abstract class Queue<E> implements EfficientLengthIterable<E> {
+ /// Creates a queue.
+ factory Queue() = ListQueue<E>;
+
+ /// Creates a queue containing all [elements].
+ ///
+ /// The element order in the queue is as if the elements were added using
+ /// [addLast] in the order provided by [elements.iterator].
+ ///
+ /// All the [elements] should be instances of [E].
+ /// The `elements` iterable itself may have any element type, so this
+ /// constructor can be used to down-cast a `Queue`, for example as:
+ /// ```dart
+ /// Queue<SuperType> superQueue = ...;
+ /// Queue<SubType> subQueue =
+ /// new Queue<SubType>.from(superSet.whereType<SubType>());
+ /// ```
+ factory Queue.from(Iterable elements) = ListQueue<E>.from;
+
+ /// Creates a queue from [elements].
+ ///
+ /// The element order in the queue is as if the elements were added using
+ /// [addLast] in the order provided by [elements.iterator].
+ factory Queue.of(Iterable<E> elements) = ListQueue<E>.of;
+
+ /// Adapts [source] to be a `Queue<T>`.
+ ///
+ /// Any time the queue would produce an element that is not a [T],
+ /// the element access will throw.
+ ///
+ /// Any time a [T] value is attempted stored into the adapted queue,
+ /// the store will throw unless the value is also an instance of [S].
+ ///
+ /// If all accessed elements of [source] are actually instances of [T],
+ /// and if all elements stored into the returned queue are actually instance
+ /// of [S],
+ /// then the returned queue can be used as a `Queue<T>`.
+ static Queue<T> castFrom<S, T>(Queue<S> source) => CastQueue<S, T>(source);
+
+ /// Provides a view of this queue as a queue of [R] instances, if necessary.
+ ///
+ /// If this queue contains only instances of [R], all read operations
+ /// will work correctly. If any operation tries to access an element
+ /// that is not an instance of [R], the access will throw instead.
+ ///
+ /// Elements added to the queue (e.g., by using [addFirst] or [addAll])
+ /// must be instance of [R] to be valid arguments to the adding function,
+ /// and they must be instances of [E] as well to be accepted by
+ /// this queue as well.
+ Queue<R> cast<R>();
+
+ /// Removes and returns the first element of this queue.
+ ///
+ /// The queue must not be empty when this method is called.
+ E removeFirst();
+
+ /// Removes and returns the last element of the queue.
+ ///
+ /// The queue must not be empty when this method is called.
+ E removeLast();
+
+ /// Adds [value] at the beginning of the queue.
+ void addFirst(E value);
+
+ /// Adds [value] at the end of the queue.
+ void addLast(E value);
+
+ /// Adds [value] at the end of the queue.
+ void add(E value);
+
+ /// Remove a single instance of [value] from the queue.
+ ///
+ /// Returns `true` if a value was removed, or `false` if the queue
+ /// contained no element equal to [value].
+ bool remove(Object value);
+
+ /// Adds all elements of [iterable] at the end of the queue. The
+ /// length of the queue is extended by the length of [iterable].
+ void addAll(Iterable<E> iterable);
+
+ /// Removes all elements matched by [test] from the queue.
+ ///
+ /// The `test` function must not throw or modify the queue.
+ void removeWhere(bool test(E element));
+
+ /// Removes all elements not matched by [test] from the queue.
+ ///
+ /// The `test` function must not throw or modify the queue.
+ void retainWhere(bool test(E element));
+
+ /// Removes all elements in the queue. The size of the queue becomes zero.
+ void clear();
+}
+
+class _DoubleLink<Link extends _DoubleLink<Link>> {
+ Link _previousLink;
+ Link _nextLink;
+
+ void _link(Link previous, Link next) {
+ _nextLink = next;
+ _previousLink = previous;
+ if (previous != null) previous._nextLink = this;
+ if (next != null) next._previousLink = this;
+ }
+
+ void _unlink() {
+ if (_previousLink != null) _previousLink._nextLink = _nextLink;
+ if (_nextLink != null) _nextLink._previousLink = _previousLink;
+ _nextLink = null;
+ _previousLink = null;
+ }
+}
+
+/// An entry in a doubly linked list. It contains a pointer to the next
+/// entry, the previous entry, and the boxed element.
+class DoubleLinkedQueueEntry<E> extends _DoubleLink<DoubleLinkedQueueEntry<E>> {
+ /// The element in the queue.
+ E element;
+
+ DoubleLinkedQueueEntry(this.element);
+
+ /// Appends the given [e] as entry just after this entry.
+ void append(E e) {
+ DoubleLinkedQueueEntry<E>(e)._link(this, _nextLink);
+ }
+
+ /// Prepends the given [e] as entry just before this entry.
+ void prepend(E e) {
+ DoubleLinkedQueueEntry<E>(e)._link(_previousLink, this);
+ }
+
+ E remove() {
+ _unlink();
+ return element;
+ }
+
+ /// Returns the previous entry or `null` if there is none.
+ DoubleLinkedQueueEntry<E> previousEntry() => _previousLink;
+
+ /// Returns the next entry or `null` if there is none.
+ DoubleLinkedQueueEntry<E> nextEntry() => _nextLink;
+}
+
+/// Interface for the link classes used by [DoubleLinkedQueue].
+///
+/// Both the [_DoubleLinkedQueueElement] and [_DoubleLinkedQueueSentinel]
+/// implement this interface.
+/// The entry contains a link back to the queue, so calling `append`
+/// or `prepend` can correctly update the element count.
+abstract class _DoubleLinkedQueueEntry<E> extends DoubleLinkedQueueEntry<E> {
+ DoubleLinkedQueue<E> _queue;
+ _DoubleLinkedQueueEntry(E element, this._queue) : super(element);
+
+ DoubleLinkedQueueEntry<E> _asNonSentinelEntry();
+
+ void _append(E e) {
+ _DoubleLinkedQueueElement<E>(e, _queue)._link(this, _nextLink);
+ }
+
+ void _prepend(E e) {
+ _DoubleLinkedQueueElement<E>(e, _queue)._link(_previousLink, this);
+ }
+
+ E _remove();
+
+ E get _element => element;
+
+ DoubleLinkedQueueEntry<E> nextEntry() {
+ _DoubleLinkedQueueEntry<E> entry = _nextLink;
+ return entry._asNonSentinelEntry();
+ }
+
+ DoubleLinkedQueueEntry<E> previousEntry() {
+ _DoubleLinkedQueueEntry<E> entry = _previousLink;
+ return entry._asNonSentinelEntry();
+ }
+}
+
+/// The actual entry type used by the [DoubleLinkedQueue].
+///
+/// The entry contains a reference to the queue, allowing
+/// [append]/[prepend] to update the list length.
+class _DoubleLinkedQueueElement<E> extends _DoubleLinkedQueueEntry<E> {
+ _DoubleLinkedQueueElement(E element, DoubleLinkedQueue<E> queue)
+ : super(element, queue);
+
+ void append(E e) {
+ _append(e);
+ if (_queue != null) _queue._elementCount++;
+ }
+
+ void prepend(E e) {
+ _prepend(e);
+ if (_queue != null) _queue._elementCount++;
+ }
+
+ E _remove() {
+ _queue = null;
+ _unlink();
+ return element;
+ }
+
+ E remove() {
+ if (_queue != null) _queue._elementCount--;
+ return _remove();
+ }
+
+ _DoubleLinkedQueueElement<E> _asNonSentinelEntry() {
+ return this;
+ }
+}
+
+/// A sentinel in a double linked list is used to manipulate the list
+/// at both ends.
+/// A double linked list has exactly one sentinel,
+/// which is the only entry when the list is constructed.
+/// Initially, a sentinel has its next and previous entry point to itself.
+/// A sentinel does not box any user element.
+class _DoubleLinkedQueueSentinel<E> extends _DoubleLinkedQueueEntry<E> {
+ _DoubleLinkedQueueSentinel(DoubleLinkedQueue<E> queue) : super(null, queue) {
+ _previousLink = this;
+ _nextLink = this;
+ }
+
+ DoubleLinkedQueueEntry<E> _asNonSentinelEntry() {
+ return null;
+ }
+
+ /// Hit by, e.g., [DoubleLinkedQueue.removeFirst] if the queue is empty.
+ E _remove() {
+ throw IterableElementError.noElement();
+ }
+
+ /// Hit by, e.g., [DoubleLinkedQueue.first] if the queue is empty.
+ E get _element {
+ throw IterableElementError.noElement();
+ }
+}
+
+/// A [Queue] implementation based on a double-linked list.
+///
+/// Allows constant time add, remove-at-ends and peek operations.
+class DoubleLinkedQueue<E> extends Iterable<E> implements Queue<E> {
+ _DoubleLinkedQueueSentinel<E> _sentinel;
+ int _elementCount = 0;
+
+ DoubleLinkedQueue() {
+ _sentinel = _DoubleLinkedQueueSentinel<E>(this);
+ }
+
+ /// Creates a double-linked queue containing all [elements].
+ ///
+ /// The element order in the queue is as if the elements were added using
+ /// [addLast] in the order provided by [elements.iterator].
+ ///
+ /// All the [elements] should be instances of [E].
+ /// The `elements` iterable itself may have any element type, so this
+ /// constructor can be used to down-cast a `Queue`, for example as:
+ /// ```dart
+ /// Queue<SuperType> superQueue = ...;
+ /// Queue<SubType> subQueue =
+ /// new DoubleLinkedQueue<SubType>.from(superQueue.whereType<SubType>());
+ /// ```
+ factory DoubleLinkedQueue.from(Iterable elements) {
+ Queue<E> list = DoubleLinkedQueue<E>();
+ for (final e in elements) {
+ list.addLast(e);
+ }
+ return list;
+ }
+
+ /// Creates a double-linked queue from [elements].
+ ///
+ /// The element order in the queue is as if the elements were added using
+ /// [addLast] in the order provided by [elements.iterator].
+ factory DoubleLinkedQueue.of(Iterable<E> elements) =>
+ DoubleLinkedQueue<E>()..addAll(elements);
+
+ Queue<R> cast<R>() => Queue.castFrom<E, R>(this);
+ int get length => _elementCount;
+
+ void addLast(E value) {
+ _sentinel._prepend(value);
+ _elementCount++;
+ }
+
+ void addFirst(E value) {
+ _sentinel._append(value);
+ _elementCount++;
+ }
+
+ void add(E value) {
+ _sentinel._prepend(value);
+ _elementCount++;
+ }
+
+ void addAll(Iterable<E> iterable) {
+ for (final E value in iterable) {
+ _sentinel._prepend(value);
+ _elementCount++;
+ }
+ }
+
+ E removeLast() {
+ _DoubleLinkedQueueEntry<E> lastEntry = _sentinel._previousLink;
+ E result = lastEntry._remove();
+ _elementCount--;
+ return result;
+ }
+
+ E removeFirst() {
+ _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink;
+ E result = firstEntry._remove();
+ _elementCount--;
+ return result;
+ }
+
+ bool remove(Object o) {
+ _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
+ while (!identical(entry, _sentinel)) {
+ bool equals = (entry._element == o);
+ if (!identical(this, entry._queue)) {
+ // Entry must still be in the queue.
+ throw ConcurrentModificationError(this);
+ }
+ if (equals) {
+ entry._remove();
+ _elementCount--;
+ return true;
+ }
+ entry = entry._nextLink;
+ }
+ return false;
+ }
+
+ void _filter(bool test(E element), bool removeMatching) {
+ _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
+ while (!identical(entry, _sentinel)) {
+ bool matches = test(entry._element);
+ if (!identical(this, entry._queue)) {
+ // Entry must still be in the queue.
+ throw ConcurrentModificationError(this);
+ }
+ _DoubleLinkedQueueEntry<E> next = entry._nextLink; // Cannot be null.
+ if (identical(removeMatching, matches)) {
+ entry._remove();
+ _elementCount--;
+ }
+ entry = next;
+ }
+ }
+
+ void removeWhere(bool test(E element)) {
+ _filter(test, true);
+ }
+
+ void retainWhere(bool test(E element)) {
+ _filter(test, false);
+ }
+
+ E get first {
+ _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink;
+ return firstEntry._element;
+ }
+
+ E get last {
+ _DoubleLinkedQueueEntry<E> lastEntry = _sentinel._previousLink;
+ return lastEntry._element;
+ }
+
+ E get single {
+ // Note that this throws correctly if the queue is empty
+ // because reading the element of the sentinel throws.
+ if (identical(_sentinel._nextLink, _sentinel._previousLink)) {
+ _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
+ return entry._element;
+ }
+ throw IterableElementError.tooMany();
+ }
+
+ /// The entry object of the first element in the queue.
+ ///
+ /// Each element of the queue has an associated [DoubleLinkedQueueEntry].
+ /// Returns the entry object corresponding to the first element of the queue.
+ ///
+ /// The entry objects can also be accessed using [lastEntry],
+ /// and they can be iterated using [DoubleLinkedQueueEntry.nextEntry()] and
+ /// [DoubleLinkedQueueEntry.previousEntry()].
+ DoubleLinkedQueueEntry<E> firstEntry() {
+ return _sentinel.nextEntry();
+ }
+
+ /// The entry object of the last element in the queue.
+ ///
+ /// Each element of the queue has an associated [DoubleLinkedQueueEntry].
+ /// Returns the entry object corresponding to the last element of the queue.
+ ///
+ /// The entry objects can also be accessed using [firstEntry],
+ /// and they can be iterated using [DoubleLinkedQueueEntry.nextEntry()] and
+ /// [DoubleLinkedQueueEntry.previousEntry()].
+ DoubleLinkedQueueEntry<E> lastEntry() {
+ return _sentinel.previousEntry();
+ }
+
+ bool get isEmpty {
+ return (identical(_sentinel._nextLink, _sentinel));
+ }
+
+ void clear() {
+ _sentinel._nextLink = _sentinel;
+ _sentinel._previousLink = _sentinel;
+ _elementCount = 0;
+ }
+
+ /// Calls [action] for each entry object of this double-linked queue.
+ ///
+ /// Each element of the queue has an associated [DoubleLinkedQueueEntry].
+ /// This method iterates the entry objects from first to last and calls
+ /// [action] with each object in turn.
+ ///
+ /// The entry objects can also be accessed using [firstEntry] and [lastEntry],
+ /// and iterated using [DoubleLinkedQueueEntry.nextEntry()] and
+ /// [DoubleLinkedQueueEntry.previousEntry()].
+ ///
+ /// The [action] function can use methods on [DoubleLinkedQueueEntry] to
+ /// remove the entry or it can insert elements before or after then entry.
+ /// If the current entry is removed, iteration continues with the entry that
+ /// was following the current entry when [action] was called. Any elements
+ /// inserted after the current element before it is removed will not be
+ /// visited by the iteration.
+ void forEachEntry(void action(DoubleLinkedQueueEntry<E> element)) {
+ _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
+ while (!identical(entry, _sentinel)) {
+ _DoubleLinkedQueueElement<E> element = entry;
+ _DoubleLinkedQueueEntry<E> next = element._nextLink;
+ // Remember both entry and entry._nextLink.
+ // If someone calls `element.remove()` we continue from `next`.
+ // Otherwise we use the value of entry._nextLink which may have been
+ // updated.
+ action(element);
+ if (identical(this, entry._queue)) {
+ next = entry._nextLink;
+ } else if (!identical(this, next._queue)) {
+ throw ConcurrentModificationError(this);
+ }
+ entry = next;
+ }
+ }
+
+ _DoubleLinkedQueueIterator<E> get iterator {
+ return _DoubleLinkedQueueIterator<E>(_sentinel);
+ }
+
+ String toString() => IterableBase.iterableToFullString(this, '{', '}');
+}
+
+class _DoubleLinkedQueueIterator<E> implements Iterator<E> {
+ _DoubleLinkedQueueSentinel<E> _sentinel;
+ _DoubleLinkedQueueEntry<E> _nextEntry;
+ E _current;
+
+ _DoubleLinkedQueueIterator(_DoubleLinkedQueueSentinel<E> sentinel)
+ : _sentinel = sentinel,
+ _nextEntry = sentinel._nextLink;
+
+ bool moveNext() {
+ if (identical(_nextEntry, _sentinel)) {
+ _current = null;
+ _nextEntry = null;
+ _sentinel = null;
+ return false;
+ }
+ _DoubleLinkedQueueElement<E> elementEntry = _nextEntry;
+ if (!identical(_sentinel._queue, elementEntry._queue)) {
+ throw ConcurrentModificationError(_sentinel._queue);
+ }
+ _current = elementEntry._element;
+ _nextEntry = elementEntry._nextLink;
+ return true;
+ }
+
+ E get current => _current;
+}
+
+/// List based [Queue].
+///
+/// Keeps a cyclic buffer of elements, and grows to a larger buffer when
+/// it fills up. This guarantees constant time peek and remove operations, and
+/// amortized constant time add operations.
+///
+/// The structure is efficient for any queue or stack usage.
+class ListQueue<E> extends ListIterable<E> implements Queue<E> {
+ static const int _INITIAL_CAPACITY = 8;
+ List<E> _table;
+ int _head;
+ int _tail;
+ int _modificationCount = 0;
+
+ /// Create an empty queue.
+ ///
+ /// If [initialCapacity] is given, prepare the queue for at least that many
+ /// elements.
+ ListQueue([int initialCapacity])
+ : _head = 0,
+ _tail = 0 {
+ if (initialCapacity == null || initialCapacity < _INITIAL_CAPACITY) {
+ initialCapacity = _INITIAL_CAPACITY;
+ } else if (!_isPowerOf2(initialCapacity)) {
+ initialCapacity = _nextPowerOf2(initialCapacity);
+ }
+ assert(_isPowerOf2(initialCapacity));
+ _table = List<E>(initialCapacity);
+ }
+
+ /// Create a `ListQueue` containing all [elements].
+ ///
+ /// The elements are added to the queue, as by [addLast], in the order given
+ /// by `elements.iterator`.
+ ///
+ /// All the [elements] should be instances of [E].
+ /// The `elements` iterable itself may have any element type, so this
+ /// constructor can be used to down-cast a `Queue`, for example as:
+ /// ```dart
+ /// Queue<SuperType> superQueue = ...;
+ /// Queue<SubType> subQueue =
+ /// new ListQueue<SubType>.from(superQueue.whereType<SubType>());
+ /// ```
+ factory ListQueue.from(Iterable elements) {
+ if (elements is List) {
+ int length = elements.length;
+ ListQueue<E> queue = ListQueue<E>(length + 1);
+ assert(queue._table.length > length);
+ for (int i = 0; i < length; i++) {
+ queue._table[i] = elements[i];
+ }
+ queue._tail = length;
+ return queue;
+ } else {
+ int capacity = _INITIAL_CAPACITY;
+ if (elements is EfficientLengthIterable) {
+ capacity = elements.length;
+ }
+ ListQueue<E> result = ListQueue<E>(capacity);
+ for (final element in elements) {
+ result.addLast(element);
+ }
+ return result;
+ }
+ }
+
+ /// Create a `ListQueue` from [elements].
+ ///
+ /// The elements are added to the queue, as by [addLast], in the order given
+ /// by `elements.iterator`.
+ factory ListQueue.of(Iterable<E> elements) =>
+ ListQueue<E>()..addAll(elements);
+
+ // Iterable interface.
+
+ Queue<R> cast<R>() => Queue.castFrom<E, R>(this);
+ Iterator<E> get iterator => _ListQueueIterator<E>(this);
+
+ void forEach(void f(E element)) {
+ int modificationCount = _modificationCount;
+ for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) {
+ f(_table[i]);
+ _checkModification(modificationCount);
+ }
+ }
+
+ bool get isEmpty => _head == _tail;
+
+ int get length => (_tail - _head) & (_table.length - 1);
+
+ E get first {
+ if (_head == _tail) throw IterableElementError.noElement();
+ return _table[_head];
+ }
+
+ E get last {
+ if (_head == _tail) throw IterableElementError.noElement();
+ return _table[(_tail - 1) & (_table.length - 1)];
+ }
+
+ E get single {
+ if (_head == _tail) throw IterableElementError.noElement();
+ if (length > 1) throw IterableElementError.tooMany();
+ return _table[_head];
+ }
+
+ E elementAt(int index) {
+ RangeError.checkValidIndex(index, this);
+ return _table[(_head + index) & (_table.length - 1)];
+ }
+
+ List<E> toList({bool growable = true}) {
+ List<E> list;
+ if (growable) {
+ list = <E>[]..length = length;
+ } else {
+ list = List<E>(length);
+ }
+ _writeToList(list);
+ return list;
+ }
+
+ // Collection interface.
+
+ void add(E value) {
+ _add(value);
+ }
+
+ void addAll(Iterable<E> elements) {
+ if (elements is List<E>) {
+ List<E> list = elements;
+ int addCount = list.length;
+ int length = this.length;
+ if (length + addCount >= _table.length) {
+ _preGrow(length + addCount);
+ // After preGrow, all elements are at the start of the list.
+ _table.setRange(length, length + addCount, list, 0);
+ _tail += addCount;
+ } else {
+ // Adding addCount elements won't reach _head.
+ int endSpace = _table.length - _tail;
+ if (addCount < endSpace) {
+ _table.setRange(_tail, _tail + addCount, list, 0);
+ _tail += addCount;
+ } else {
+ int preSpace = addCount - endSpace;
+ _table.setRange(_tail, _tail + endSpace, list, 0);
+ _table.setRange(0, preSpace, list, endSpace);
+ _tail = preSpace;
+ }
+ }
+ _modificationCount++;
+ } else {
+ for (E element in elements) _add(element);
+ }
+ }
+
+ bool remove(Object value) {
+ for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) {
+ E element = _table[i];
+ if (element == value) {
+ _remove(i);
+ _modificationCount++;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void _filterWhere(bool test(E element), bool removeMatching) {
+ int modificationCount = _modificationCount;
+ int i = _head;
+ while (i != _tail) {
+ E element = _table[i];
+ bool remove = identical(removeMatching, test(element));
+ _checkModification(modificationCount);
+ if (remove) {
+ i = _remove(i);
+ modificationCount = ++_modificationCount;
+ } else {
+ i = (i + 1) & (_table.length - 1);
+ }
+ }
+ }
+
+ /// Remove all elements matched by [test].
+ ///
+ /// This method is inefficient since it works by repeatedly removing single
+ /// elements, each of which can take linear time.
+ void removeWhere(bool test(E element)) {
+ _filterWhere(test, true);
+ }
+
+ /// Remove all elements not matched by [test].
+ ///
+ /// This method is inefficient since it works by repeatedly removing single
+ /// elements, each of which can take linear time.
+ void retainWhere(bool test(E element)) {
+ _filterWhere(test, false);
+ }
+
+ void clear() {
+ if (_head != _tail) {
+ for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) {
+ _table[i] = null;
+ }
+ _head = _tail = 0;
+ _modificationCount++;
+ }
+ }
+
+ String toString() => IterableBase.iterableToFullString(this, "{", "}");
+
+ // Queue interface.
+
+ void addLast(E value) {
+ _add(value);
+ }
+
+ void addFirst(E value) {
+ _head = (_head - 1) & (_table.length - 1);
+ _table[_head] = value;
+ if (_head == _tail) _grow();
+ _modificationCount++;
+ }
+
+ E removeFirst() {
+ if (_head == _tail) throw IterableElementError.noElement();
+ _modificationCount++;
+ E result = _table[_head];
+ _table[_head] = null;
+ _head = (_head + 1) & (_table.length - 1);
+ return result;
+ }
+
+ E removeLast() {
+ if (_head == _tail) throw IterableElementError.noElement();
+ _modificationCount++;
+ _tail = (_tail - 1) & (_table.length - 1);
+ E result = _table[_tail];
+ _table[_tail] = null;
+ return result;
+ }
+
+ // Internal helper functions.
+
+ /// Whether [number] is a power of two.
+ ///
+ /// Only works for positive numbers.
+ static bool _isPowerOf2(int number) => (number & (number - 1)) == 0;
+
+ /// Rounds [number] up to the nearest power of 2.
+ ///
+ /// If [number] is a power of 2 already, it is returned.
+ ///
+ /// Only works for positive numbers.
+ static int _nextPowerOf2(int number) {
+ assert(number > 0);
+ number = (number << 1) - 1;
+ for (;;) {
+ int nextNumber = number & (number - 1);
+ if (nextNumber == 0) return number;
+ number = nextNumber;
+ }
+ }
+
+ /// Check if the queue has been modified during iteration.
+ void _checkModification(int expectedModificationCount) {
+ if (expectedModificationCount != _modificationCount) {
+ throw ConcurrentModificationError(this);
+ }
+ }
+
+ /// Adds element at end of queue. Used by both [add] and [addAll].
+ void _add(E element) {
+ _table[_tail] = element;
+ _tail = (_tail + 1) & (_table.length - 1);
+ if (_head == _tail) _grow();
+ _modificationCount++;
+ }
+
+ /// Removes the element at [offset] into [_table].
+ ///
+ /// Removal is performed by linearly moving elements either before or after
+ /// [offset] by one position.
+ ///
+ /// Returns the new offset of the following element. This may be the same
+ /// offset or the following offset depending on how elements are moved
+ /// to fill the hole.
+ int _remove(int offset) {
+ int mask = _table.length - 1;
+ int startDistance = (offset - _head) & mask;
+ int endDistance = (_tail - offset) & mask;
+ if (startDistance < endDistance) {
+ // Closest to start.
+ int i = offset;
+ while (i != _head) {
+ int prevOffset = (i - 1) & mask;
+ _table[i] = _table[prevOffset];
+ i = prevOffset;
+ }
+ _table[_head] = null;
+ _head = (_head + 1) & mask;
+ return (offset + 1) & mask;
+ } else {
+ _tail = (_tail - 1) & mask;
+ int i = offset;
+ while (i != _tail) {
+ int nextOffset = (i + 1) & mask;
+ _table[i] = _table[nextOffset];
+ i = nextOffset;
+ }
+ _table[_tail] = null;
+ return offset;
+ }
+ }
+
+ /// Grow the table when full.
+ void _grow() {
+ List<E> newTable = List<E>(_table.length * 2);
+ int split = _table.length - _head;
+ newTable.setRange(0, split, _table, _head);
+ newTable.setRange(split, split + _head, _table, 0);
+ _head = 0;
+ _tail = _table.length;
+ _table = newTable;
+ }
+
+ int _writeToList(List<E> target) {
+ assert(target.length >= length);
+ if (_head <= _tail) {
+ int length = _tail - _head;
+ target.setRange(0, length, _table, _head);
+ return length;
+ } else {
+ int firstPartSize = _table.length - _head;
+ target.setRange(0, firstPartSize, _table, _head);
+ target.setRange(firstPartSize, firstPartSize + _tail, _table, 0);
+ return _tail + firstPartSize;
+ }
+ }
+
+ /// Grows the table even if it is not full.
+ void _preGrow(int newElementCount) {
+ assert(newElementCount >= length);
+
+ // Add some extra room to ensure that there's room for more elements after
+ // expansion.
+ newElementCount += newElementCount >> 1;
+ int newCapacity = _nextPowerOf2(newElementCount);
+ List<E> newTable = List<E>(newCapacity);
+ _tail = _writeToList(newTable);
+ _table = newTable;
+ _head = 0;
+ }
+}
+
+/// Iterator for a [ListQueue].
+///
+/// Considers any add or remove operation a concurrent modification.
+class _ListQueueIterator<E> implements Iterator<E> {
+ final ListQueue<E> _queue;
+ final int _end;
+ final int _modificationCount;
+ int _position;
+ E _current;
+
+ _ListQueueIterator(ListQueue<E> queue)
+ : _queue = queue,
+ _end = queue._tail,
+ _modificationCount = queue._modificationCount,
+ _position = queue._head;
+
+ E get current => _current;
+
+ bool moveNext() {
+ _queue._checkModification(_modificationCount);
+ if (_position == _end) {
+ _current = null;
+ return false;
+ }
+ _current = _queue._table[_position];
+ _position = (_position + 1) & (_queue._table.length - 1);
+ return true;
+ }
+}
diff --git a/sdk_nnbd/lib/collection/set.dart b/sdk_nnbd/lib/collection/set.dart
new file mode 100644
index 0000000..7508b23
--- /dev/null
+++ b/sdk_nnbd/lib/collection/set.dart
@@ -0,0 +1,630 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Base implementations of [Set].
+part of dart.collection;
+
+/// Mixin implementation of [Set].
+///
+/// This class provides a base implementation of a `Set` that depends only
+/// on the abstract members: [add], [contains], [lookup], [remove],
+/// [iterator], [length] and [toSet].
+///
+/// Some of the methods assume that `toSet` creates a modifiable set.
+/// If using this mixin for an unmodifiable set,
+/// where `toSet` should return an unmodifiable set,
+/// it's necessary to reimplement
+/// [retainAll], [union], [intersection] and [difference].
+///
+/// Implementations of `Set` using this mixin should consider also implementing
+/// `clear` in constant time. The default implementation works by removing every
+/// element.
+abstract class SetMixin<E> implements Set<E> {
+ // This class reimplements all of [IterableMixin].
+ // If/when Dart mixins get more powerful, we should just create a single
+ // Mixin class from IterableMixin and the new methods of this class.
+
+ bool add(E value);
+
+ bool contains(Object element);
+
+ E lookup(Object element);
+
+ bool remove(Object value);
+
+ Iterator<E> get iterator;
+
+ Set<E> toSet();
+
+ int get length;
+
+ bool get isEmpty => length == 0;
+
+ bool get isNotEmpty => length != 0;
+
+ Set<R> cast<R>() => Set.castFrom<E, R>(this);
+ Iterable<E> followedBy(Iterable<E> other) =>
+ FollowedByIterable<E>.firstEfficient(this, other);
+
+ Iterable<T> whereType<T>() => WhereTypeIterable<T>(this);
+
+ void clear() {
+ removeAll(toList());
+ }
+
+ void addAll(Iterable<E> elements) {
+ for (E element in elements) add(element);
+ }
+
+ void removeAll(Iterable<Object> elements) {
+ for (Object element in elements) remove(element);
+ }
+
+ void retainAll(Iterable<Object> elements) {
+ // Create a copy of the set, remove all of elements from the copy,
+ // then remove all remaining elements in copy from this.
+ Set<E> toRemove = toSet();
+ for (Object o in elements) {
+ toRemove.remove(o);
+ }
+ removeAll(toRemove);
+ }
+
+ void removeWhere(bool test(E element)) {
+ List toRemove = [];
+ for (E element in this) {
+ if (test(element)) toRemove.add(element);
+ }
+ removeAll(toRemove);
+ }
+
+ void retainWhere(bool test(E element)) {
+ List toRemove = [];
+ for (E element in this) {
+ if (!test(element)) toRemove.add(element);
+ }
+ removeAll(toRemove);
+ }
+
+ bool containsAll(Iterable<Object> other) {
+ for (Object o in other) {
+ if (!contains(o)) return false;
+ }
+ return true;
+ }
+
+ Set<E> union(Set<E> other) {
+ return toSet()..addAll(other);
+ }
+
+ Set<E> intersection(Set<Object> other) {
+ Set<E> result = toSet();
+ for (E element in this) {
+ if (!other.contains(element)) result.remove(element);
+ }
+ return result;
+ }
+
+ Set<E> difference(Set<Object> other) {
+ Set<E> result = toSet();
+ for (E element in this) {
+ if (other.contains(element)) result.remove(element);
+ }
+ return result;
+ }
+
+ List<E> toList({bool growable = true}) {
+ List<E> result = growable ? (<E>[]..length = length) : List<E>(length);
+ int i = 0;
+ for (E element in this) result[i++] = element;
+ return result;
+ }
+
+ Iterable<T> map<T>(T f(E element)) =>
+ EfficientLengthMappedIterable<E, T>(this, f);
+
+ E get single {
+ if (length > 1) throw IterableElementError.tooMany();
+ Iterator<E> it = iterator;
+ if (!it.moveNext()) throw IterableElementError.noElement();
+ E result = it.current;
+ return result;
+ }
+
+ String toString() => IterableBase.iterableToFullString(this, '{', '}');
+
+ // Copied from IterableMixin.
+ // Should be inherited if we had multi-level mixins.
+
+ Iterable<E> where(bool f(E element)) => WhereIterable<E>(this, f);
+
+ Iterable<T> expand<T>(Iterable<T> f(E element)) =>
+ ExpandIterable<E, T>(this, f);
+
+ void forEach(void f(E element)) {
+ for (E element in this) f(element);
+ }
+
+ E reduce(E combine(E value, E element)) {
+ Iterator<E> iterator = this.iterator;
+ if (!iterator.moveNext()) {
+ throw IterableElementError.noElement();
+ }
+ E value = iterator.current;
+ while (iterator.moveNext()) {
+ value = combine(value, iterator.current);
+ }
+ return value;
+ }
+
+ T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+ var value = initialValue;
+ for (E element in this) value = combine(value, element);
+ return value;
+ }
+
+ bool every(bool f(E element)) {
+ for (E element in this) {
+ if (!f(element)) return false;
+ }
+ return true;
+ }
+
+ String join([String separator = ""]) {
+ Iterator<E> iterator = this.iterator;
+ if (!iterator.moveNext()) return "";
+ StringBuffer buffer = StringBuffer();
+ if (separator == null || separator == "") {
+ do {
+ buffer.write(iterator.current);
+ } while (iterator.moveNext());
+ } else {
+ buffer.write(iterator.current);
+ while (iterator.moveNext()) {
+ buffer.write(separator);
+ buffer.write(iterator.current);
+ }
+ }
+ return buffer.toString();
+ }
+
+ bool any(bool test(E element)) {
+ for (E element in this) {
+ if (test(element)) return true;
+ }
+ return false;
+ }
+
+ Iterable<E> take(int n) {
+ return TakeIterable<E>(this, n);
+ }
+
+ Iterable<E> takeWhile(bool test(E value)) {
+ return TakeWhileIterable<E>(this, test);
+ }
+
+ Iterable<E> skip(int n) {
+ return SkipIterable<E>(this, n);
+ }
+
+ Iterable<E> skipWhile(bool test(E value)) {
+ return SkipWhileIterable<E>(this, test);
+ }
+
+ E get first {
+ Iterator<E> it = iterator;
+ if (!it.moveNext()) {
+ throw IterableElementError.noElement();
+ }
+ return it.current;
+ }
+
+ E get last {
+ Iterator<E> it = iterator;
+ if (!it.moveNext()) {
+ throw IterableElementError.noElement();
+ }
+ E result;
+ do {
+ result = it.current;
+ } while (it.moveNext());
+ return result;
+ }
+
+ E firstWhere(bool test(E value), {E orElse()}) {
+ for (E element in this) {
+ if (test(element)) return element;
+ }
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E lastWhere(bool test(E value), {E orElse()}) {
+ E result;
+ bool foundMatching = false;
+ for (E element in this) {
+ if (test(element)) {
+ result = element;
+ foundMatching = true;
+ }
+ }
+ if (foundMatching) return result;
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E singleWhere(bool test(E value), {E orElse()}) {
+ E result;
+ bool foundMatching = false;
+ for (E element in this) {
+ if (test(element)) {
+ if (foundMatching) {
+ throw IterableElementError.tooMany();
+ }
+ result = element;
+ foundMatching = true;
+ }
+ }
+ if (foundMatching) return result;
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E elementAt(int index) {
+ ArgumentError.checkNotNull(index, "index");
+ RangeError.checkNotNegative(index, "index");
+ int elementIndex = 0;
+ for (E element in this) {
+ if (index == elementIndex) return element;
+ elementIndex++;
+ }
+ throw RangeError.index(index, this, "index", null, elementIndex);
+ }
+}
+
+/// Base implementation of [Set].
+///
+/// This class provides a base implementation of a `Set` that depends only
+/// on the abstract members: [add], [contains], [lookup], [remove],
+/// [iterator], [length] and [toSet].
+///
+/// Some of the methods assume that `toSet` creates a modifiable set.
+/// If using this base class for an unmodifiable set,
+/// where `toSet` should return an unmodifiable set,
+/// it's necessary to reimplement
+/// [retainAll], [union], [intersection] and [difference].
+///
+/// Implementations of `Set` using this base should consider also implementing
+/// `clear` in constant time. The default implementation works by removing every
+/// element.
+abstract class SetBase<E> extends Object with SetMixin<E> {
+ /// Convert a `Set` to a string as `{each, element, as, string}`.
+ ///
+ /// Handles circular references where converting one of the elements
+ /// to a string ends up converting [set] to a string again.
+ static String setToString(Set set) =>
+ IterableBase.iterableToFullString(set, '{', '}');
+}
+
+/// Common internal implementation of some [Set] methods.
+// TODO(35548): Make this mix-in SetMixin, by adding `with SetMixin<E>`
+// and removing the copied members below,
+// when analyzer supports const constructors for mixin applications.
+abstract class _SetBase<E> implements Set<E> {
+ // The following two methods override the ones in SetBase.
+ // It's possible to be more efficient if we have a way to create an empty
+ // set of the correct type.
+ const _SetBase();
+
+ Set<E> _newSet();
+
+ Set<R> _newSimilarSet<R>();
+
+ Set<R> cast<R>() => Set.castFrom<E, R>(this, newSet: _newSimilarSet);
+
+ Set<E> difference(Set<Object> other) {
+ Set<E> result = _newSet();
+ for (var element in this) {
+ if (!other.contains(element)) result.add(element);
+ }
+ return result;
+ }
+
+ Set<E> intersection(Set<Object> other) {
+ Set<E> result = _newSet();
+ for (var element in this) {
+ if (other.contains(element)) result.add(element);
+ }
+ return result;
+ }
+
+ // Subclasses can optimize this further.
+ Set<E> toSet() => _newSet()..addAll(this);
+
+ /// TODO(35548): Remove the following declarations again when the analyzer
+ /// supports mixins with const constructors, and mix in `SetMixin` instead.
+
+ bool get isEmpty => length == 0;
+
+ bool get isNotEmpty => length != 0;
+
+ Iterable<E> followedBy(Iterable<E> other) =>
+ FollowedByIterable<E>.firstEfficient(this, other);
+
+ Iterable<T> whereType<T>() => WhereTypeIterable<T>(this);
+
+ void clear() {
+ removeAll(toList());
+ }
+
+ void addAll(Iterable<E> elements) {
+ for (E element in elements) add(element);
+ }
+
+ void removeAll(Iterable<Object> elements) {
+ for (Object element in elements) remove(element);
+ }
+
+ void retainAll(Iterable<Object> elements) {
+ // Create a copy of the set, remove all of elements from the copy,
+ // then remove all remaining elements in copy from this.
+ Set<E> toRemove = toSet();
+ for (Object o in elements) {
+ toRemove.remove(o);
+ }
+ removeAll(toRemove);
+ }
+
+ void removeWhere(bool test(E element)) {
+ List toRemove = [];
+ for (E element in this) {
+ if (test(element)) toRemove.add(element);
+ }
+ removeAll(toRemove);
+ }
+
+ void retainWhere(bool test(E element)) {
+ List toRemove = [];
+ for (E element in this) {
+ if (!test(element)) toRemove.add(element);
+ }
+ removeAll(toRemove);
+ }
+
+ bool containsAll(Iterable<Object> other) {
+ for (Object o in other) {
+ if (!contains(o)) return false;
+ }
+ return true;
+ }
+
+ Set<E> union(Set<E> other) {
+ return toSet()..addAll(other);
+ }
+
+ List<E> toList({bool growable = true}) {
+ List<E> result = growable ? (<E>[]..length = length) : List<E>(length);
+ int i = 0;
+ for (E element in this) result[i++] = element;
+ return result;
+ }
+
+ Iterable<T> map<T>(T f(E element)) =>
+ EfficientLengthMappedIterable<E, T>(this, f);
+
+ E get single {
+ if (length > 1) throw IterableElementError.tooMany();
+ Iterator<E> it = iterator;
+ if (!it.moveNext()) throw IterableElementError.noElement();
+ E result = it.current;
+ return result;
+ }
+
+ String toString() => IterableBase.iterableToFullString(this, '{', '}');
+
+ Iterable<E> where(bool f(E element)) => WhereIterable<E>(this, f);
+
+ Iterable<T> expand<T>(Iterable<T> f(E element)) =>
+ ExpandIterable<E, T>(this, f);
+
+ void forEach(void f(E element)) {
+ for (E element in this) f(element);
+ }
+
+ E reduce(E combine(E value, E element)) {
+ Iterator<E> iterator = this.iterator;
+ if (!iterator.moveNext()) {
+ throw IterableElementError.noElement();
+ }
+ E value = iterator.current;
+ while (iterator.moveNext()) {
+ value = combine(value, iterator.current);
+ }
+ return value;
+ }
+
+ T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+ var value = initialValue;
+ for (E element in this) value = combine(value, element);
+ return value;
+ }
+
+ bool every(bool f(E element)) {
+ for (E element in this) {
+ if (!f(element)) return false;
+ }
+ return true;
+ }
+
+ String join([String separator = ""]) {
+ Iterator<E> iterator = this.iterator;
+ if (!iterator.moveNext()) return "";
+ StringBuffer buffer = StringBuffer();
+ if (separator == null || separator == "") {
+ do {
+ buffer.write(iterator.current);
+ } while (iterator.moveNext());
+ } else {
+ buffer.write(iterator.current);
+ while (iterator.moveNext()) {
+ buffer.write(separator);
+ buffer.write(iterator.current);
+ }
+ }
+ return buffer.toString();
+ }
+
+ bool any(bool test(E element)) {
+ for (E element in this) {
+ if (test(element)) return true;
+ }
+ return false;
+ }
+
+ Iterable<E> take(int n) {
+ return TakeIterable<E>(this, n);
+ }
+
+ Iterable<E> takeWhile(bool test(E value)) {
+ return TakeWhileIterable<E>(this, test);
+ }
+
+ Iterable<E> skip(int n) {
+ return SkipIterable<E>(this, n);
+ }
+
+ Iterable<E> skipWhile(bool test(E value)) {
+ return SkipWhileIterable<E>(this, test);
+ }
+
+ E get first {
+ Iterator<E> it = iterator;
+ if (!it.moveNext()) {
+ throw IterableElementError.noElement();
+ }
+ return it.current;
+ }
+
+ E get last {
+ Iterator<E> it = iterator;
+ if (!it.moveNext()) {
+ throw IterableElementError.noElement();
+ }
+ E result;
+ do {
+ result = it.current;
+ } while (it.moveNext());
+ return result;
+ }
+
+ E firstWhere(bool test(E value), {E orElse()}) {
+ for (E element in this) {
+ if (test(element)) return element;
+ }
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E lastWhere(bool test(E value), {E orElse()}) {
+ E result;
+ bool foundMatching = false;
+ for (E element in this) {
+ if (test(element)) {
+ result = element;
+ foundMatching = true;
+ }
+ }
+ if (foundMatching) return result;
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E singleWhere(bool test(E value), {E orElse()}) {
+ E result;
+ bool foundMatching = false;
+ for (E element in this) {
+ if (test(element)) {
+ if (foundMatching) {
+ throw IterableElementError.tooMany();
+ }
+ result = element;
+ foundMatching = true;
+ }
+ }
+ if (foundMatching) return result;
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E elementAt(int index) {
+ ArgumentError.checkNotNull(index, "index");
+ RangeError.checkNotNegative(index, "index");
+ int elementIndex = 0;
+ for (E element in this) {
+ if (index == elementIndex) return element;
+ elementIndex++;
+ }
+ throw RangeError.index(index, this, "index", null, elementIndex);
+ }
+}
+
+/// Class used to implement const sets.
+class _UnmodifiableSet<E> extends _SetBase<E> {
+ final Map<E, Null> _map;
+
+ const _UnmodifiableSet(this._map);
+
+ Set<E> _newSet() => LinkedHashSet<E>();
+
+ Set<R> _newSimilarSet<R>() => LinkedHashSet<R>();
+
+ // Lookups use map methods.
+
+ bool contains(Object element) => _map.containsKey(element);
+
+ Iterator<E> get iterator => _map.keys.iterator;
+
+ int get length => _map.length;
+
+ E lookup(Object element) {
+ for (var key in _map.keys) {
+ if (key == element) return key;
+ }
+ return null;
+ }
+
+ // Mutating methods throw.
+
+ bool add(E value) {
+ throw UnsupportedError("Cannot change unmodifiable set");
+ }
+
+ void clear() {
+ throw UnsupportedError("Cannot change unmodifiable set");
+ }
+
+ void addAll(Iterable<E> elements) {
+ throw UnsupportedError("Cannot change unmodifiable set");
+ }
+
+ void removeAll(Iterable<Object> elements) {
+ throw UnsupportedError("Cannot change unmodifiable set");
+ }
+
+ void retainAll(Iterable<Object> elements) {
+ throw UnsupportedError("Cannot change unmodifiable set");
+ }
+
+ void removeWhere(bool test(E element)) {
+ throw UnsupportedError("Cannot change unmodifiable set");
+ }
+
+ void retainWhere(bool test(E element)) {
+ throw UnsupportedError("Cannot change unmodifiable set");
+ }
+
+ bool remove(Object value) {
+ throw UnsupportedError("Cannot change unmodifiable set");
+ }
+}
diff --git a/sdk_nnbd/lib/collection/splay_tree.dart b/sdk_nnbd/lib/collection/splay_tree.dart
new file mode 100644
index 0000000..5f71934
--- /dev/null
+++ b/sdk_nnbd/lib/collection/splay_tree.dart
@@ -0,0 +1,831 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.collection;
+
+typedef _Predicate<T> = bool Function(T value);
+
+/// A node in a splay tree. It holds the sorting key and the left
+/// and right children in the tree.
+class _SplayTreeNode<K> {
+ final K key;
+ _SplayTreeNode<K> left;
+ _SplayTreeNode<K> right;
+
+ _SplayTreeNode(this.key);
+}
+
+/// A node in a splay tree based map.
+///
+/// A [_SplayTreeNode] that also contains a value
+class _SplayTreeMapNode<K, V> extends _SplayTreeNode<K> {
+ V value;
+ _SplayTreeMapNode(K key, this.value) : super(key);
+}
+
+/// A splay tree is a self-balancing binary search tree.
+///
+/// It has the additional property that recently accessed elements
+/// are quick to access again.
+/// It performs basic operations such as insertion, look-up and
+/// removal, in O(log(n)) amortized time.
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
+ // The root node of the splay tree. It will contain either the last
+ // element inserted or the last element looked up.
+ Node get _root;
+ set _root(Node newValue);
+
+ // The dummy node used when performing a splay on the tree. Reusing it
+ // avoids allocating a node each time a splay is performed.
+ Node get _dummy;
+
+ // Number of elements in the splay tree.
+ int _count = 0;
+
+ /// Counter incremented whenever the keys in the map changes.
+ ///
+ /// Used to detect concurrent modifications.
+ int _modificationCount = 0;
+
+ /// Counter incremented whenever the tree structure changes.
+ ///
+ /// Used to detect that an in-place traversal cannot use
+ /// cached information that relies on the tree structure.
+ int _splayCount = 0;
+
+ /// The comparator that is used for this splay tree.
+ Comparator<K> get _comparator;
+
+ /// The predicate to determine that a given object is a valid key.
+ _Predicate get _validKey;
+
+ /// Comparison used to compare keys.
+ int _compare(K key1, K key2);
+
+ /// Perform the splay operation for the given key. Moves the node with
+ /// the given key to the top of the tree. If no node has the given
+ /// key, the last node on the search path is moved to the top of the
+ /// tree. This is the simplified top-down splaying algorithm from:
+ /// "Self-adjusting Binary Search Trees" by Sleator and Tarjan.
+ ///
+ /// Returns the result of comparing the new root of the tree to [key].
+ /// Returns -1 if the table is empty.
+ int _splay(K key) {
+ if (_root == null) return -1;
+
+ // The right child of the dummy node will hold
+ // the L tree of the algorithm. The left child of the dummy node
+ // will hold the R tree of the algorithm. Using a dummy node, left
+ // and right will always be nodes and we avoid special cases.
+ Node left = _dummy;
+ Node right = _dummy;
+ Node current = _root;
+ int comp;
+ while (true) {
+ comp = _compare(current.key, key);
+ if (comp > 0) {
+ if (current.left == null) break;
+ comp = _compare(current.left.key, key);
+ if (comp > 0) {
+ // Rotate right.
+ _SplayTreeNode<K> tmp = current.left;
+ current.left = tmp.right;
+ tmp.right = current;
+ current = tmp;
+ if (current.left == null) break;
+ }
+ // Link right.
+ right.left = current;
+ right = current;
+ current = current.left;
+ } else if (comp < 0) {
+ if (current.right == null) break;
+ comp = _compare(current.right.key, key);
+ if (comp < 0) {
+ // Rotate left.
+ Node tmp = current.right;
+ current.right = tmp.left;
+ tmp.left = current;
+ current = tmp;
+ if (current.right == null) break;
+ }
+ // Link left.
+ left.right = current;
+ left = current;
+ current = current.right;
+ } else {
+ break;
+ }
+ }
+ // Assemble.
+ left.right = current.left;
+ right.left = current.right;
+ current.left = _dummy.right;
+ current.right = _dummy.left;
+ _root = current;
+
+ _dummy.right = null;
+ _dummy.left = null;
+ _splayCount++;
+ return comp;
+ }
+
+ // Emulates splaying with a key that is smaller than any in the subtree
+ // anchored at [node].
+ // and that node is returned. It should replace the reference to [node]
+ // in any parent tree or root pointer.
+ external Node _splayMin(Node node);
+
+ // Emulates splaying with a key that is greater than any in the subtree
+ // anchored at [node].
+ // After this, the largest element in the tree is the root of the subtree,
+ // and that node is returned. It should replace the reference to [node]
+ // in any parent tree or root pointer.
+ external Node _splayMax(Node node);
+
+ Node _remove(K key) {
+ if (_root == null) return null;
+ int comp = _splay(key);
+ if (comp != 0) return null;
+ Node result = _root;
+ _count--;
+ // assert(_count >= 0);
+ if (_root.left == null) {
+ _root = _root.right;
+ } else {
+ Node right = _root.right;
+ // Splay to make sure that the new root has an empty right child.
+ _root = _splayMax(_root.left);
+ // Insert the original right child as the right child of the new
+ // root.
+ _root.right = right;
+ }
+ _modificationCount++;
+ return result;
+ }
+
+ /// Adds a new root node with the given [key] or [value].
+ ///
+ /// The [comp] value is the result of comparing the existing root's key
+ /// with key.
+ void _addNewRoot(Node node, int comp) {
+ _count++;
+ _modificationCount++;
+ if (_root == null) {
+ _root = node;
+ return;
+ }
+ // assert(_count >= 0);
+ if (comp < 0) {
+ node.left = _root;
+ node.right = _root.right;
+ _root.right = null;
+ } else {
+ node.right = _root;
+ node.left = _root.left;
+ _root.left = null;
+ }
+ _root = node;
+ }
+
+ Node get _first {
+ if (_root == null) return null;
+ _root = _splayMin(_root);
+ return _root;
+ }
+
+ Node get _last {
+ if (_root == null) return null;
+ _root = _splayMax(_root);
+ return _root;
+ }
+
+ void _clear() {
+ _root = null;
+ _count = 0;
+ _modificationCount++;
+ }
+}
+
+class _TypeTest<T> {
+ bool test(v) => v is T;
+}
+
+int _dynamicCompare(dynamic a, dynamic b) => Comparable.compare(a, b);
+
+Comparator<K> _defaultCompare<K>() {
+ // If K <: Comparable, then we can just use Comparable.compare
+ // with no casts.
+ Object compare = Comparable.compare;
+ if (compare is Comparator<K>) {
+ return compare;
+ }
+ // Otherwise wrap and cast the arguments on each call.
+ return _dynamicCompare;
+}
+
+/// A [Map] of objects that can be ordered relative to each other.
+///
+/// The map is based on a self-balancing binary tree. It allows most operations
+/// in amortized logarithmic time.
+///
+/// Keys of the map are compared using the `compare` function passed in
+/// the constructor, both for ordering and for equality.
+/// If the map contains only the key `a`, then `map.containsKey(b)`
+/// will return `true` if and only if `compare(a, b) == 0`,
+/// and the value of `a == b` is not even checked.
+/// If the compare function is omitted, the objects are assumed to be
+/// [Comparable], and are compared using their [Comparable.compareTo] method.
+/// Non-comparable objects (including `null`) will not work as keys
+/// in that case.
+///
+/// To allow calling [operator []], [remove] or [containsKey] with objects
+/// that are not supported by the `compare` function, an extra `isValidKey`
+/// predicate function can be supplied. This function is tested before
+/// using the `compare` function on an argument value that may not be a [K]
+/// value. If omitted, the `isValidKey` function defaults to testing if the
+/// value is a [K].
+class SplayTreeMap<K, V> extends _SplayTree<K, _SplayTreeMapNode<K, V>>
+ with MapMixin<K, V> {
+ _SplayTreeMapNode<K, V> _root;
+ final _SplayTreeMapNode<K, V> _dummy = _SplayTreeMapNode<K, V>(null, null);
+
+ Comparator<K> _comparator;
+ _Predicate _validKey;
+
+ SplayTreeMap([int compare(K key1, K key2), bool isValidKey(potentialKey)])
+ : _comparator = compare ?? _defaultCompare<K>(),
+ _validKey = isValidKey ?? ((v) => v is K);
+
+ /// Creates a [SplayTreeMap] that contains all key/value pairs of [other].
+ ///
+ /// The keys must all be instances of [K] and the values of [V].
+ /// The [other] map itself can have any type.
+ factory SplayTreeMap.from(Map other,
+ [int compare(K key1, K key2), bool isValidKey(potentialKey)]) {
+ SplayTreeMap<K, V> result = SplayTreeMap<K, V>(compare, isValidKey);
+ other.forEach((k, v) {
+ result[k] = v;
+ });
+ return result;
+ }
+
+ /// Creates a [SplayTreeMap] that contains all key/value pairs of [other].
+ factory SplayTreeMap.of(Map<K, V> other,
+ [int compare(K key1, K key2), bool isValidKey(potentialKey)]) =>
+ SplayTreeMap<K, V>(compare, isValidKey)..addAll(other);
+
+ /// Creates a [SplayTreeMap] where the keys and values are computed from the
+ /// [iterable].
+ ///
+ /// For each element of the [iterable] this constructor computes a key/value
+ /// pair, by applying [key] and [value] respectively.
+ ///
+ /// The keys of the key/value pairs do not need to be unique. The last
+ /// occurrence of a key will simply overwrite any previous value.
+ ///
+ /// If no functions are specified for [key] and [value] the default is to
+ /// use the iterable value itself.
+ factory SplayTreeMap.fromIterable(Iterable iterable,
+ {K key(element),
+ V value(element),
+ int compare(K key1, K key2),
+ bool isValidKey(potentialKey)}) {
+ SplayTreeMap<K, V> map = SplayTreeMap<K, V>(compare, isValidKey);
+ MapBase._fillMapWithMappedIterable(map, iterable, key, value);
+ return map;
+ }
+
+ /// Creates a [SplayTreeMap] associating the given [keys] to [values].
+ ///
+ /// This constructor iterates over [keys] and [values] and maps each element
+ /// of [keys] to the corresponding element of [values].
+ ///
+ /// If [keys] contains the same object multiple times, the last occurrence
+ /// overwrites the previous value.
+ ///
+ /// It is an error if the two [Iterable]s don't have the same length.
+ factory SplayTreeMap.fromIterables(Iterable<K> keys, Iterable<V> values,
+ [int compare(K key1, K key2), bool isValidKey(potentialKey)]) {
+ SplayTreeMap<K, V> map = SplayTreeMap<K, V>(compare, isValidKey);
+ MapBase._fillMapWithIterables(map, keys, values);
+ return map;
+ }
+
+ int _compare(K key1, K key2) => _comparator(key1, key2);
+
+ SplayTreeMap._internal();
+
+ V operator [](Object key) {
+ if (!_validKey(key)) return null;
+ if (_root != null) {
+ int comp = _splay(key);
+ if (comp == 0) {
+ return _root.value;
+ }
+ }
+ return null;
+ }
+
+ V remove(Object key) {
+ if (!_validKey(key)) return null;
+ _SplayTreeMapNode<K, V> mapRoot = _remove(key);
+ if (mapRoot != null) return mapRoot.value;
+ return null;
+ }
+
+ void operator []=(K key, V value) {
+ if (key == null) throw ArgumentError(key);
+ // Splay on the key to move the last node on the search path for
+ // the key to the root of the tree.
+ int comp = _splay(key);
+ if (comp == 0) {
+ _root.value = value;
+ return;
+ }
+ _addNewRoot(_SplayTreeMapNode(key, value), comp);
+ }
+
+ V putIfAbsent(K key, V ifAbsent()) {
+ if (key == null) throw ArgumentError(key);
+ int comp = _splay(key);
+ if (comp == 0) {
+ return _root.value;
+ }
+ int modificationCount = _modificationCount;
+ int splayCount = _splayCount;
+ V value = ifAbsent();
+ if (modificationCount != _modificationCount) {
+ throw ConcurrentModificationError(this);
+ }
+ if (splayCount != _splayCount) {
+ comp = _splay(key);
+ // Key is still not there, otherwise _modificationCount would be changed.
+ assert(comp != 0);
+ }
+ _addNewRoot(_SplayTreeMapNode(key, value), comp);
+ return value;
+ }
+
+ void addAll(Map<K, V> other) {
+ other.forEach((K key, V value) {
+ this[key] = value;
+ });
+ }
+
+ bool get isEmpty {
+ return (_root == null);
+ }
+
+ bool get isNotEmpty => !isEmpty;
+
+ void forEach(void f(K key, V value)) {
+ Iterator<_SplayTreeNode<K>> nodes = _SplayTreeNodeIterator<K>(this);
+ while (nodes.moveNext()) {
+ _SplayTreeMapNode<K, V> node = nodes.current;
+ f(node.key, node.value);
+ }
+ }
+
+ int get length {
+ return _count;
+ }
+
+ void clear() {
+ _clear();
+ }
+
+ bool containsKey(Object key) {
+ return _validKey(key) && _splay(key) == 0;
+ }
+
+ bool containsValue(Object value) {
+ int initialSplayCount = _splayCount;
+ bool visit(_SplayTreeMapNode node) {
+ while (node != null) {
+ if (node.value == value) return true;
+ if (initialSplayCount != _splayCount) {
+ throw ConcurrentModificationError(this);
+ }
+ if (node.right != null && visit(node.right)) return true;
+ node = node.left;
+ }
+ return false;
+ }
+
+ return visit(_root);
+ }
+
+ Iterable<K> get keys => _SplayTreeKeyIterable<K>(this);
+
+ Iterable<V> get values => _SplayTreeValueIterable<K, V>(this);
+
+ /// Get the first key in the map. Returns [:null:] if the map is empty.
+ K firstKey() {
+ if (_root == null) return null;
+ return _first.key;
+ }
+
+ /// Get the last key in the map. Returns [:null:] if the map is empty.
+ K lastKey() {
+ if (_root == null) return null;
+ return _last.key;
+ }
+
+ /// Get the last key in the map that is strictly smaller than [key]. Returns
+ /// [:null:] if no key was not found.
+ K lastKeyBefore(K key) {
+ if (key == null) throw ArgumentError(key);
+ if (_root == null) return null;
+ int comp = _splay(key);
+ if (comp < 0) return _root.key;
+ _SplayTreeNode<K> node = _root.left;
+ if (node == null) return null;
+ while (node.right != null) {
+ node = node.right;
+ }
+ return node.key;
+ }
+
+ /// Get the first key in the map that is strictly larger than [key]. Returns
+ /// [:null:] if no key was not found.
+ K firstKeyAfter(K key) {
+ if (key == null) throw ArgumentError(key);
+ if (_root == null) return null;
+ int comp = _splay(key);
+ if (comp > 0) return _root.key;
+ _SplayTreeNode<K> node = _root.right;
+ if (node == null) return null;
+ while (node.left != null) {
+ node = node.left;
+ }
+ return node.key;
+ }
+}
+
+abstract class _SplayTreeIterator<K, T> implements Iterator<T> {
+ final _SplayTree<K, _SplayTreeNode<K>> _tree;
+
+ /// Worklist of nodes to visit.
+ ///
+ /// These nodes have been passed over on the way down in a
+ /// depth-first left-to-right traversal. Visiting each node,
+ /// and their right subtrees will visit the remainder of
+ /// the nodes of a full traversal.
+ ///
+ /// Only valid as long as the original tree isn't reordered.
+ final List<_SplayTreeNode<K>> _workList = <_SplayTreeNode<K>>[];
+
+ /// Original modification counter of [_tree].
+ ///
+ /// Incremented on [_tree] when a key is added or removed.
+ /// If it changes, iteration is aborted.
+ ///
+ /// Not final because some iterators may modify the tree knowingly,
+ /// and they update the modification count in that case.
+ int _modificationCount;
+
+ /// Count of splay operations on [_tree] when [_workList] was built.
+ ///
+ /// If the splay count on [_tree] increases, [_workList] becomes invalid.
+ int _splayCount;
+
+ /// Current node.
+ _SplayTreeNode<K> _currentNode;
+
+ _SplayTreeIterator(_SplayTree<K, _SplayTreeNode<K>> tree)
+ : _tree = tree,
+ _modificationCount = tree._modificationCount,
+ _splayCount = tree._splayCount {
+ _findLeftMostDescendent(tree._root);
+ }
+
+ _SplayTreeIterator.startAt(_SplayTree<K, _SplayTreeNode<K>> tree, K startKey)
+ : _tree = tree,
+ _modificationCount = tree._modificationCount {
+ if (tree._root == null) return;
+ int compare = tree._splay(startKey);
+ _splayCount = tree._splayCount;
+ if (compare < 0) {
+ // Don't include the root, start at the next element after the root.
+ _findLeftMostDescendent(tree._root.right);
+ } else {
+ _workList.add(tree._root);
+ }
+ }
+
+ T get current {
+ if (_currentNode == null) return null;
+ return _getValue(_currentNode);
+ }
+
+ void _findLeftMostDescendent(_SplayTreeNode<K> node) {
+ while (node != null) {
+ _workList.add(node);
+ node = node.left;
+ }
+ }
+
+ /// Called when the tree structure of the tree has changed.
+ ///
+ /// This can be caused by a splay operation.
+ /// If the key-set changes, iteration is aborted before getting
+ /// here, so we know that the keys are the same as before, it's
+ /// only the tree that has been reordered.
+ void _rebuildWorkList(_SplayTreeNode<K> currentNode) {
+ assert(_workList.isNotEmpty);
+ _workList.clear();
+ if (currentNode == null) {
+ _findLeftMostDescendent(_tree._root);
+ } else {
+ _tree._splay(currentNode.key);
+ _findLeftMostDescendent(_tree._root.right);
+ assert(_workList.isNotEmpty);
+ }
+ }
+
+ bool moveNext() {
+ if (_modificationCount != _tree._modificationCount) {
+ throw ConcurrentModificationError(_tree);
+ }
+ // Picks the next element in the worklist as current.
+ // Updates the worklist with the left-most path of the current node's
+ // right-hand child.
+ // If the worklist is no longer valid (after a splay), it is rebuild
+ // from scratch.
+ if (_workList.isEmpty) {
+ _currentNode = null;
+ return false;
+ }
+ if (_tree._splayCount != _splayCount && _currentNode != null) {
+ _rebuildWorkList(_currentNode);
+ }
+ _currentNode = _workList.removeLast();
+ _findLeftMostDescendent(_currentNode.right);
+ return true;
+ }
+
+ T _getValue(_SplayTreeNode<K> node);
+}
+
+class _SplayTreeKeyIterable<K> extends EfficientLengthIterable<K> {
+ _SplayTree<K, _SplayTreeNode<K>> _tree;
+ _SplayTreeKeyIterable(this._tree);
+ int get length => _tree._count;
+ bool get isEmpty => _tree._count == 0;
+ Iterator<K> get iterator => _SplayTreeKeyIterator<K>(_tree);
+
+ Set<K> toSet() {
+ SplayTreeSet<K> set = SplayTreeSet<K>(_tree._comparator, _tree._validKey);
+ set._count = _tree._count;
+ set._root = set._copyNode(_tree._root);
+ return set;
+ }
+}
+
+class _SplayTreeValueIterable<K, V> extends EfficientLengthIterable<V> {
+ SplayTreeMap<K, V> _map;
+ _SplayTreeValueIterable(this._map);
+ int get length => _map._count;
+ bool get isEmpty => _map._count == 0;
+ Iterator<V> get iterator => _SplayTreeValueIterator<K, V>(_map);
+}
+
+class _SplayTreeKeyIterator<K> extends _SplayTreeIterator<K, K> {
+ _SplayTreeKeyIterator(_SplayTree<K, _SplayTreeNode<K>> map) : super(map);
+ K _getValue(_SplayTreeNode<K> node) => node.key;
+}
+
+class _SplayTreeValueIterator<K, V> extends _SplayTreeIterator<K, V> {
+ _SplayTreeValueIterator(SplayTreeMap<K, V> map) : super(map);
+ V _getValue(_SplayTreeNode<K> node) {
+ _SplayTreeMapNode<K, V> mapNode = node;
+ return mapNode.value;
+ }
+}
+
+class _SplayTreeNodeIterator<K>
+ extends _SplayTreeIterator<K, _SplayTreeNode<K>> {
+ _SplayTreeNodeIterator(_SplayTree<K, _SplayTreeNode<K>> tree) : super(tree);
+ _SplayTreeNodeIterator.startAt(
+ _SplayTree<K, _SplayTreeNode<K>> tree, K startKey)
+ : super.startAt(tree, startKey);
+ _SplayTreeNode<K> _getValue(_SplayTreeNode<K> node) => node;
+}
+
+/// A [Set] of objects that can be ordered relative to each other.
+///
+/// The set is based on a self-balancing binary tree. It allows most operations
+/// in amortized logarithmic time.
+///
+/// Elements of the set are compared using the `compare` function passed in
+/// the constructor, both for ordering and for equality.
+/// If the set contains only an object `a`, then `set.contains(b)`
+/// will return `true` if and only if `compare(a, b) == 0`,
+/// and the value of `a == b` is not even checked.
+/// If the compare function is omitted, the objects are assumed to be
+/// [Comparable], and are compared using their [Comparable.compareTo] method.
+/// Non-comparable objects (including `null`) will not work as an element
+/// in that case.
+class SplayTreeSet<E> extends _SplayTree<E, _SplayTreeNode<E>>
+ with IterableMixin<E>, SetMixin<E> {
+ _SplayTreeNode<E> _root;
+ final _SplayTreeNode<E> _dummy = _SplayTreeNode<E>(null);
+
+ Comparator<E> _comparator;
+ _Predicate _validKey;
+
+ /// Create a new [SplayTreeSet] with the given compare function.
+ ///
+ /// If the [compare] function is omitted, it defaults to [Comparable.compare],
+ /// and the elements must be comparable.
+ ///
+ /// A provided `compare` function may not work on all objects. It may not even
+ /// work on all `E` instances.
+ ///
+ /// For operations that add elements to the set, the user is supposed to not
+ /// pass in objects that doesn't work with the compare function.
+ ///
+ /// The methods [contains], [remove], [lookup], [removeAll] or [retainAll]
+ /// are typed to accept any object(s), and the [isValidKey] test can used to
+ /// filter those objects before handing them to the `compare` function.
+ ///
+ /// If [isValidKey] is provided, only values satisfying `isValidKey(other)`
+ /// are compared using the `compare` method in the methods mentioned above.
+ /// If the `isValidKey` function returns false for an object, it is assumed to
+ /// not be in the set.
+ ///
+ /// If omitted, the `isValidKey` function defaults to checking against the
+ /// type parameter: `other is E`.
+ SplayTreeSet([int compare(E key1, E key2), bool isValidKey(potentialKey)])
+ : _comparator = compare ?? _defaultCompare<E>(),
+ _validKey = isValidKey ?? ((v) => v is E);
+
+ /// Creates a [SplayTreeSet] that contains all [elements].
+ ///
+ /// The set works as if created by `new SplayTreeSet<E>(compare, isValidKey)`.
+ ///
+ /// All the [elements] should be instances of [E] and valid arguments to
+ /// [compare].
+ /// The `elements` iterable itself may have any element type, so this
+ /// constructor can be used to down-cast a `Set`, for example as:
+ /// ```dart
+ /// Set<SuperType> superSet = ...;
+ /// Set<SubType> subSet =
+ /// new SplayTreeSet<SubType>.from(superSet.whereType<SubType>());
+ /// ```
+ factory SplayTreeSet.from(Iterable elements,
+ [int compare(E key1, E key2), bool isValidKey(potentialKey)]) {
+ SplayTreeSet<E> result = SplayTreeSet<E>(compare, isValidKey);
+ for (final element in elements) {
+ E e = element;
+ result.add(e);
+ }
+ return result;
+ }
+
+ /// Creates a [SplayTreeSet] from [elements].
+ ///
+ /// The set works as if created by `new SplayTreeSet<E>(compare, isValidKey)`.
+ ///
+ /// All the [elements] should be valid as arguments to the [compare] function.
+ factory SplayTreeSet.of(Iterable<E> elements,
+ [int compare(E key1, E key2), bool isValidKey(potentialKey)]) =>
+ SplayTreeSet(compare, isValidKey)..addAll(elements);
+
+ Set<T> _newSet<T>() =>
+ SplayTreeSet<T>((T a, T b) => _comparator(a as E, b as E), _validKey);
+
+ Set<R> cast<R>() => Set.castFrom<E, R>(this, newSet: _newSet);
+ int _compare(E e1, E e2) => _comparator(e1, e2);
+
+ // From Iterable.
+
+ Iterator<E> get iterator => _SplayTreeKeyIterator<E>(this);
+
+ int get length => _count;
+ bool get isEmpty => _root == null;
+ bool get isNotEmpty => _root != null;
+
+ E get first {
+ if (_count == 0) throw IterableElementError.noElement();
+ return _first.key;
+ }
+
+ E get last {
+ if (_count == 0) throw IterableElementError.noElement();
+ return _last.key;
+ }
+
+ E get single {
+ if (_count == 0) throw IterableElementError.noElement();
+ if (_count > 1) throw IterableElementError.tooMany();
+ return _root.key;
+ }
+
+ // From Set.
+ bool contains(Object element) {
+ return _validKey(element) && _splay(element) == 0;
+ }
+
+ bool add(E element) {
+ int compare = _splay(element);
+ if (compare == 0) return false;
+ _addNewRoot(_SplayTreeNode(element), compare);
+ return true;
+ }
+
+ bool remove(Object object) {
+ if (!_validKey(object)) return false;
+ return _remove(object) != null;
+ }
+
+ void addAll(Iterable<E> elements) {
+ for (E element in elements) {
+ int compare = _splay(element);
+ if (compare != 0) {
+ _addNewRoot(_SplayTreeNode(element), compare);
+ }
+ }
+ }
+
+ void removeAll(Iterable<Object> elements) {
+ for (Object element in elements) {
+ if (_validKey(element)) _remove(element);
+ }
+ }
+
+ void retainAll(Iterable<Object> elements) {
+ // Build a set with the same sense of equality as this set.
+ SplayTreeSet<E> retainSet = SplayTreeSet<E>(_comparator, _validKey);
+ int modificationCount = _modificationCount;
+ for (Object object in elements) {
+ if (modificationCount != _modificationCount) {
+ // The iterator should not have side effects.
+ throw ConcurrentModificationError(this);
+ }
+ // Equivalent to this.contains(object).
+ if (_validKey(object) && _splay(object) == 0) {
+ retainSet.add(_root.key);
+ }
+ }
+ // Take over the elements from the retained set, if it differs.
+ if (retainSet._count != _count) {
+ _root = retainSet._root;
+ _count = retainSet._count;
+ _modificationCount++;
+ }
+ }
+
+ E lookup(Object object) {
+ if (!_validKey(object)) return null;
+ int comp = _splay(object);
+ if (comp != 0) return null;
+ return _root.key;
+ }
+
+ Set<E> intersection(Set<Object> other) {
+ Set<E> result = SplayTreeSet<E>(_comparator, _validKey);
+ for (E element in this) {
+ if (other.contains(element)) result.add(element);
+ }
+ return result;
+ }
+
+ Set<E> difference(Set<Object> other) {
+ Set<E> result = SplayTreeSet<E>(_comparator, _validKey);
+ for (E element in this) {
+ if (!other.contains(element)) result.add(element);
+ }
+ return result;
+ }
+
+ Set<E> union(Set<E> other) {
+ return _clone()..addAll(other);
+ }
+
+ SplayTreeSet<E> _clone() {
+ var set = SplayTreeSet<E>(_comparator, _validKey);
+ set._count = _count;
+ set._root = _copyNode(_root);
+ return set;
+ }
+
+ // Copies the structure of a SplayTree into a new similar structure.
+ // Works on _SplayTreeMapNode as well, but only copies the keys,
+ _SplayTreeNode<E> _copyNode(_SplayTreeNode<E> node) {
+ if (node == null) return null;
+ return _SplayTreeNode<E>(node.key)
+ ..left = _copyNode(node.left)
+ ..right = _copyNode(node.right);
+ }
+
+ void clear() {
+ _clear();
+ }
+
+ Set<E> toSet() => _clone();
+
+ String toString() => IterableBase.iterableToFullString(this, '{', '}');
+}
diff --git a/sdk_nnbd/lib/convert/ascii.dart b/sdk_nnbd/lib/convert/ascii.dart
new file mode 100644
index 0000000..35105ac
--- /dev/null
+++ b/sdk_nnbd/lib/convert/ascii.dart
@@ -0,0 +1,287 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// An instance of the default implementation of the [AsciiCodec].
+///
+/// This instance provides a convenient access to the most common ASCII
+/// use cases.
+///
+/// Examples:
+/// ```dart
+/// var encoded = ascii.encode("This is ASCII!");
+/// var decoded = ascii.decode([0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
+/// 0x20, 0x41, 0x53, 0x43, 0x49, 0x49, 0x21]);
+/// ```
+const AsciiCodec ascii = AsciiCodec();
+
+const int _asciiMask = 0x7F;
+
+/// An [AsciiCodec] allows encoding strings as ASCII bytes
+/// and decoding ASCII bytes to strings.
+class AsciiCodec extends Encoding {
+ final bool _allowInvalid;
+
+ /// Instantiates a new [AsciiCodec].
+ ///
+ /// If [allowInvalid] is true, the [decode] method and the converter
+ /// returned by [decoder] will default to allowing invalid values.
+ /// If allowing invalid values, the values will be decoded into the Unicode
+ /// Replacement character (U+FFFD). If not, an exception will be thrown.
+ /// Calls to the [decode] method can choose to override this default.
+ ///
+ /// Encoders will not accept invalid (non ASCII) characters.
+ const AsciiCodec({bool allowInvalid = false}) : _allowInvalid = allowInvalid;
+
+ /// The name of this codec, "us-ascii".
+ String get name => "us-ascii";
+
+ Uint8List encode(String source) => encoder.convert(source);
+
+ /// Decodes the ASCII [bytes] (a list of unsigned 7-bit integers) to the
+ /// corresponding string.
+ ///
+ /// If [bytes] contains values that are not in the range 0 .. 127, the decoder
+ /// will eventually throw a [FormatException].
+ ///
+ /// If [allowInvalid] is not provided, it defaults to the value used to create
+ /// this [AsciiCodec].
+ String decode(List<int> bytes, {bool allowInvalid}) {
+ allowInvalid ??= _allowInvalid;
+ if (allowInvalid) {
+ return const AsciiDecoder(allowInvalid: true).convert(bytes);
+ } else {
+ return const AsciiDecoder(allowInvalid: false).convert(bytes);
+ }
+ }
+
+ AsciiEncoder get encoder => const AsciiEncoder();
+
+ AsciiDecoder get decoder => _allowInvalid
+ ? const AsciiDecoder(allowInvalid: true)
+ : const AsciiDecoder(allowInvalid: false);
+}
+
+// Superclass for [AsciiEncoder] and [Latin1Encoder].
+// Generalizes common operations that only differ by a mask;
+class _UnicodeSubsetEncoder extends Converter<String, List<int>> {
+ final int _subsetMask;
+
+ const _UnicodeSubsetEncoder(this._subsetMask);
+
+ /// Converts the [String] into a list of its code units.
+ ///
+ /// If [start] and [end] are provided, only the substring
+ /// `string.substring(start, end)` is used as input to the conversion.
+ Uint8List convert(String string, [int start = 0, int end]) {
+ var stringLength = string.length;
+ end = RangeError.checkValidRange(start, end, stringLength);
+ var length = end - start;
+ var result = Uint8List(length);
+ for (var i = 0; i < length; i++) {
+ var codeUnit = string.codeUnitAt(start + i);
+ if ((codeUnit & ~_subsetMask) != 0) {
+ throw ArgumentError.value(
+ string, "string", "Contains invalid characters.");
+ }
+ result[i] = codeUnit;
+ }
+ return result;
+ }
+
+ /// Starts a chunked conversion.
+ ///
+ /// The converter works more efficiently if the given [sink] is a
+ /// [ByteConversionSink].
+ StringConversionSink startChunkedConversion(Sink<List<int>> sink) {
+ return _UnicodeSubsetEncoderSink(_subsetMask,
+ sink is ByteConversionSink ? sink : ByteConversionSink.from(sink));
+ }
+
+ // Override the base-class' bind, to provide a better type.
+ Stream<List<int>> bind(Stream<String> stream) => super.bind(stream);
+}
+
+/// This class converts strings of only ASCII characters to bytes.
+class AsciiEncoder extends _UnicodeSubsetEncoder {
+ const AsciiEncoder() : super(_asciiMask);
+}
+
+/// This class encodes chunked strings to bytes (unsigned 8-bit
+/// integers).
+class _UnicodeSubsetEncoderSink extends StringConversionSinkBase {
+ final ByteConversionSink _sink;
+ final int _subsetMask;
+
+ _UnicodeSubsetEncoderSink(this._subsetMask, this._sink);
+
+ void close() {
+ _sink.close();
+ }
+
+ void addSlice(String source, int start, int end, bool isLast) {
+ RangeError.checkValidRange(start, end, source.length);
+ for (var i = start; i < end; i++) {
+ var codeUnit = source.codeUnitAt(i);
+ if ((codeUnit & ~_subsetMask) != 0) {
+ throw ArgumentError(
+ "Source contains invalid character with code point: $codeUnit.");
+ }
+ }
+ _sink.add(source.codeUnits.sublist(start, end));
+ if (isLast) {
+ close();
+ }
+ }
+}
+
+/// This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
+/// to a string.
+abstract class _UnicodeSubsetDecoder extends Converter<List<int>, String> {
+ final bool _allowInvalid;
+ final int _subsetMask;
+
+ /// Instantiates a new decoder.
+ ///
+ /// The [_allowInvalid] argument defines how [convert] deals
+ /// with invalid bytes.
+ ///
+ /// The [_subsetMask] argument is a bit mask used to define the subset
+ /// of Unicode being decoded. Use [_LATIN1_MASK] for Latin-1 (8-bit) or
+ /// [_asciiMask] for ASCII (7-bit).
+ ///
+ /// If [_allowInvalid] is `true`, [convert] replaces invalid bytes with the
+ /// Unicode Replacement character `U+FFFD` (�).
+ /// Otherwise it throws a [FormatException].
+ const _UnicodeSubsetDecoder(this._allowInvalid, this._subsetMask);
+
+ /// Converts the [bytes] (a list of unsigned 7- or 8-bit integers) to the
+ /// corresponding string.
+ ///
+ /// If [start] and [end] are provided, only the sub-list of bytes from
+ /// `start` to `end` (`end` not inclusive) is used as input to the conversion.
+ String convert(List<int> bytes, [int start = 0, int end]) {
+ var byteCount = bytes.length;
+ RangeError.checkValidRange(start, end, byteCount);
+ end ??= byteCount;
+
+ for (var i = start; i < end; i++) {
+ var byte = bytes[i];
+ if ((byte & ~_subsetMask) != 0) {
+ if (!_allowInvalid) {
+ throw FormatException("Invalid value in input: $byte");
+ }
+ return _convertInvalid(bytes, start, end);
+ }
+ }
+ return String.fromCharCodes(bytes, start, end);
+ }
+
+ String _convertInvalid(List<int> bytes, int start, int end) {
+ var buffer = StringBuffer();
+ for (var i = start; i < end; i++) {
+ var value = bytes[i];
+ if ((value & ~_subsetMask) != 0) value = 0xFFFD;
+ buffer.writeCharCode(value);
+ }
+ return buffer.toString();
+ }
+
+ /// Starts a chunked conversion.
+ ///
+ /// The converter works more efficiently if the given [sink] is a
+ /// [StringConversionSink].
+ ByteConversionSink startChunkedConversion(Sink<String> sink);
+
+ // Override the base-class's bind, to provide a better type.
+ Stream<String> bind(Stream<List<int>> stream) => super.bind(stream);
+}
+
+class AsciiDecoder extends _UnicodeSubsetDecoder {
+ const AsciiDecoder({bool allowInvalid = false})
+ : super(allowInvalid, _asciiMask);
+
+ /// Starts a chunked conversion.
+ ///
+ /// The converter works more efficiently if the given [sink] is a
+ /// [StringConversionSink].
+ ByteConversionSink startChunkedConversion(Sink<String> sink) {
+ StringConversionSink stringSink;
+ if (sink is StringConversionSink) {
+ stringSink = sink;
+ } else {
+ stringSink = StringConversionSink.from(sink);
+ }
+ // TODO(lrn): Use asUtf16Sink when it becomes available. It
+ // works just as well, is likely to have less decoding overhead,
+ // and make adding U+FFFD easier.
+ // At that time, merge this with _Latin1DecoderSink;
+ if (_allowInvalid) {
+ return _ErrorHandlingAsciiDecoderSink(stringSink.asUtf8Sink(false));
+ } else {
+ return _SimpleAsciiDecoderSink(stringSink);
+ }
+ }
+}
+
+class _ErrorHandlingAsciiDecoderSink extends ByteConversionSinkBase {
+ ByteConversionSink _utf8Sink;
+ _ErrorHandlingAsciiDecoderSink(this._utf8Sink);
+
+ void close() {
+ _utf8Sink.close();
+ }
+
+ void add(List<int> source) {
+ addSlice(source, 0, source.length, false);
+ }
+
+ void addSlice(List<int> source, int start, int end, bool isLast) {
+ RangeError.checkValidRange(start, end, source.length);
+ for (var i = start; i < end; i++) {
+ if ((source[i] & ~_asciiMask) != 0) {
+ if (i > start) _utf8Sink.addSlice(source, start, i, false);
+ // Add UTF-8 encoding of U+FFFD.
+ _utf8Sink.add(const <int>[0xEF, 0xBF, 0xBD]);
+ start = i + 1;
+ }
+ }
+ if (start < end) {
+ _utf8Sink.addSlice(source, start, end, isLast);
+ } else if (isLast) {
+ close();
+ }
+ }
+}
+
+class _SimpleAsciiDecoderSink extends ByteConversionSinkBase {
+ Sink _sink;
+ _SimpleAsciiDecoderSink(this._sink);
+
+ void close() {
+ _sink.close();
+ }
+
+ void add(List<int> source) {
+ for (var i = 0; i < source.length; i++) {
+ if ((source[i] & ~_asciiMask) != 0) {
+ throw FormatException("Source contains non-ASCII bytes.");
+ }
+ }
+ _sink.add(String.fromCharCodes(source));
+ }
+
+ void addSlice(List<int> source, int start, int end, bool isLast) {
+ final length = source.length;
+ RangeError.checkValidRange(start, end, length);
+ if (start < end) {
+ if (start != 0 || end != length) {
+ source = source.sublist(start, end);
+ }
+ add(source);
+ }
+ if (isLast) close();
+ }
+}
diff --git a/sdk_nnbd/lib/convert/base64.dart b/sdk_nnbd/lib/convert/base64.dart
new file mode 100644
index 0000000..ce522be
--- /dev/null
+++ b/sdk_nnbd/lib/convert/base64.dart
@@ -0,0 +1,854 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// A [base64](https://tools.ietf.org/html/rfc4648) encoder and decoder.
+///
+/// It encodes using the default base64 alphabet,
+/// decodes using both the base64 and base64url alphabets,
+/// does not allow invalid characters and requires padding.
+///
+/// Examples:
+///
+/// var encoded = base64.encode([0x62, 0x6c, 0xc3, 0xa5, 0x62, 0xc3, 0xa6,
+/// 0x72, 0x67, 0x72, 0xc3, 0xb8, 0x64]);
+/// var decoded = base64.decode("YmzDpWLDpnJncsO4ZAo=");
+///
+/// The top-level [base64Encode] and [base64Decode] functions may be used
+/// instead if a local variable shadows the [base64] constant.
+const Base64Codec base64 = Base64Codec();
+
+/// A [base64url](https://tools.ietf.org/html/rfc4648) encoder and decoder.
+///
+/// It encodes and decodes using the base64url alphabet,
+/// decodes using both the base64 and base64url alphabets,
+/// does not allow invalid characters and requires padding.
+///
+/// Examples:
+///
+/// var encoded = base64Url.encode([0x62, 0x6c, 0xc3, 0xa5, 0x62, 0xc3, 0xa6,
+/// 0x72, 0x67, 0x72, 0xc3, 0xb8, 0x64]);
+/// var decoded = base64Url.decode("YmzDpWLDpnJncsO4ZAo=");
+const Base64Codec base64Url = Base64Codec.urlSafe();
+
+/// Encodes [bytes] using [base64](https://tools.ietf.org/html/rfc4648) encoding.
+///
+/// Shorthand for [base64.encode]. Useful if a local variable shadows the global
+/// [base64] constant.
+String base64Encode(List<int> bytes) => base64.encode(bytes);
+
+/// Encodes [bytes] using [base64url](https://tools.ietf.org/html/rfc4648) encoding.
+///
+/// Shorthand for [base64url.encode].
+String base64UrlEncode(List<int> bytes) => base64Url.encode(bytes);
+
+/// Decodes [base64](https://tools.ietf.org/html/rfc4648) or [base64url](https://tools.ietf.org/html/rfc4648) encoded bytes.
+///
+/// Shorthand for [base64.decode]. Useful if a local variable shadows the
+/// global [base64] constant.
+Uint8List base64Decode(String source) => base64.decode(source);
+
+// Constants used in more than one class.
+const int _paddingChar = 0x3d; // '='.
+
+/// A [base64](https://tools.ietf.org/html/rfc4648) encoder and decoder.
+///
+/// A [Base64Codec] allows base64 encoding bytes into ASCII strings and
+/// decoding valid encodings back to bytes.
+///
+/// This implementation only handles the simplest RFC 4648 base64 and base64url
+/// encodings.
+/// It does not allow invalid characters when decoding and it requires,
+/// and generates, padding so that the input is always a multiple of four
+/// characters.
+class Base64Codec extends Codec<List<int>, String> {
+ final Base64Encoder _encoder;
+ const Base64Codec() : _encoder = const Base64Encoder();
+ const Base64Codec.urlSafe() : _encoder = const Base64Encoder.urlSafe();
+
+ Base64Encoder get encoder => _encoder;
+
+ Base64Decoder get decoder => const Base64Decoder();
+
+ /// Decodes [encoded].
+ ///
+ /// The input is decoded as if by `decoder.convert`.
+ ///
+ /// The returned [Uint8List] contains exactly the decoded bytes,
+ /// so the [Uint8List.length] is precisely the number of decoded bytes.
+ /// The [Uint8List.buffer] may be larger than the decoded bytes.
+ Uint8List decode(String encoded) => decoder.convert(encoded);
+
+ /// Validates and normalizes the base64 encoded data in [source].
+ ///
+ /// Only acts on the substring from [start] to [end], with [end]
+ /// defaulting to the end of the string.
+ ///
+ /// Normalization will:
+ /// * Unescape any `%`-escapes.
+ /// * Only allow valid characters (`A`-`Z`, `a`-`z`, `0`-`9`, `/` and `+`).
+ /// * Normalize a `_` or `-` character to `/` or `+`.
+ /// * Validate that existing padding (trailing `=` characters) is correct.
+ /// * If no padding exists, add correct padding if necessary and possible.
+ /// * Validate that the length is correct (a multiple of four).
+ String normalize(String source, [int start = 0, int end]) {
+ end = RangeError.checkValidRange(start, end, source.length);
+ const percent = 0x25;
+ const equals = 0x3d;
+ StringBuffer buffer;
+ var sliceStart = start;
+ var alphabet = _Base64Encoder._base64Alphabet;
+ var inverseAlphabet = _Base64Decoder._inverseAlphabet;
+ var firstPadding = -1;
+ var firstPaddingSourceIndex = -1;
+ var paddingCount = 0;
+ for (var i = start; i < end;) {
+ var sliceEnd = i;
+ var char = source.codeUnitAt(i++);
+ var originalChar = char;
+ // Normalize char, keep originalChar to see if it matches the source.
+ if (char == percent) {
+ if (i + 2 <= end) {
+ char = parseHexByte(source, i); // May be negative.
+ i += 2;
+ // We know that %25 isn't valid, but our table considers it
+ // a potential padding start, so skip the checks.
+ if (char == percent) char = -1;
+ } else {
+ // An invalid HEX escape (too short).
+ // Just skip past the handling and reach the throw below.
+ char = -1;
+ }
+ }
+ // If char is negative here, hex-decoding failed in some way.
+ if (0 <= char && char <= 127) {
+ var value = inverseAlphabet[char];
+ if (value >= 0) {
+ char = alphabet.codeUnitAt(value);
+ if (char == originalChar) continue;
+ } else if (value == _Base64Decoder._padding) {
+ // We have ruled out percent, so char is '='.
+ if (firstPadding < 0) {
+ // Mark position in normalized output where padding occurs.
+ firstPadding = (buffer?.length ?? 0) + (sliceEnd - sliceStart);
+ firstPaddingSourceIndex = sliceEnd;
+ }
+ paddingCount++;
+ // It could have been an escaped equals (%3D).
+ if (originalChar == equals) continue;
+ }
+ if (value != _Base64Decoder._invalid) {
+ buffer ??= StringBuffer();
+ buffer.write(source.substring(sliceStart, sliceEnd));
+ buffer.writeCharCode(char);
+ sliceStart = i;
+ continue;
+ }
+ }
+ throw FormatException("Invalid base64 data", source, sliceEnd);
+ }
+ if (buffer != null) {
+ buffer.write(source.substring(sliceStart, end));
+ if (firstPadding >= 0) {
+ // There was padding in the source. Check that it is valid:
+ // * result length a multiple of four
+ // * one or two padding characters at the end.
+ _checkPadding(source, firstPaddingSourceIndex, end, firstPadding,
+ paddingCount, buffer.length);
+ } else {
+ // Length of last chunk (1-4 chars) in the encoding.
+ var endLength = ((buffer.length - 1) % 4) + 1;
+ if (endLength == 1) {
+ // The data must have length 0, 2 or 3 modulo 4.
+ throw FormatException("Invalid base64 encoding length ", source, end);
+ }
+ while (endLength < 4) {
+ buffer.write("=");
+ endLength++;
+ }
+ }
+ return source.replaceRange(start, end, buffer.toString());
+ }
+ // Original was already normalized, only check padding.
+ var length = end - start;
+ if (firstPadding >= 0) {
+ _checkPadding(source, firstPaddingSourceIndex, end, firstPadding,
+ paddingCount, length);
+ } else {
+ // No padding given, so add some if needed it.
+ var endLength = length % 4;
+ if (endLength == 1) {
+ // The data must have length 0, 2 or 3 modulo 4.
+ throw FormatException("Invalid base64 encoding length ", source, end);
+ }
+ if (endLength > 1) {
+ // There is no "insertAt" on String, but this works as well.
+ source = source.replaceRange(end, end, (endLength == 2) ? "==" : "=");
+ }
+ }
+ return source;
+ }
+
+ static void _checkPadding(String source, int sourceIndex, int sourceEnd,
+ int firstPadding, int paddingCount, int length) {
+ if (length % 4 != 0) {
+ throw FormatException(
+ "Invalid base64 padding, padded length must be multiple of four, "
+ "is $length",
+ source,
+ sourceEnd);
+ }
+ if (firstPadding + paddingCount != length) {
+ throw FormatException(
+ "Invalid base64 padding, '=' not at the end", source, sourceIndex);
+ }
+ if (paddingCount > 2) {
+ throw FormatException(
+ "Invalid base64 padding, more than two '=' characters",
+ source,
+ sourceIndex);
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+// Encoder
+// ------------------------------------------------------------------------
+
+/// Base64 and base64url encoding converter.
+///
+/// Encodes lists of bytes using base64 or base64url encoding.
+///
+/// The results are ASCII strings using a restricted alphabet.
+class Base64Encoder extends Converter<List<int>, String> {
+ final bool _urlSafe;
+
+ const Base64Encoder() : _urlSafe = false;
+ const Base64Encoder.urlSafe() : _urlSafe = true;
+
+ String convert(List<int> input) {
+ if (input.isEmpty) return "";
+ var encoder = _Base64Encoder(_urlSafe);
+ var buffer = encoder.encode(input, 0, input.length, true);
+ return String.fromCharCodes(buffer);
+ }
+
+ ByteConversionSink startChunkedConversion(Sink<String> sink) {
+ if (sink is StringConversionSink) {
+ return _Utf8Base64EncoderSink(sink.asUtf8Sink(false), _urlSafe);
+ }
+ return _AsciiBase64EncoderSink(sink, _urlSafe);
+ }
+}
+
+/// Helper class for encoding bytes to base64.
+class _Base64Encoder {
+ /// The RFC 4648 base64 encoding alphabet.
+ static const String _base64Alphabet =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ /// The RFC 4648 base64url encoding alphabet.
+ static const String _base64UrlAlphabet =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+ /// Shift-count to extract the values stored in [_state].
+ static const int _valueShift = 2;
+
+ /// Mask to extract the count value stored in [_state].
+ static const int _countMask = 3;
+
+ static const int _sixBitMask = 0x3F;
+
+ /// Intermediate state between chunks.
+ ///
+ /// Encoding handles three bytes at a time.
+ /// If fewer than three bytes has been seen, this value encodes
+ /// the number of bytes seen (0, 1 or 2) and their values.
+ int _state = 0;
+
+ /// Alphabet used for encoding.
+ final String _alphabet;
+
+ _Base64Encoder(bool urlSafe)
+ : _alphabet = urlSafe ? _base64UrlAlphabet : _base64Alphabet;
+
+ /// Encode count and bits into a value to be stored in [_state].
+ static int _encodeState(int count, int bits) {
+ assert(count <= _countMask);
+ return bits << _valueShift | count;
+ }
+
+ /// Extract bits from encoded state.
+ static int _stateBits(int state) => state >> _valueShift;
+
+ /// Extract count from encoded state.
+ static int _stateCount(int state) => state & _countMask;
+
+ /// Create a [Uint8List] with the provided length.
+ Uint8List createBuffer(int bufferLength) => Uint8List(bufferLength);
+
+ /// Encode [bytes] from [start] to [end] and the bits in [_state].
+ ///
+ /// Returns a [Uint8List] of the ASCII codes of the encoded data.
+ ///
+ /// If the input, including left over [_state] from earlier encodings,
+ /// are not a multiple of three bytes, then the partial state is stored
+ /// back into [_state].
+ /// If [isLast] is true, partial state is encoded in the output instead,
+ /// with the necessary padding.
+ ///
+ /// Returns `null` if there is no output.
+ Uint8List encode(List<int> bytes, int start, int end, bool isLast) {
+ assert(0 <= start);
+ assert(start <= end);
+ assert(bytes == null || end <= bytes.length);
+ var length = end - start;
+
+ var count = _stateCount(_state);
+ var byteCount = (count + length);
+ var fullChunks = byteCount ~/ 3;
+ var partialChunkLength = byteCount - fullChunks * 3;
+ var bufferLength = fullChunks * 4;
+ if (isLast && partialChunkLength > 0) {
+ bufferLength += 4; // Room for padding.
+ }
+ var output = createBuffer(bufferLength);
+ _state =
+ encodeChunk(_alphabet, bytes, start, end, isLast, output, 0, _state);
+ if (bufferLength > 0) return output;
+ // If the input plus the data in state is still less than three bytes,
+ // there may not be any output.
+ return null;
+ }
+
+ static int encodeChunk(String alphabet, List<int> bytes, int start, int end,
+ bool isLast, Uint8List output, int outputIndex, int state) {
+ var bits = _stateBits(state);
+ // Count number of missing bytes in three-byte chunk.
+ var expectedChars = 3 - _stateCount(state);
+
+ // The input must be a list of bytes (integers in the range 0..255).
+ // The value of `byteOr` will be the bitwise or of all the values in
+ // `bytes` and a later check will validate that they were all valid bytes.
+ var byteOr = 0;
+ for (var i = start; i < end; i++) {
+ var byte = bytes[i];
+ byteOr |= byte;
+ bits = ((bits << 8) | byte) & 0xFFFFFF; // Never store more than 24 bits.
+ expectedChars--;
+ if (expectedChars == 0) {
+ output[outputIndex++] = alphabet.codeUnitAt((bits >> 18) & _sixBitMask);
+ output[outputIndex++] = alphabet.codeUnitAt((bits >> 12) & _sixBitMask);
+ output[outputIndex++] = alphabet.codeUnitAt((bits >> 6) & _sixBitMask);
+ output[outputIndex++] = alphabet.codeUnitAt(bits & _sixBitMask);
+ expectedChars = 3;
+ bits = 0;
+ }
+ }
+ if (byteOr >= 0 && byteOr <= 255) {
+ if (isLast && expectedChars < 3) {
+ writeFinalChunk(alphabet, output, outputIndex, 3 - expectedChars, bits);
+ return 0;
+ }
+ return _encodeState(3 - expectedChars, bits);
+ }
+
+ // There was an invalid byte value somewhere in the input - find it!
+ var i = start;
+ while (i < end) {
+ var byte = bytes[i];
+ if (byte < 0 || byte > 255) break;
+ i++;
+ }
+ throw ArgumentError.value(
+ bytes, "Not a byte value at index $i: 0x${bytes[i].toRadixString(16)}");
+ }
+
+ /// Writes a final encoded four-character chunk.
+ ///
+ /// Only used when the [_state] contains a partial (1 or 2 byte)
+ /// input.
+ static void writeFinalChunk(
+ String alphabet, Uint8List output, int outputIndex, int count, int bits) {
+ assert(count > 0);
+ if (count == 1) {
+ output[outputIndex++] = alphabet.codeUnitAt((bits >> 2) & _sixBitMask);
+ output[outputIndex++] = alphabet.codeUnitAt((bits << 4) & _sixBitMask);
+ output[outputIndex++] = _paddingChar;
+ output[outputIndex++] = _paddingChar;
+ } else {
+ assert(count == 2);
+ output[outputIndex++] = alphabet.codeUnitAt((bits >> 10) & _sixBitMask);
+ output[outputIndex++] = alphabet.codeUnitAt((bits >> 4) & _sixBitMask);
+ output[outputIndex++] = alphabet.codeUnitAt((bits << 2) & _sixBitMask);
+ output[outputIndex++] = _paddingChar;
+ }
+ }
+}
+
+class _BufferCachingBase64Encoder extends _Base64Encoder {
+ /// Reused buffer.
+ ///
+ /// When the buffer isn't released to the sink, only used to create another
+ /// value (a string), the buffer can be reused between chunks.
+ Uint8List bufferCache;
+
+ _BufferCachingBase64Encoder(bool urlSafe) : super(urlSafe);
+
+ Uint8List createBuffer(int bufferLength) {
+ if (bufferCache == null || bufferCache.length < bufferLength) {
+ bufferCache = Uint8List(bufferLength);
+ }
+ // Return a view of the buffer, so it has the requested length.
+ return Uint8List.view(bufferCache.buffer, 0, bufferLength);
+ }
+}
+
+abstract class _Base64EncoderSink extends ByteConversionSinkBase {
+ void add(List<int> source) {
+ _add(source, 0, source.length, false);
+ }
+
+ void close() {
+ _add(null, 0, 0, true);
+ }
+
+ void addSlice(List<int> source, int start, int end, bool isLast) {
+ if (end == null) throw ArgumentError.notNull("end");
+ RangeError.checkValidRange(start, end, source.length);
+ _add(source, start, end, isLast);
+ }
+
+ void _add(List<int> source, int start, int end, bool isLast);
+}
+
+class _AsciiBase64EncoderSink extends _Base64EncoderSink {
+ final Sink<String> _sink;
+ final _Base64Encoder _encoder;
+
+ _AsciiBase64EncoderSink(this._sink, bool urlSafe)
+ : _encoder = _BufferCachingBase64Encoder(urlSafe);
+
+ void _add(List<int> source, int start, int end, bool isLast) {
+ var buffer = _encoder.encode(source, start, end, isLast);
+ if (buffer != null) {
+ var string = String.fromCharCodes(buffer);
+ _sink.add(string);
+ }
+ if (isLast) {
+ _sink.close();
+ }
+ }
+}
+
+class _Utf8Base64EncoderSink extends _Base64EncoderSink {
+ final ByteConversionSink _sink;
+ final _Base64Encoder _encoder;
+
+ _Utf8Base64EncoderSink(this._sink, bool urlSafe)
+ : _encoder = _Base64Encoder(urlSafe);
+
+ void _add(List<int> source, int start, int end, bool isLast) {
+ var buffer = _encoder.encode(source, start, end, isLast);
+ if (buffer != null) {
+ _sink.addSlice(buffer, 0, buffer.length, isLast);
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+// Decoder
+// ------------------------------------------------------------------------
+
+/// Decoder for base64 encoded data.
+///
+/// This decoder accepts both base64 and base64url ("url-safe") encodings.
+///
+/// The encoding is required to be properly padded.
+class Base64Decoder extends Converter<String, List<int>> {
+ const Base64Decoder();
+
+ /// Decodes the characters of [input] from [start] to [end] as base64.
+ ///
+ /// If [start] is omitted, it defaults to the start of [input].
+ /// If [end] is omitted, it defaults to the end of [input].
+ ///
+ /// The returned [Uint8List] contains exactly the decoded bytes,
+ /// so the [Uint8List.length] is precisely the number of decoded bytes.
+ /// The [Uint8List.buffer] may be larger than the decoded bytes.
+ Uint8List convert(String input, [int start = 0, int end]) {
+ end = RangeError.checkValidRange(start, end, input.length);
+ if (start == end) return Uint8List(0);
+ var decoder = _Base64Decoder();
+ var buffer = decoder.decode(input, start, end);
+ decoder.close(input, end);
+ return buffer;
+ }
+
+ StringConversionSink startChunkedConversion(Sink<List<int>> sink) {
+ return _Base64DecoderSink(sink);
+ }
+}
+
+/// Helper class implementing base64 decoding with intermediate state.
+class _Base64Decoder {
+ /// Shift-count to extract the values stored in [_state].
+ static const int _valueShift = 2;
+
+ /// Mask to extract the count value stored in [_state].
+ static const int _countMask = 3;
+
+ /// Invalid character in decoding table.
+ static const int _invalid = -2;
+
+ /// Padding character in decoding table.
+ static const int _padding = -1;
+
+ // Shorthands to make the table more readable.
+ static const int __ = _invalid;
+ static const int _p = _padding;
+
+ /// Mapping from ASCII characters to their index in the base64 alphabet.
+ ///
+ /// Uses [_invalid] for invalid indices and [_padding] for the padding
+ /// character.
+ ///
+ /// Accepts the "URL-safe" alphabet as well (`-` and `_` are the
+ /// 62nd and 63rd alphabet characters), and considers `%` a padding
+ /// character, which must then be followed by `3D`, the percent-escape
+ /// for `=`.
+ static final List<int> _inverseAlphabet = Int8List.fromList([
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
+ __, __, __, __, __, _p, __, __, __, __, __, 62, __, 62, __, 63, //
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, __, __, __, _p, __, __, //
+ __, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, //
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, __, __, __, __, 63, //
+ __, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, __, __, __, __, __, //
+ ]);
+
+ // Character constants.
+ static const int _char_percent = 0x25; // '%'.
+ static const int _char_3 = 0x33; // '3'.
+ static const int _char_d = 0x64; // 'd'.
+
+ /// Maintains the intermediate state of a partly-decoded input.
+ ///
+ /// Base64 is decoded in chunks of four characters. If a chunk does not
+ /// contain a full block, the decoded bits (six per character) of the
+ /// available characters are stored in [_state] until the next call to
+ /// [_decode] or [_close].
+ ///
+ /// If no padding has been seen, the value is
+ /// `numberOfCharactersSeen | (decodedBits << 2)`
+ /// where `numberOfCharactersSeen` is between 0 and 3 and decoded bits
+ /// contains six bits per seen character.
+ ///
+ /// If padding has been seen the value is negative. It's the bitwise negation
+ /// of the number of remaining allowed padding characters (always ~0 or ~1).
+ ///
+ /// A state of `0` or `~0` are valid places to end decoding, all other values
+ /// mean that a four-character block has not been completed.
+ int _state = 0;
+
+ /// Encodes [count] and [bits] as a value to be stored in [_state].
+ static int _encodeCharacterState(int count, int bits) {
+ assert(count == (count & _countMask));
+ return (bits << _valueShift | count);
+ }
+
+ /// Extracts count from a [_state] value.
+ static int _stateCount(int state) {
+ assert(state >= 0);
+ return state & _countMask;
+ }
+
+ /// Extracts value bits from a [_state] value.
+ static int _stateBits(int state) {
+ assert(state >= 0);
+ return state >> _valueShift;
+ }
+
+ /// Encodes a number of expected padding characters to be stored in [_state].
+ static int _encodePaddingState(int expectedPadding) {
+ assert(expectedPadding >= 0);
+ assert(expectedPadding <= 5);
+ return -expectedPadding - 1; // ~expectedPadding adapted to dart2js.
+ }
+
+ /// Extracts expected padding character count from a [_state] value.
+ static int _statePadding(int state) {
+ assert(state < 0);
+ return -state - 1; // ~state adapted to dart2js.
+ }
+
+ static bool _hasSeenPadding(int state) => state < 0;
+
+ /// Decodes [input] from [start] to [end].
+ ///
+ /// Returns a [Uint8List] with the decoded bytes.
+ /// If a previous call had an incomplete four-character block, the bits from
+ /// those are included in decoding
+ Uint8List decode(String input, int start, int end) {
+ assert(0 <= start);
+ assert(start <= end);
+ assert(end <= input.length);
+ if (_hasSeenPadding(_state)) {
+ _state = _checkPadding(input, start, end, _state);
+ return null;
+ }
+ if (start == end) return Uint8List(0);
+ var buffer = _allocateBuffer(input, start, end, _state);
+ _state = decodeChunk(input, start, end, buffer, 0, _state);
+ return buffer;
+ }
+
+ /// Checks that [_state] represents a valid decoding.
+ void close(String input, int end) {
+ if (_state < _encodePaddingState(0)) {
+ throw FormatException("Missing padding character", input, end);
+ }
+ if (_state > 0) {
+ throw FormatException(
+ "Invalid length, must be multiple of four", input, end);
+ }
+ _state = _encodePaddingState(0);
+ }
+
+ /// Decodes [input] from [start] to [end].
+ ///
+ /// Includes the state returned by a previous call in the decoding.
+ /// Writes the decoding to [output] at [outIndex], and there must
+ /// be room in the output.
+ static int decodeChunk(String input, int start, int end, Uint8List output,
+ int outIndex, int state) {
+ assert(!_hasSeenPadding(state));
+ const asciiMask = 127;
+ const asciiMax = 127;
+ const eightBitMask = 0xFF;
+ const bitsPerCharacter = 6;
+
+ var bits = _stateBits(state);
+ var count = _stateCount(state);
+ // String contents should be all ASCII.
+ // Instead of checking for each character, we collect the bitwise-or of
+ // all the characters in `charOr` and later validate that all characters
+ // were ASCII.
+ var charOr = 0;
+ for (var i = start; i < end; i++) {
+ var char = input.codeUnitAt(i);
+ charOr |= char;
+ var code = _inverseAlphabet[char & asciiMask];
+ if (code >= 0) {
+ bits = ((bits << bitsPerCharacter) | code) & 0xFFFFFF;
+ count = (count + 1) & 3;
+ if (count == 0) {
+ assert(outIndex + 3 <= output.length);
+ output[outIndex++] = (bits >> 16) & eightBitMask;
+ output[outIndex++] = (bits >> 8) & eightBitMask;
+ output[outIndex++] = bits & eightBitMask;
+ bits = 0;
+ }
+ continue;
+ } else if (code == _padding && count > 1) {
+ if (charOr < 0 || charOr > asciiMax) break;
+ if (count == 3) {
+ if ((bits & 0x03) != 0) {
+ throw FormatException("Invalid encoding before padding", input, i);
+ }
+ output[outIndex++] = bits >> 10;
+ output[outIndex++] = bits >> 2;
+ } else {
+ if ((bits & 0x0F) != 0) {
+ throw FormatException("Invalid encoding before padding", input, i);
+ }
+ output[outIndex++] = bits >> 4;
+ }
+ // Expected padding is the number of expected padding characters,
+ // where `=` counts as three and `%3D` counts as one per character.
+ //
+ // Expect either zero or one padding depending on count (2 or 3),
+ // plus two more characters if the code was `%` (a partial padding).
+ var expectedPadding = (3 - count) * 3;
+ if (char == _char_percent) expectedPadding += 2;
+ state = _encodePaddingState(expectedPadding);
+ return _checkPadding(input, i + 1, end, state);
+ }
+ throw FormatException("Invalid character", input, i);
+ }
+ if (charOr >= 0 && charOr <= asciiMax) {
+ return _encodeCharacterState(count, bits);
+ }
+ // There is an invalid (non-ASCII) character in the input.
+ int i;
+ for (i = start; i < end; i++) {
+ var char = input.codeUnitAt(i);
+ if (char < 0 || char > asciiMax) break;
+ }
+ throw FormatException("Invalid character", input, i);
+ }
+
+ /// Allocates a buffer with room for the decoding of a substring of [input].
+ ///
+ /// Includes room for the characters in [state], and handles padding correctly.
+ static Uint8List _allocateBuffer(
+ String input, int start, int end, int state) {
+ assert(state >= 0);
+ var paddingStart = _trimPaddingChars(input, start, end);
+ var length = _stateCount(state) + (paddingStart - start);
+ // Three bytes per full four bytes in the input.
+ var bufferLength = (length >> 2) * 3;
+ // If padding was seen, then this is the last chunk, and the final partial
+ // chunk should be decoded too.
+ var remainderLength = length & 3;
+ if (remainderLength != 0 && paddingStart < end) {
+ bufferLength += remainderLength - 1;
+ }
+ if (bufferLength > 0) return Uint8List(bufferLength);
+ // If the input plus state is less than four characters, and it's not
+ // at the end of input, no buffer is needed.
+ return null;
+ }
+
+ /// Returns the position of the start of padding at the end of the input.
+ ///
+ /// Returns the end of input if there is no padding.
+ ///
+ /// This is used to ensure that the decoding buffer has the exact size
+ /// it needs when input is valid, and at least enough bytes to reach the error
+ /// when input is invalid.
+ ///
+ /// Never count more than two padding sequences since any more than that
+ /// will raise an error anyway, and we only care about being precise for
+ /// successful conversions.
+ static int _trimPaddingChars(String input, int start, int end) {
+ // This may count '%=' as two paddings. That's ok, it will err later,
+ // but the buffer will be large enough to reach the error.
+ var padding = 0;
+ var index = end;
+ var newEnd = end;
+ while (index > start && padding < 2) {
+ index--;
+ var char = input.codeUnitAt(index);
+ if (char == _paddingChar) {
+ padding++;
+ newEnd = index;
+ continue;
+ }
+ if ((char | 0x20) == _char_d) {
+ if (index == start) break;
+ index--;
+ char = input.codeUnitAt(index);
+ }
+ if (char == _char_3) {
+ if (index == start) break;
+ index--;
+ char = input.codeUnitAt(index);
+ }
+ if (char == _char_percent) {
+ padding++;
+ newEnd = index;
+ continue;
+ }
+ break;
+ }
+ return newEnd;
+ }
+
+ /// Check that the remainder of the string is valid padding.
+ ///
+ /// Valid padding is a correct number (0, 1 or 2) of `=` characters
+ /// or `%3D` sequences depending on the number of preceding base64 characters.
+ /// The [state] parameter encodes which padding continuations are allowed
+ /// as the number of expected characters. That number is the number of
+ /// expected padding characters times 3 minus the number of padding characters
+ /// seen so far, where `=` counts as 3 counts as three characters,
+ /// and the padding sequence `%3D` counts as one character per character.
+ ///
+ /// The number of missing characters is always between 0 and 5 because we
+ /// only call this function after having seen at least one `=` or `%`
+ /// character.
+ /// If the number of missing characters is not 3 or 0, we have seen (at least)
+ /// a `%` character and expects the rest of the `%3D` sequence, and a `=` is
+ /// not allowed. When missing 3 characters, either `=` or `%` is allowed.
+ ///
+ /// When the value is 0, no more padding (or any other character) is allowed.
+ static int _checkPadding(String input, int start, int end, int state) {
+ assert(_hasSeenPadding(state));
+ if (start == end) return state;
+ var expectedPadding = _statePadding(state);
+ assert(expectedPadding >= 0);
+ assert(expectedPadding < 6);
+ while (expectedPadding > 0) {
+ var char = input.codeUnitAt(start);
+ if (expectedPadding == 3) {
+ if (char == _paddingChar) {
+ expectedPadding -= 3;
+ start++;
+ break;
+ }
+ if (char == _char_percent) {
+ expectedPadding--;
+ start++;
+ if (start == end) break;
+ char = input.codeUnitAt(start);
+ } else {
+ break;
+ }
+ }
+ // Partial padding means we have seen part of a "%3D" escape.
+ var expectedPartialPadding = expectedPadding;
+ if (expectedPartialPadding > 3) expectedPartialPadding -= 3;
+ if (expectedPartialPadding == 2) {
+ // Expects '3'
+ if (char != _char_3) break;
+ start++;
+ expectedPadding--;
+ if (start == end) break;
+ char = input.codeUnitAt(start);
+ }
+ // Expects 'D' or 'd'.
+ if ((char | 0x20) != _char_d) break;
+ start++;
+ expectedPadding--;
+ if (start == end) break;
+ }
+ if (start != end) {
+ throw FormatException("Invalid padding character", input, start);
+ }
+ return _encodePaddingState(expectedPadding);
+ }
+}
+
+class _Base64DecoderSink extends StringConversionSinkBase {
+ /// Output sink
+ final Sink<List<int>> _sink;
+ final _Base64Decoder _decoder = _Base64Decoder();
+
+ _Base64DecoderSink(this._sink);
+
+ void add(String string) {
+ if (string.isEmpty) return;
+ var buffer = _decoder.decode(string, 0, string.length);
+ if (buffer != null) _sink.add(buffer);
+ }
+
+ void close() {
+ _decoder.close(null, null);
+ _sink.close();
+ }
+
+ void addSlice(String string, int start, int end, bool isLast) {
+ end = RangeError.checkValidRange(start, end, string.length);
+ if (start == end) return;
+ var buffer = _decoder.decode(string, start, end);
+ if (buffer != null) _sink.add(buffer);
+ if (isLast) {
+ _decoder.close(string, end);
+ _sink.close();
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/convert/byte_conversion.dart b/sdk_nnbd/lib/convert/byte_conversion.dart
new file mode 100644
index 0000000..3d52d78
--- /dev/null
+++ b/sdk_nnbd/lib/convert/byte_conversion.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// The [ByteConversionSink] provides an interface for converters to
+/// efficiently transmit byte data.
+///
+/// Instead of limiting the interface to one non-chunked list of bytes it
+/// accepts its input in chunks (themselves being lists of bytes).
+///
+/// This abstract class will likely get more methods over time. Implementers are
+/// urged to extend or mix in [ByteConversionSinkBase] to ensure that their
+/// class covers the newly added methods.
+abstract class ByteConversionSink extends ChunkedConversionSink<List<int>> {
+ ByteConversionSink();
+ factory ByteConversionSink.withCallback(
+ void callback(List<int> accumulated)) = _ByteCallbackSink;
+ factory ByteConversionSink.from(Sink<List<int>> sink) = _ByteAdapterSink;
+
+ /// Adds the next [chunk] to `this`.
+ ///
+ /// Adds the bytes defined by [start] and [end]-exclusive to `this`.
+ ///
+ /// If [isLast] is `true` closes `this`.
+ ///
+ /// Contrary to `add` the given [chunk] must not be held onto. Once the method
+ /// returns, it is safe to overwrite the data in it.
+ void addSlice(List<int> chunk, int start, int end, bool isLast);
+
+ // TODO(floitsch): add more methods:
+ // - iterateBytes.
+}
+
+/// This class provides a base-class for converters that need to accept byte
+/// inputs.
+abstract class ByteConversionSinkBase extends ByteConversionSink {
+ void add(List<int> chunk);
+ void close();
+
+ void addSlice(List<int> chunk, int start, int end, bool isLast) {
+ add(chunk.sublist(start, end));
+ if (isLast) close();
+ }
+}
+
+/// This class adapts a simple [Sink] to a [ByteConversionSink].
+///
+/// All additional methods of the [ByteConversionSink] (compared to the
+/// ChunkedConversionSink) are redirected to the `add` method.
+class _ByteAdapterSink extends ByteConversionSinkBase {
+ final Sink<List<int>> _sink;
+
+ _ByteAdapterSink(this._sink);
+
+ void add(List<int> chunk) {
+ _sink.add(chunk);
+ }
+
+ void close() {
+ _sink.close();
+ }
+}
+
+/// This class accumulates all chunks into one list of bytes
+/// and invokes a callback when the sink is closed.
+///
+/// This class can be used to terminate a chunked conversion.
+class _ByteCallbackSink extends ByteConversionSinkBase {
+ static const _INITIAL_BUFFER_SIZE = 1024;
+
+ final void Function(List<int>) _callback;
+ List<int> _buffer = Uint8List(_INITIAL_BUFFER_SIZE);
+ int _bufferIndex = 0;
+
+ _ByteCallbackSink(void callback(List<int> accumulated))
+ : _callback = callback;
+
+ void add(Iterable<int> chunk) {
+ var freeCount = _buffer.length - _bufferIndex;
+ if (chunk.length > freeCount) {
+ // Grow the buffer.
+ var oldLength = _buffer.length;
+ var newLength = _roundToPowerOf2(chunk.length + oldLength) * 2;
+ var grown = Uint8List(newLength);
+ grown.setRange(0, _buffer.length, _buffer);
+ _buffer = grown;
+ }
+ _buffer.setRange(_bufferIndex, _bufferIndex + chunk.length, chunk);
+ _bufferIndex += chunk.length;
+ }
+
+ static int _roundToPowerOf2(int v) {
+ assert(v > 0);
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v++;
+ return v;
+ }
+
+ void close() {
+ _callback(_buffer.sublist(0, _bufferIndex));
+ }
+}
diff --git a/sdk_nnbd/lib/convert/chunked_conversion.dart b/sdk_nnbd/lib/convert/chunked_conversion.dart
new file mode 100644
index 0000000..e946f97
--- /dev/null
+++ b/sdk_nnbd/lib/convert/chunked_conversion.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// A [ChunkedConversionSink] is used to transmit data more efficiently between
+/// two converters during chunked conversions.
+///
+/// The basic `ChunkedConversionSink` is just a [Sink], and converters should
+/// work with a plain `Sink`, but may work more efficiently with certain
+/// specialized types of `ChunkedConversionSink`.
+///
+/// It is recommended that implementations of `ChunkedConversionSink` extend
+/// this class, to inherit any further methods that may be added to the class.
+abstract class ChunkedConversionSink<T> implements Sink<T> {
+ ChunkedConversionSink();
+ factory ChunkedConversionSink.withCallback(
+ void callback(List<T> accumulated)) = _SimpleCallbackSink<T>;
+
+ /// Adds chunked data to this sink.
+ ///
+ /// This method is also used when converters are used as [StreamTransformer]s.
+ void add(T chunk);
+
+ /// Closes the sink.
+ ///
+ /// This signals the end of the chunked conversion. This method is called
+ /// when converters are used as [StreamTransformer]'s.
+ void close();
+}
+
+/// This class accumulates all chunks and invokes a callback with a list of
+/// the chunks when the sink is closed.
+///
+/// This class can be used to terminate a chunked conversion.
+class _SimpleCallbackSink<T> extends ChunkedConversionSink<T> {
+ final void Function(List<T>) _callback;
+ final List<T> _accumulated = <T>[];
+
+ _SimpleCallbackSink(this._callback);
+
+ void add(T chunk) {
+ _accumulated.add(chunk);
+ }
+
+ void close() {
+ _callback(_accumulated);
+ }
+}
+
+/// This class implements the logic for a chunked conversion as a
+/// stream transformer.
+///
+/// It is used as strategy in the [EventTransformStream].
+///
+/// It also implements the [ChunkedConversionSink] interface so that it
+/// can be used as output sink in a chunked conversion.
+class _ConverterStreamEventSink<S, T> implements EventSink<S> {
+ /// The output sink for the converter.
+ final EventSink<T> _eventSink;
+
+ /// The input sink for new data. All data that is received with
+ /// [handleData] is added into this sink.
+ final Sink<S> _chunkedSink;
+
+ _ConverterStreamEventSink(Converter<S, T> converter, EventSink<T> sink)
+ : _eventSink = sink,
+ _chunkedSink = converter.startChunkedConversion(sink);
+
+ void add(S o) {
+ _chunkedSink.add(o);
+ }
+
+ void addError(Object error, [StackTrace stackTrace]) {
+ _eventSink.addError(error, stackTrace);
+ }
+
+ void close() {
+ _chunkedSink.close();
+ }
+}
diff --git a/sdk_nnbd/lib/convert/codec.dart b/sdk_nnbd/lib/convert/codec.dart
new file mode 100644
index 0000000..38e4a3c
--- /dev/null
+++ b/sdk_nnbd/lib/convert/codec.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// A [Codec] encodes and (if supported) decodes data.
+///
+/// Codecs can be fused. For example fusing [json] and [utf8] produces
+/// an encoder that can convert Json objects directly to bytes, or can decode
+/// bytes directly to json objects.
+///
+/// Fused codecs generally attempt to optimize the operations and can be faster
+/// than executing each step of an encoding separately.
+abstract class Codec<S, T> {
+ const Codec();
+
+ /// Encodes [input].
+ ///
+ /// The input is encoded as if by `encoder.convert`.
+ T encode(S input) => encoder.convert(input);
+
+ /// Decodes [encoded] data.
+ ///
+ /// The input is decoded as if by `decoder.convert`.
+ S decode(T encoded) => decoder.convert(encoded);
+
+ /// Returns the encoder from [S] to [T].
+ ///
+ /// It may be stateful and should not be reused.
+ Converter<S, T> get encoder;
+
+ /// Returns the decoder of `this`, converting from [T] to [S].
+ ///
+ /// It may be stateful and should not be reused.
+ Converter<T, S> get decoder;
+
+ /// Fuses `this` with `other`.
+ ///
+ /// When encoding, the resulting codec encodes with `this` before
+ /// encoding with [other].
+ ///
+ /// When decoding, the resulting codec decodes with [other] before decoding
+ /// with `this`.
+ ///
+ /// In some cases one needs to use the [inverted] codecs to be able to fuse
+ /// them correctly. That is, the output type of `this` ([T]) must match the
+ /// input type of the second codec [other].
+ ///
+ /// Examples:
+ /// ```dart
+ /// final jsonToBytes = json.fuse(utf8);
+ /// List<int> bytes = jsonToBytes.encode(["json-object"]);
+ /// var decoded = jsonToBytes.decode(bytes);
+ /// assert(decoded is List && decoded[0] == "json-object");
+ ///
+ /// var inverted = json.inverted;
+ /// var jsonIdentity = json.fuse(inverted);
+ /// var jsonObject = jsonIdentity.encode(["1", 2]);
+ /// assert(jsonObject is List && jsonObject[0] == "1" && jsonObject[1] == 2);
+ /// ```
+ // TODO(floitsch): use better example with line-splitter once that one is
+ // in this library.
+ Codec<S, R> fuse<R>(Codec<T, R> other) {
+ return _FusedCodec<S, T, R>(this, other);
+ }
+
+ /// Inverts `this`.
+ ///
+ /// The [encoder] and [decoder] of the resulting codec are swapped.
+ Codec<T, S> get inverted => _InvertedCodec<T, S>(this);
+}
+
+/// Fuses the given codecs.
+///
+/// In the non-chunked conversion simply invokes the non-chunked conversions in
+/// sequence.
+class _FusedCodec<S, M, T> extends Codec<S, T> {
+ final Codec<S, M> _first;
+ final Codec<M, T> _second;
+
+ Converter<S, T> get encoder => _first.encoder.fuse<T>(_second.encoder);
+ Converter<T, S> get decoder => _second.decoder.fuse<S>(_first.decoder);
+
+ _FusedCodec(this._first, this._second);
+}
+
+class _InvertedCodec<T, S> extends Codec<T, S> {
+ final Codec<S, T> _codec;
+
+ _InvertedCodec(Codec<S, T> codec) : _codec = codec;
+
+ Converter<T, S> get encoder => _codec.decoder;
+ Converter<S, T> get decoder => _codec.encoder;
+
+ Codec<S, T> get inverted => _codec;
+}
diff --git a/sdk_nnbd/lib/convert/convert.dart b/sdk_nnbd/lib/convert/convert.dart
new file mode 100644
index 0000000..6173782
--- /dev/null
+++ b/sdk_nnbd/lib/convert/convert.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+///
+/// Encoders and decoders for converting between different data representations,
+/// including JSON and UTF-8.
+///
+/// In addition to converters for common data representations, this library
+/// provides support for implementing converters in a way which makes them easy to
+/// chain and to use with streams.
+///
+/// To use this library in your code:
+///
+/// import 'dart:convert';
+///
+/// Two commonly used converters are the top-level instances of
+/// [JsonCodec] and [Utf8Codec], named [json] and [utf8], respectively.
+///
+/// JSON is a simple text format for representing
+/// structured objects and collections.
+/// The JSON encoder/decoder transforms between strings and
+/// object structures, such as lists and maps, using the JSON format.
+///
+/// UTF-8 is a common variable-width encoding that can represent
+/// every character in the Unicode character set.
+/// The UTF-8 encoder/decoder transforms between Strings and bytes.
+///
+/// Converters are often used with streams
+/// to transform the data that comes through the stream
+/// as it becomes available.
+/// The following code uses two converters.
+/// The first is a UTF-8 decoder, which converts the data from bytes to UTF-8
+/// as it's read from a file,
+/// The second is an instance of [LineSplitter],
+/// which splits the data on newline boundaries.
+///
+/// var lineNumber = 1;
+/// var stream = File('quotes.txt').openRead();
+///
+/// stream.transform(utf8.decoder)
+/// .transform(const LineSplitter())
+/// .listen((line) {
+/// if (showLineNumbers) {
+/// stdout.write('${lineNumber++} ');
+/// }
+/// stdout.writeln(line);
+/// });
+///
+/// See the documentation for the [Codec] and [Converter] classes
+/// for information about creating your own converters.
+///
+/// {@category Core}
+library dart.convert;
+
+import 'dart:async';
+import 'dart:typed_data';
+import 'dart:_internal' show CastConverter, parseHexByte;
+
+part 'ascii.dart';
+part 'base64.dart';
+part 'byte_conversion.dart';
+part 'chunked_conversion.dart';
+part 'codec.dart';
+part 'converter.dart';
+part 'encoding.dart';
+part 'html_escape.dart';
+part 'json.dart';
+part 'latin1.dart';
+part 'line_splitter.dart';
+part 'string_conversion.dart';
+part 'utf.dart';
diff --git a/sdk_nnbd/lib/convert/convert_sources.gni b/sdk_nnbd/lib/convert/convert_sources.gni
new file mode 100644
index 0000000..ad79649
--- /dev/null
+++ b/sdk_nnbd/lib/convert/convert_sources.gni
@@ -0,0 +1,23 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# This file contains all sources for the dart:convert library.
+convert_sdk_sources = [
+ "convert.dart",
+
+ # The above file needs to be first as it lists the parts below.
+ "ascii.dart",
+ "base64.dart",
+ "byte_conversion.dart",
+ "chunked_conversion.dart",
+ "codec.dart",
+ "converter.dart",
+ "encoding.dart",
+ "html_escape.dart",
+ "json.dart",
+ "latin1.dart",
+ "line_splitter.dart",
+ "string_conversion.dart",
+ "utf.dart",
+]
diff --git a/sdk_nnbd/lib/convert/converter.dart b/sdk_nnbd/lib/convert/converter.dart
new file mode 100644
index 0000000..2167933
--- /dev/null
+++ b/sdk_nnbd/lib/convert/converter.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// A [Converter] converts data from one representation into another.
+///
+/// It is recommended that implementations of `Converter` extend this class,
+/// to inherit any further methods that may be added to the class.
+abstract class Converter<S, T> extends StreamTransformerBase<S, T> {
+ const Converter();
+
+ /// Adapts [source] to be a `Converter<TS, TT>`.
+ ///
+ /// This allows [source] to be used at the new type, but at run-time it
+ /// must satisfy the requirements of both the new type and its original type.
+ ///
+ /// Conversion input must be both [SS] and [TS] and the output created by
+ /// [source] for those input must be both [ST] and [TT].
+ static Converter<TS, TT> castFrom<SS, ST, TS, TT>(Converter<SS, ST> source) =>
+ CastConverter<SS, ST, TS, TT>(source);
+
+ /// Converts [input] and returns the result of the conversion.
+ T convert(S input);
+
+ /// Fuses `this` with [other].
+ ///
+ /// Encoding with the resulting converter is equivalent to converting with
+ /// `this` before converting with `other`.
+ Converter<S, TT> fuse<TT>(Converter<T, TT> other) {
+ return _FusedConverter<S, T, TT>(this, other);
+ }
+
+ /// Starts a chunked conversion.
+ ///
+ /// The returned sink serves as input for the long-running conversion. The
+ /// given [sink] serves as output.
+ Sink<S> startChunkedConversion(Sink<T> sink) {
+ throw UnsupportedError(
+ "This converter does not support chunked conversions: $this");
+ }
+
+ Stream<T> bind(Stream<S> stream) {
+ return Stream<T>.eventTransformed(
+ stream, (EventSink sink) => _ConverterStreamEventSink(this, sink));
+ }
+
+ /// Provides a `Converter<RS, RT>` view of this stream transformer.
+ ///
+ /// The resulting transformer will check at run-time that all conversion
+ /// inputs are actually instances of [S],
+ /// and it will check that all conversion output produced by this converter
+ /// are actually instances of [RT].
+ Converter<RS, RT> cast<RS, RT>() => Converter.castFrom<S, T, RS, RT>(this);
+}
+
+/// Fuses two converters.
+///
+/// For a non-chunked conversion converts the input in sequence.
+class _FusedConverter<S, M, T> extends Converter<S, T> {
+ final Converter<S, M> _first;
+ final Converter<M, T> _second;
+
+ _FusedConverter(this._first, this._second);
+
+ T convert(S input) => _second.convert(_first.convert(input));
+
+ Sink<S> startChunkedConversion(Sink<T> sink) {
+ return _first.startChunkedConversion(_second.startChunkedConversion(sink));
+ }
+}
diff --git a/sdk_nnbd/lib/convert/encoding.dart b/sdk_nnbd/lib/convert/encoding.dart
new file mode 100644
index 0000000..7ce8ec3
--- /dev/null
+++ b/sdk_nnbd/lib/convert/encoding.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// Open-ended Encoding enum.
+abstract class Encoding extends Codec<String, List<int>> {
+ const Encoding();
+
+ /// Returns the encoder from `String` to `List<int>`.
+ ///
+ /// It may be stateful and should not be reused.
+ Converter<String, List<int>> get encoder;
+
+ /// Returns the decoder of `this`, converting from `List<int>` to `String`.
+ ///
+ /// It may be stateful and should not be reused.
+ Converter<List<int>, String> get decoder;
+
+ Future<String> decodeStream(Stream<List<int>> byteStream) {
+ return decoder
+ .bind(byteStream)
+ .fold(StringBuffer(),
+ (StringBuffer buffer, String string) => buffer..write(string))
+ .then((StringBuffer buffer) => buffer.toString());
+ }
+
+ /// Name of the encoding.
+ ///
+ /// If the encoding is standardized, this is the lower-case version of one of
+ /// the IANA official names for the character set (see
+ /// http://www.iana.org/assignments/character-sets/character-sets.xml)
+ String get name;
+
+ // All aliases (in lowercase) of supported encoding from
+ // http://www.iana.org/assignments/character-sets/character-sets.xml.
+ static final Map<String, Encoding> _nameToEncoding = <String, Encoding>{
+ // ISO_8859-1:1987.
+ "iso_8859-1:1987": latin1,
+ "iso-ir-100": latin1,
+ "iso_8859-1": latin1,
+ "iso-8859-1": latin1,
+ "latin1": latin1,
+ "l1": latin1,
+ "ibm819": latin1,
+ "cp819": latin1,
+ "csisolatin1": latin1,
+
+ // US-ASCII.
+ "iso-ir-6": ascii,
+ "ansi_x3.4-1968": ascii,
+ "ansi_x3.4-1986": ascii,
+ "iso_646.irv:1991": ascii,
+ "iso646-us": ascii,
+ "us-ascii": ascii,
+ "us": ascii,
+ "ibm367": ascii,
+ "cp367": ascii,
+ "csascii": ascii,
+ "ascii": ascii, // This is not in the IANA official names.
+
+ // UTF-8.
+ "csutf8": utf8,
+ "utf-8": utf8
+ };
+
+ /// Gets an [Encoding] object from the name of the character set
+ /// name. The names used are the IANA official names for the
+ /// character set (see
+ /// http://www.iana.org/assignments/character-sets/character-sets.xml).
+ ///
+ /// The [name] passed is case insensitive.
+ ///
+ /// If character set is not supported [:null:] is returned.
+ static Encoding getByName(String name) {
+ if (name == null) return null;
+ name = name.toLowerCase();
+ return _nameToEncoding[name];
+ }
+}
diff --git a/sdk_nnbd/lib/convert/html_escape.dart b/sdk_nnbd/lib/convert/html_escape.dart
new file mode 100644
index 0000000..a0a7119
--- /dev/null
+++ b/sdk_nnbd/lib/convert/html_escape.dart
@@ -0,0 +1,223 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// A `String` converter that converts characters to HTML entities.
+///
+/// This is intended to sanitize text before inserting the text into an HTML
+/// document. Characters that are meaningful in HTML are converted to
+/// HTML entities (like `&` for `&`).
+///
+/// The general converter escapes all characters that are meaningful in HTML
+/// attributes or normal element context. Elements with special content types
+/// (like CSS or JavaScript) may need a more specialized escaping that
+/// understands that content type.
+///
+/// If the context where the text will be inserted is known in more detail,
+/// it's possible to omit escaping some characters (like quotes when not
+/// inside an attribute value).
+///
+/// The escaped text should only be used inside quoted HTML attributes values
+/// or as text content of a normal element. Using the escaped text inside a
+/// tag, but not inside a quoted attribute value, is still dangerous.
+const HtmlEscape htmlEscape = HtmlEscape();
+
+/// HTML escape modes.
+///
+/// Allows specifying a mode for HTML escaping that depend on the context
+/// where the escaped result is going to be used.
+/// The relevant contexts are:
+///
+/// * as text content of an HTML element.
+/// * as value of a (single- or double-) quoted attribute value.
+///
+/// All modes require escaping of `&` (ampersand) characters, and may
+/// enable escaping of more characters.
+///
+/// Custom escape modes can be created using the [HtmlEscapeMode.HtmlEscapeMode]
+/// constructor.
+class HtmlEscapeMode {
+ final String _name;
+
+ /// Whether to escape '<' and '>'.
+ final bool escapeLtGt;
+
+ /// Whether to escape '"' (quote).
+ final bool escapeQuot;
+
+ /// Whether to escape "'" (apostrophe).
+ final bool escapeApos;
+
+ /// Whether to escape "/" (forward slash, solidus).
+ ///
+ /// Escaping a slash is recommended to avoid cross-site scripting attacks by
+ /// [the Open Web Application Security Project](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet#RULE_.231_-_HTML_Escape_Before_Inserting_Untrusted_Data_into_HTML_Element_Content)
+ final bool escapeSlash;
+
+ /// Default escaping mode which escape all characters.
+ ///
+ /// The result of such an escaping is usable both in element content and
+ /// in any attribute value.
+ ///
+ /// The escaping only works for elements with normal HTML content,
+ /// and not for, for example, script or style element content,
+ /// which require escapes matching their particular content syntax.
+ static const HtmlEscapeMode unknown =
+ HtmlEscapeMode._('unknown', true, true, true, true);
+
+ /// Escaping mode for text going into double-quoted HTML attribute values.
+ ///
+ /// The result should not be used as the content of an unquoted
+ /// or single-quoted attribute value.
+ ///
+ /// Escapes double quotes (`"`) but not single quotes (`'`),
+ /// and escapes `<` and `>` characters because they are not allowed
+ /// in strict XHTML attributes
+ static const HtmlEscapeMode attribute =
+ HtmlEscapeMode._('attribute', true, true, false, false);
+
+ /// Escaping mode for text going into single-quoted HTML attribute values.
+ ///
+ /// The result should not be used as the content of an unquoted
+ /// or double-quoted attribute value.
+ ///
+ /// Escapes single quotes (`'`) but not double quotes (`"`),
+ /// and escapes `<` and `>` characters because they are not allowed
+ /// in strict XHTML attributes
+ static const HtmlEscapeMode sqAttribute =
+ HtmlEscapeMode._('attribute', true, false, true, false);
+
+ /// Escaping mode for text going into HTML element content.
+ ///
+ /// The escaping only works for elements with normal HTML content,
+ /// and not for, for example, script or style element content,
+ /// which require escapes matching their particular content syntax.
+ ///
+ /// Escapes `<` and `>` characters.
+ static const HtmlEscapeMode element =
+ HtmlEscapeMode._('element', true, false, false, false);
+
+ const HtmlEscapeMode._(this._name, this.escapeLtGt, this.escapeQuot,
+ this.escapeApos, this.escapeSlash);
+
+ /// Create a custom escaping mode.
+ ///
+ /// All modes escape `&`.
+ /// The mode can further be set to escape `<` and `>` ([escapeLtGt]),
+ /// `"` ([escapeQuot]), `'` ([escapeApos]), and/or `/` ([escapeSlash]).
+ const HtmlEscapeMode(
+ {String name = "custom",
+ this.escapeLtGt = false,
+ this.escapeQuot = false,
+ this.escapeApos = false,
+ this.escapeSlash = false})
+ : _name = name;
+
+ String toString() => _name;
+}
+
+/// Converter which escapes characters with special meaning in HTML.
+///
+/// The converter finds characters that are significant in HTML source and
+/// replaces them with corresponding HTML entities.
+///
+/// The characters that need escaping in HTML are:
+///
+/// * `&` (ampersand) always need to be escaped.
+/// * `<` (less than) and '>' (greater than) when inside an element.
+/// * `"` (quote) when inside a double-quoted attribute value.
+/// * `'` (apostrophe) when inside a single-quoted attribute value.
+/// Apostrophe is escaped as `'` instead of `'` since
+/// not all browsers understand `'`.
+/// * `/` (slash) is recommended to be escaped because it may be used
+/// to terminate an element in some HTML dialects.
+///
+/// Escaping `>` (greater than) isn't necessary, but the result is often
+/// found to be easier to read if greater-than is also escaped whenever
+/// less-than is.
+class HtmlEscape extends Converter<String, String> {
+ /// The [HtmlEscapeMode] used by the converter.
+ final HtmlEscapeMode mode;
+
+ /// Create converter that escapes HTML characters.
+ ///
+ /// If [mode] is provided as either [HtmlEscapeMode.attribute] or
+ /// [HtmlEscapeMode.element], only the corresponding subset of HTML
+ /// characters are escaped.
+ /// The default is to escape all HTML characters.
+ const HtmlEscape([this.mode = HtmlEscapeMode.unknown]);
+
+ String convert(String text) {
+ var val = _convert(text, 0, text.length);
+ return val == null ? text : val;
+ }
+
+ /// Converts the substring of text from start to end.
+ ///
+ /// Returns `null` if no changes were necessary, otherwise returns
+ /// the converted string.
+ String _convert(String text, int start, int end) {
+ StringBuffer result;
+ for (var i = start; i < end; i++) {
+ var ch = text[i];
+ String replacement;
+ switch (ch) {
+ case '&':
+ replacement = '&';
+ break;
+ case '"':
+ if (mode.escapeQuot) replacement = '"';
+ break;
+ case "'":
+ if (mode.escapeApos) replacement = ''';
+ break;
+ case '<':
+ if (mode.escapeLtGt) replacement = '<';
+ break;
+ case '>':
+ if (mode.escapeLtGt) replacement = '>';
+ break;
+ case '/':
+ if (mode.escapeSlash) replacement = '/';
+ break;
+ }
+ if (replacement != null) {
+ result ??= StringBuffer();
+ if (i > start) result.write(text.substring(start, i));
+ result.write(replacement);
+ start = i + 1;
+ }
+ }
+ if (result == null) return null;
+ if (end > start) result.write(text.substring(start, end));
+ return result.toString();
+ }
+
+ StringConversionSink startChunkedConversion(Sink<String> sink) {
+ return _HtmlEscapeSink(this,
+ sink is StringConversionSink ? sink : StringConversionSink.from(sink));
+ }
+}
+
+class _HtmlEscapeSink extends StringConversionSinkBase {
+ final HtmlEscape _escape;
+ final StringConversionSink _sink;
+
+ _HtmlEscapeSink(this._escape, this._sink);
+
+ void addSlice(String chunk, int start, int end, bool isLast) {
+ var val = _escape._convert(chunk, start, end);
+ if (val == null) {
+ _sink.addSlice(chunk, start, end, isLast);
+ } else {
+ _sink.add(val);
+ if (isLast) _sink.close();
+ }
+ }
+
+ void close() {
+ _sink.close();
+ }
+}
diff --git a/sdk_nnbd/lib/convert/json.dart b/sdk_nnbd/lib/convert/json.dart
new file mode 100644
index 0000000..5746e52
--- /dev/null
+++ b/sdk_nnbd/lib/convert/json.dart
@@ -0,0 +1,1034 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// Error thrown by JSON serialization if an object cannot be serialized.
+///
+/// The [unsupportedObject] field holds that object that failed to be serialized.
+///
+/// If an object isn't directly serializable, the serializer calls the `toJson`
+/// method on the object. If that call fails, the error will be stored in the
+/// [cause] field. If the call returns an object that isn't directly
+/// serializable, the [cause] is null.
+class JsonUnsupportedObjectError extends Error {
+ /// The object that could not be serialized.
+ final Object unsupportedObject;
+
+ /// The exception thrown when trying to convert the object.
+ final Object cause;
+
+ /// The partial result of the conversion, up until the error happened.
+ ///
+ /// May be null.
+ final String partialResult;
+
+ JsonUnsupportedObjectError(this.unsupportedObject,
+ {this.cause, this.partialResult});
+
+ String toString() {
+ var safeString = Error.safeToString(unsupportedObject);
+ String prefix;
+ if (cause != null) {
+ prefix = "Converting object to an encodable object failed:";
+ } else {
+ prefix = "Converting object did not return an encodable object:";
+ }
+ return "$prefix $safeString";
+ }
+}
+
+/// Reports that an object could not be stringified due to cyclic references.
+///
+/// An object that references itself cannot be serialized by
+/// [JsonCodec.encode]/[JsonEncoder.convert].
+/// When the cycle is detected, a [JsonCyclicError] is thrown.
+class JsonCyclicError extends JsonUnsupportedObjectError {
+ /// The first object that was detected as part of a cycle.
+ JsonCyclicError(Object object) : super(object);
+ String toString() => "Cyclic error in JSON stringify";
+}
+
+/// An instance of the default implementation of the [JsonCodec].
+///
+/// This instance provides a convenient access to the most common JSON
+/// use cases.
+///
+/// Examples:
+///
+/// var encoded = json.encode([1, 2, { "a": null }]);
+/// var decoded = json.decode('["foo", { "bar": 499 }]');
+///
+/// The top-level [jsonEncode] and [jsonDecode] functions may be used instead if
+/// a local variable shadows the [json] constant.
+const JsonCodec json = JsonCodec();
+
+/// Converts [value] to a JSON string.
+///
+/// If value contains objects that are not directly encodable to a JSON
+/// string (a value that is not a number, boolean, string, null, list or a map
+/// with string keys), the [toEncodable] function is used to convert it to an
+/// object that must be directly encodable.
+///
+/// If [toEncodable] is omitted, it defaults to a function that returns the
+/// result of calling `.toJson()` on the unencodable object.
+///
+/// Shorthand for [json.encode]. Useful if a local variable shadows the global
+/// [json] constant.
+String jsonEncode(Object object, {Object toEncodable(Object nonEncodable)}) =>
+ json.encode(object, toEncodable: toEncodable);
+
+/// Parses the string and returns the resulting Json object.
+///
+/// The optional [reviver] function is called once for each object or list
+/// property that has been parsed during decoding. The `key` argument is either
+/// the integer list index for a list property, the string map key for object
+/// properties, or `null` for the final result.
+///
+/// The default [reviver] (when not provided) is the identity function.
+///
+/// Shorthand for [json.decode]. Useful if a local variable shadows the global
+/// [json] constant.
+dynamic jsonDecode(String source, {Object reviver(Object key, Object value)}) =>
+ json.decode(source, reviver: reviver);
+
+/// A [JsonCodec] encodes JSON objects to strings and decodes strings to
+/// JSON objects.
+///
+/// Examples:
+///
+/// var encoded = json.encode([1, 2, { "a": null }]);
+/// var decoded = json.decode('["foo", { "bar": 499 }]');
+class JsonCodec extends Codec<Object, String> {
+ final Function(Object key, Object value) _reviver;
+ final Function(dynamic) _toEncodable;
+
+ /// Creates a `JsonCodec` with the given reviver and encoding function.
+ ///
+ /// The [reviver] function is called during decoding. It is invoked once for
+ /// each object or list property that has been parsed.
+ /// The `key` argument is either the integer list index for a list property,
+ /// the string map key for object properties, or `null` for the final result.
+ ///
+ /// If [reviver] is omitted, it defaults to returning the value argument.
+ ///
+ /// The [toEncodable] function is used during encoding. It is invoked for
+ /// values that are not directly encodable to a string (a value that is not a
+ /// number, boolean, string, null, list or a map with string keys). The
+ /// function must return an object that is directly encodable. The elements of
+ /// a returned list and values of a returned map do not need to be directly
+ /// encodable, and if they aren't, `toEncodable` will be used on them as well.
+ /// Please notice that it is possible to cause an infinite recursive regress
+ /// in this way, by effectively creating an infinite data structure through
+ /// repeated call to `toEncodable`.
+ ///
+ /// If [toEncodable] is omitted, it defaults to a function that returns the
+ /// result of calling `.toJson()` on the unencodable object.
+ const JsonCodec({reviver(Object key, Object value), toEncodable(var object)})
+ : _reviver = reviver,
+ _toEncodable = toEncodable;
+
+ /// Creates a `JsonCodec` with the given reviver.
+ ///
+ /// The [reviver] function is called once for each object or list property
+ /// that has been parsed during decoding. The `key` argument is either the
+ /// integer list index for a list property, the string map key for object
+ /// properties, or `null` for the final result.
+ JsonCodec.withReviver(reviver(Object key, Object value))
+ : this(reviver: reviver);
+
+ /// Parses the string and returns the resulting Json object.
+ ///
+ /// The optional [reviver] function is called once for each object or list
+ /// property that has been parsed during decoding. The `key` argument is either
+ /// the integer list index for a list property, the string map key for object
+ /// properties, or `null` for the final result.
+ ///
+ /// The default [reviver] (when not provided) is the identity function.
+ dynamic decode(String source, {reviver(Object key, Object value)}) {
+ reviver ??= _reviver;
+ if (reviver == null) return decoder.convert(source);
+ return JsonDecoder(reviver).convert(source);
+ }
+
+ /// Converts [value] to a JSON string.
+ ///
+ /// If value contains objects that are not directly encodable to a JSON
+ /// string (a value that is not a number, boolean, string, null, list or a map
+ /// with string keys), the [toEncodable] function is used to convert it to an
+ /// object that must be directly encodable.
+ ///
+ /// If [toEncodable] is omitted, it defaults to a function that returns the
+ /// result of calling `.toJson()` on the unencodable object.
+ String encode(Object value, {toEncodable(object)}) {
+ toEncodable ??= _toEncodable;
+ if (toEncodable == null) return encoder.convert(value);
+ return JsonEncoder(toEncodable).convert(value);
+ }
+
+ JsonEncoder get encoder {
+ if (_toEncodable == null) return const JsonEncoder();
+ return JsonEncoder(_toEncodable);
+ }
+
+ JsonDecoder get decoder {
+ if (_reviver == null) return const JsonDecoder();
+ return JsonDecoder(_reviver);
+ }
+}
+
+/// This class converts JSON objects to strings.
+class JsonEncoder extends Converter<Object, String> {
+ /// The string used for indention.
+ ///
+ /// When generating multi-line output, this string is inserted once at the
+ /// beginning of each indented line for each level of indentation.
+ ///
+ /// If `null`, the output is encoded as a single line.
+ final String indent;
+
+ /// Function called on non-encodable objects to return a replacement
+ /// encodable object that will be encoded in the orignal's place.
+ final Function(dynamic) _toEncodable;
+
+ /// Creates a JSON encoder.
+ ///
+ /// The JSON encoder handles numbers, strings, booleans, null, lists and
+ /// maps with string keys directly.
+ ///
+ /// Any other object is attempted converted by [toEncodable] to an
+ /// object that is of one of the convertible types.
+ ///
+ /// If [toEncodable] is omitted, it defaults to calling `.toJson()` on
+ /// the object.
+ const JsonEncoder([toEncodable(object)])
+ : indent = null,
+ _toEncodable = toEncodable;
+
+ /// Creates a JSON encoder that creates multi-line JSON.
+ ///
+ /// The encoding of elements of lists and maps are indented and put on separate
+ /// lines. The [indent] string is prepended to these elements, once for each
+ /// level of indentation.
+ ///
+ /// If [indent] is `null`, the output is encoded as a single line.
+ ///
+ /// The JSON encoder handles numbers, strings, booleans, null, lists and
+ /// maps with string keys directly.
+ ///
+ /// Any other object is attempted converted by [toEncodable] to an
+ /// object that is of one of the convertible types.
+ ///
+ /// If [toEncodable] is omitted, it defaults to calling `.toJson()` on
+ /// the object.
+ const JsonEncoder.withIndent(this.indent, [toEncodable(object)])
+ : _toEncodable = toEncodable;
+
+ /// Converts [object] to a JSON [String].
+ ///
+ /// Directly serializable values are [num], [String], [bool], and [Null], as
+ /// well as some [List] and [Map] values. For [List], the elements must all be
+ /// serializable. For [Map], the keys must be [String] and the values must be
+ /// serializable.
+ ///
+ /// If a value of any other type is attempted to be serialized, the
+ /// `toEncodable` function provided in the constructor is called with the value
+ /// as argument. The result, which must be a directly serializable value, is
+ /// serialized instead of the original value.
+ ///
+ /// If the conversion throws, or returns a value that is not directly
+ /// serializable, a [JsonUnsupportedObjectError] exception is thrown.
+ /// If the call throws, the error is caught and stored in the
+ /// [JsonUnsupportedObjectError]'s [:cause:] field.
+ ///
+ /// If a [List] or [Map] contains a reference to itself, directly or through
+ /// other lists or maps, it cannot be serialized and a [JsonCyclicError] is
+ /// thrown.
+ ///
+ /// [object] should not change during serialization.
+ ///
+ /// If an object is serialized more than once, [convert] may cache the text
+ /// for it. In other words, if the content of an object changes after it is
+ /// first serialized, the new values may not be reflected in the result.
+ String convert(Object object) =>
+ _JsonStringStringifier.stringify(object, _toEncodable, indent);
+
+ /// Starts a chunked conversion.
+ ///
+ /// The converter works more efficiently if the given [sink] is a
+ /// [StringConversionSink].
+ ///
+ /// Returns a chunked-conversion sink that accepts at most one object. It is
+ /// an error to invoke `add` more than once on the returned sink.
+ ChunkedConversionSink<Object> startChunkedConversion(Sink<String> sink) {
+ if (sink is _Utf8EncoderSink) {
+ return _JsonUtf8EncoderSink(
+ sink._sink,
+ _toEncodable,
+ JsonUtf8Encoder._utf8Encode(indent),
+ JsonUtf8Encoder._defaultBufferSize);
+ }
+ return _JsonEncoderSink(
+ sink is StringConversionSink ? sink : StringConversionSink.from(sink),
+ _toEncodable,
+ indent);
+ }
+
+ // Override the base class's bind, to provide a better type.
+ Stream<String> bind(Stream<Object> stream) => super.bind(stream);
+
+ Converter<Object, T> fuse<T>(Converter<String, T> other) {
+ if (other is Utf8Encoder && T is List<int>) {
+ // The instance check guarantees that `T` is (a subtype of) List<int>,
+ // but the static type system doesn't know that, and so we cast.
+ // Cast through dynamic to keep the cast implicit for builds using
+ // unchecked implicit casts.
+ return JsonUtf8Encoder(indent, _toEncodable) as dynamic;
+ }
+ return super.fuse<T>(other);
+ }
+}
+
+/// Encoder that encodes a single object as a UTF-8 encoded JSON string.
+///
+/// This encoder works equivalently to first converting the object to
+/// a JSON string, and then UTF-8 encoding the string, but without
+/// creating an intermediate string.
+class JsonUtf8Encoder extends Converter<Object, List<int>> {
+ /// Default buffer size used by the JSON-to-UTF-8 encoder.
+ static const int _defaultBufferSize = 256;
+ @deprecated
+ static const int DEFAULT_BUFFER_SIZE = _defaultBufferSize;
+
+ /// Indentation used in pretty-print mode, `null` if not pretty.
+ final List<int> _indent;
+
+ /// Function called with each un-encodable object encountered.
+ final Function(dynamic) _toEncodable;
+
+ /// UTF-8 buffer size.
+ final int _bufferSize;
+
+ /// Create converter.
+ ///
+ /// If [indent] is non-`null`, the converter attempts to "pretty-print" the
+ /// JSON, and uses `indent` as the indentation. Otherwise the result has no
+ /// whitespace outside of string literals.
+ /// If `indent` contains characters that are not valid JSON whitespace
+ /// characters, the result will not be valid JSON. JSON whitespace characters
+ /// are space (U+0020), tab (U+0009), line feed (U+000a) and carriage return
+ /// (U+000d) ([ECMA
+ /// 404](http://www.ecma-international.org/publications/standards/Ecma-404.htm)).
+ ///
+ /// The [bufferSize] is the size of the internal buffers used to collect
+ /// UTF-8 code units.
+ /// If using [startChunkedConversion], it will be the size of the chunks.
+ ///
+ /// The JSON encoder handles numbers, strings, booleans, null, lists and maps
+ /// directly.
+ ///
+ /// Any other object is attempted converted by [toEncodable] to an object that
+ /// is of one of the convertible types.
+ ///
+ /// If [toEncodable] is omitted, it defaults to calling `.toJson()` on the
+ /// object.
+ JsonUtf8Encoder(
+ [String indent, toEncodable(object), int bufferSize = _defaultBufferSize])
+ : _indent = _utf8Encode(indent),
+ _toEncodable = toEncodable,
+ _bufferSize = bufferSize;
+
+ static List<int> _utf8Encode(String string) {
+ if (string == null) return null;
+ if (string.isEmpty) return Uint8List(0);
+ checkAscii:
+ {
+ for (var i = 0; i < string.length; i++) {
+ if (string.codeUnitAt(i) >= 0x80) break checkAscii;
+ }
+ return string.codeUnits;
+ }
+ return utf8.encode(string);
+ }
+
+ /// Convert [object] into UTF-8 encoded JSON.
+ List<int> convert(Object object) {
+ var bytes = <List<int>>[];
+ // The `stringify` function always converts into chunks.
+ // Collect the chunks into the `bytes` list, then combine them afterwards.
+ void addChunk(Uint8List chunk, int start, int end) {
+ if (start > 0 || end < chunk.length) {
+ var length = end - start;
+ chunk =
+ Uint8List.view(chunk.buffer, chunk.offsetInBytes + start, length);
+ }
+ bytes.add(chunk);
+ }
+
+ _JsonUtf8Stringifier.stringify(
+ object, _indent, _toEncodable, _bufferSize, addChunk);
+ if (bytes.length == 1) return bytes[0];
+ var length = 0;
+ for (var i = 0; i < bytes.length; i++) {
+ length += bytes[i].length;
+ }
+ var result = Uint8List(length);
+ for (var i = 0, offset = 0; i < bytes.length; i++) {
+ var byteList = bytes[i];
+ int end = offset + byteList.length;
+ result.setRange(offset, end, byteList);
+ offset = end;
+ }
+ return result;
+ }
+
+ /// Start a chunked conversion.
+ ///
+ /// Only one object can be passed into the returned sink.
+ ///
+ /// The argument [sink] will receive byte lists in sizes depending on the
+ /// `bufferSize` passed to the constructor when creating this encoder.
+ ChunkedConversionSink<Object> startChunkedConversion(Sink<List<int>> sink) {
+ ByteConversionSink byteSink;
+ if (sink is ByteConversionSink) {
+ byteSink = sink;
+ } else {
+ byteSink = ByteConversionSink.from(sink);
+ }
+ return _JsonUtf8EncoderSink(byteSink, _toEncodable, _indent, _bufferSize);
+ }
+
+ // Override the base class's bind, to provide a better type.
+ Stream<List<int>> bind(Stream<Object> stream) {
+ return super.bind(stream);
+ }
+}
+
+/// Implements the chunked conversion from object to its JSON representation.
+///
+/// The sink only accepts one value, but will produce output in a chunked way.
+class _JsonEncoderSink extends ChunkedConversionSink<Object> {
+ final String _indent;
+ final Function(dynamic) _toEncodable;
+ final StringConversionSink _sink;
+ bool _isDone = false;
+
+ _JsonEncoderSink(this._sink, this._toEncodable, this._indent);
+
+ /// Encodes the given object [o].
+ ///
+ /// It is an error to invoke this method more than once on any instance. While
+ /// this makes the input effectively non-chunked the output will be generated
+ /// in a chunked way.
+ void add(Object o) {
+ if (_isDone) {
+ throw StateError("Only one call to add allowed");
+ }
+ _isDone = true;
+ var stringSink = _sink.asStringSink();
+ _JsonStringStringifier.printOn(o, stringSink, _toEncodable, _indent);
+ stringSink.close();
+ }
+
+ void close() {/* do nothing */}
+}
+
+/// Sink returned when starting a chunked conversion from object to bytes.
+class _JsonUtf8EncoderSink extends ChunkedConversionSink<Object> {
+ /// The byte sink receiveing the encoded chunks.
+ final ByteConversionSink _sink;
+ final List<int> _indent;
+ final Function(dynamic) _toEncodable;
+ final int _bufferSize;
+ bool _isDone = false;
+ _JsonUtf8EncoderSink(
+ this._sink, this._toEncodable, this._indent, this._bufferSize);
+
+ /// Callback called for each slice of result bytes.
+ void _addChunk(Uint8List chunk, int start, int end) {
+ _sink.addSlice(chunk, start, end, false);
+ }
+
+ void add(Object object) {
+ if (_isDone) {
+ throw StateError("Only one call to add allowed");
+ }
+ _isDone = true;
+ _JsonUtf8Stringifier.stringify(
+ object, _indent, _toEncodable, _bufferSize, _addChunk);
+ _sink.close();
+ }
+
+ void close() {
+ if (!_isDone) {
+ _isDone = true;
+ _sink.close();
+ }
+ }
+}
+
+/// This class parses JSON strings and builds the corresponding objects.
+class JsonDecoder extends Converter<String, Object> {
+ final Function(Object key, Object value) _reviver;
+
+ /// Constructs a new JsonDecoder.
+ ///
+ /// The [reviver] may be `null`.
+ const JsonDecoder([reviver(Object key, Object value)]) : _reviver = reviver;
+
+ /// Converts the given JSON-string [input] to its corresponding object.
+ ///
+ /// Parsed JSON values are of the types [num], [String], [bool], [Null],
+ /// [List]s of parsed JSON values or [Map]s from [String] to parsed JSON
+ /// values.
+ ///
+ /// If `this` was initialized with a reviver, then the parsing operation
+ /// invokes the reviver on every object or list property that has been parsed.
+ /// The arguments are the property name ([String]) or list index ([int]), and
+ /// the value is the parsed value. The return value of the reviver is used as
+ /// the value of that property instead the parsed value.
+ ///
+ /// Throws [FormatException] if the input is not valid JSON text.
+ dynamic convert(String input) => _parseJson(input, _reviver);
+
+ /// Starts a conversion from a chunked JSON string to its corresponding object.
+ ///
+ /// The output [sink] receives exactly one decoded element through `add`.
+ external StringConversionSink startChunkedConversion(Sink<Object> sink);
+
+ // Override the base class's bind, to provide a better type.
+ Stream<Object> bind(Stream<String> stream) => super.bind(stream);
+}
+
+// Internal optimized JSON parsing implementation.
+external _parseJson(String source, reviver(key, value));
+
+// Implementation of encoder/stringifier.
+
+dynamic _defaultToEncodable(dynamic object) => object.toJson();
+
+/// JSON encoder that traverses an object structure and writes JSON source.
+///
+/// This is an abstract implementation that doesn't decide on the output
+/// format, but writes the JSON through abstract methods like [writeString].
+abstract class _JsonStringifier {
+ // Character code constants.
+ static const int backspace = 0x08;
+ static const int tab = 0x09;
+ static const int newline = 0x0a;
+ static const int carriageReturn = 0x0d;
+ static const int formFeed = 0x0c;
+ static const int quote = 0x22;
+ static const int char_0 = 0x30;
+ static const int backslash = 0x5c;
+ static const int char_b = 0x62;
+ static const int char_f = 0x66;
+ static const int char_n = 0x6e;
+ static const int char_r = 0x72;
+ static const int char_t = 0x74;
+ static const int char_u = 0x75;
+
+ /// List of objects currently being traversed. Used to detect cycles.
+ final List _seen = [];
+
+ /// Function called for each un-encodable object encountered.
+ final Function(dynamic) _toEncodable;
+
+ _JsonStringifier(toEncodable(o))
+ : _toEncodable = toEncodable ?? _defaultToEncodable;
+
+ String get _partialResult;
+
+ /// Append a string to the JSON output.
+ void writeString(String characters);
+
+ /// Append part of a string to the JSON output.
+ void writeStringSlice(String characters, int start, int end);
+
+ /// Append a single character, given by its code point, to the JSON output.
+ void writeCharCode(int charCode);
+
+ /// Write a number to the JSON output.
+ void writeNumber(num number);
+
+ // ('0' + x) or ('a' + x - 10)
+ static int hexDigit(int x) => x < 10 ? 48 + x : 87 + x;
+
+ /// Write, and suitably escape, a string's content as a JSON string literal.
+ void writeStringContent(String s) {
+ var offset = 0;
+ final length = s.length;
+ for (var i = 0; i < length; i++) {
+ var charCode = s.codeUnitAt(i);
+ if (charCode > backslash) continue;
+ if (charCode < 32) {
+ if (i > offset) writeStringSlice(s, offset, i);
+ offset = i + 1;
+ writeCharCode(backslash);
+ switch (charCode) {
+ case backspace:
+ writeCharCode(char_b);
+ break;
+ case tab:
+ writeCharCode(char_t);
+ break;
+ case newline:
+ writeCharCode(char_n);
+ break;
+ case formFeed:
+ writeCharCode(char_f);
+ break;
+ case carriageReturn:
+ writeCharCode(char_r);
+ break;
+ default:
+ writeCharCode(char_u);
+ writeCharCode(char_0);
+ writeCharCode(char_0);
+ writeCharCode(hexDigit((charCode >> 4) & 0xf));
+ writeCharCode(hexDigit(charCode & 0xf));
+ break;
+ }
+ } else if (charCode == quote || charCode == backslash) {
+ if (i > offset) writeStringSlice(s, offset, i);
+ offset = i + 1;
+ writeCharCode(backslash);
+ writeCharCode(charCode);
+ }
+ }
+ if (offset == 0) {
+ writeString(s);
+ } else if (offset < length) {
+ writeStringSlice(s, offset, length);
+ }
+ }
+
+ /// Check if an encountered object is already being traversed.
+ ///
+ /// Records the object if it isn't already seen. Should have a matching call to
+ /// [_removeSeen] when the object is no longer being traversed.
+ void _checkCycle(object) {
+ for (var i = 0; i < _seen.length; i++) {
+ if (identical(object, _seen[i])) {
+ throw JsonCyclicError(object);
+ }
+ }
+ _seen.add(object);
+ }
+
+ /// Remove [object] from the list of currently traversed objects.
+ ///
+ /// Should be called in the opposite order of the matching [_checkCycle]
+ /// calls.
+ void _removeSeen(object) {
+ assert(_seen.isNotEmpty);
+ assert(identical(_seen.last, object));
+ _seen.removeLast();
+ }
+
+ /// Write an object.
+ ///
+ /// If [object] isn't directly encodable, the [_toEncodable] function gets one
+ /// chance to return a replacement which is encodable.
+ void writeObject(object) {
+ // Tries stringifying object directly. If it's not a simple value, List or
+ // Map, call toJson() to get a custom representation and try serializing
+ // that.
+ if (writeJsonValue(object)) return;
+ _checkCycle(object);
+ try {
+ var customJson = _toEncodable(object);
+ if (!writeJsonValue(customJson)) {
+ throw JsonUnsupportedObjectError(object, partialResult: _partialResult);
+ }
+ _removeSeen(object);
+ } catch (e) {
+ throw JsonUnsupportedObjectError(object,
+ cause: e, partialResult: _partialResult);
+ }
+ }
+
+ /// Serialize a [num], [String], [bool], [Null], [List] or [Map] value.
+ ///
+ /// Returns true if the value is one of these types, and false if not.
+ /// If a value is both a [List] and a [Map], it's serialized as a [List].
+ bool writeJsonValue(object) {
+ if (object is num) {
+ if (!object.isFinite) return false;
+ writeNumber(object);
+ return true;
+ } else if (identical(object, true)) {
+ writeString('true');
+ return true;
+ } else if (identical(object, false)) {
+ writeString('false');
+ return true;
+ } else if (object == null) {
+ writeString('null');
+ return true;
+ } else if (object is String) {
+ writeString('"');
+ writeStringContent(object);
+ writeString('"');
+ return true;
+ } else if (object is List) {
+ _checkCycle(object);
+ writeList(object);
+ _removeSeen(object);
+ return true;
+ } else if (object is Map) {
+ _checkCycle(object);
+ // writeMap can fail if keys are not all strings.
+ var success = writeMap(object);
+ _removeSeen(object);
+ return success;
+ } else {
+ return false;
+ }
+ }
+
+ /// Serialize a [List].
+ void writeList(List list) {
+ writeString('[');
+ if (list.isNotEmpty) {
+ writeObject(list[0]);
+ for (var i = 1; i < list.length; i++) {
+ writeString(',');
+ writeObject(list[i]);
+ }
+ }
+ writeString(']');
+ }
+
+ /// Serialize a [Map].
+ bool writeMap(Map map) {
+ if (map.isEmpty) {
+ writeString("{}");
+ return true;
+ }
+ var keyValueList = List(map.length * 2);
+ var i = 0;
+ var allStringKeys = true;
+ map.forEach((key, value) {
+ if (key is! String) {
+ allStringKeys = false;
+ }
+ keyValueList[i++] = key;
+ keyValueList[i++] = value;
+ });
+ if (!allStringKeys) return false;
+ writeString('{');
+ var separator = '"';
+ for (var i = 0; i < keyValueList.length; i += 2) {
+ writeString(separator);
+ separator = ',"';
+ writeStringContent(keyValueList[i]);
+ writeString('":');
+ writeObject(keyValueList[i + 1]);
+ }
+ writeString('}');
+ return true;
+ }
+}
+
+/// A modification of [_JsonStringifier] which indents the contents of [List] and
+/// [Map] objects using the specified indent value.
+///
+/// Subclasses should implement [writeIndentation].
+abstract class _JsonPrettyPrintMixin implements _JsonStringifier {
+ int _indentLevel = 0;
+
+ /// Add [indentLevel] indentations to the JSON output.
+ void writeIndentation(int indentLevel);
+
+ void writeList(List list) {
+ if (list.isEmpty) {
+ writeString('[]');
+ } else {
+ writeString('[\n');
+ _indentLevel++;
+ writeIndentation(_indentLevel);
+ writeObject(list[0]);
+ for (var i = 1; i < list.length; i++) {
+ writeString(',\n');
+ writeIndentation(_indentLevel);
+ writeObject(list[i]);
+ }
+ writeString('\n');
+ _indentLevel--;
+ writeIndentation(_indentLevel);
+ writeString(']');
+ }
+ }
+
+ bool writeMap(Map map) {
+ if (map.isEmpty) {
+ writeString("{}");
+ return true;
+ }
+ var keyValueList = List(map.length * 2);
+ var i = 0;
+ var allStringKeys = true;
+ map.forEach((key, value) {
+ if (key is! String) {
+ allStringKeys = false;
+ }
+ keyValueList[i++] = key;
+ keyValueList[i++] = value;
+ });
+ if (!allStringKeys) return false;
+ writeString('{\n');
+ _indentLevel++;
+ var separator = "";
+ for (var i = 0; i < keyValueList.length; i += 2) {
+ writeString(separator);
+ separator = ",\n";
+ writeIndentation(_indentLevel);
+ writeString('"');
+ writeStringContent(keyValueList[i]);
+ writeString('": ');
+ writeObject(keyValueList[i + 1]);
+ }
+ writeString('\n');
+ _indentLevel--;
+ writeIndentation(_indentLevel);
+ writeString('}');
+ return true;
+ }
+}
+
+/// A specialization of [_JsonStringifier] that writes its JSON to a string.
+class _JsonStringStringifier extends _JsonStringifier {
+ final StringSink _sink;
+
+ _JsonStringStringifier(this._sink, dynamic Function(dynamic) _toEncodable)
+ : super(_toEncodable);
+
+ /// Convert object to a string.
+ ///
+ /// The [toEncodable] function is used to convert non-encodable objects
+ /// to encodable ones.
+ ///
+ /// If [indent] is not `null`, the resulting JSON will be "pretty-printed"
+ /// with newlines and indentation. The `indent` string is added as indentation
+ /// for each indentation level. It should only contain valid JSON whitespace
+ /// characters (space, tab, carriage return or line feed).
+ static String stringify(object, toEncodable(o), String indent) {
+ var output = StringBuffer();
+ printOn(object, output, toEncodable, indent);
+ return output.toString();
+ }
+
+ /// Convert object to a string, and write the result to the [output] sink.
+ ///
+ /// The result is written piecemally to the sink.
+ static void printOn(
+ object, StringSink output, toEncodable(o), String indent) {
+ _JsonStringifier stringifier;
+ if (indent == null) {
+ stringifier = _JsonStringStringifier(output, toEncodable);
+ } else {
+ stringifier = _JsonStringStringifierPretty(output, toEncodable, indent);
+ }
+ stringifier.writeObject(object);
+ }
+
+ String get _partialResult => _sink is StringBuffer ? _sink.toString() : null;
+
+ void writeNumber(num number) {
+ _sink.write(number.toString());
+ }
+
+ void writeString(String string) {
+ _sink.write(string);
+ }
+
+ void writeStringSlice(String string, int start, int end) {
+ _sink.write(string.substring(start, end));
+ }
+
+ void writeCharCode(int charCode) {
+ _sink.writeCharCode(charCode);
+ }
+}
+
+class _JsonStringStringifierPretty extends _JsonStringStringifier
+ with _JsonPrettyPrintMixin {
+ final String _indent;
+
+ _JsonStringStringifierPretty(StringSink sink, toEncodable(o), this._indent)
+ : super(sink, toEncodable);
+
+ void writeIndentation(int count) {
+ for (var i = 0; i < count; i++) writeString(_indent);
+ }
+}
+
+/// Specialization of [_JsonStringifier] that writes the JSON as UTF-8.
+///
+/// The JSON text is UTF-8 encoded and written to [Uint8List] buffers.
+/// The buffers are then passed back to a user provided callback method.
+class _JsonUtf8Stringifier extends _JsonStringifier {
+ final int bufferSize;
+ final void Function(Uint8List list, int start, int end) addChunk;
+ Uint8List buffer;
+ int index = 0;
+
+ _JsonUtf8Stringifier(toEncodable(o), this.bufferSize, this.addChunk)
+ : buffer = Uint8List(bufferSize),
+ super(toEncodable);
+
+ /// Convert [object] to UTF-8 encoded JSON.
+ ///
+ /// Calls [addChunk] with slices of UTF-8 code units.
+ /// These will typically have size [bufferSize], but may be shorter.
+ /// The buffers are not reused, so the [addChunk] call may keep and reuse the
+ /// chunks.
+ ///
+ /// If [indent] is non-`null`, the result will be "pretty-printed" with extra
+ /// newlines and indentation, using [indent] as the indentation.
+ static void stringify(Object object, List<int> indent, toEncodable(o),
+ int bufferSize, void addChunk(Uint8List chunk, int start, int end)) {
+ _JsonUtf8Stringifier stringifier;
+ if (indent != null) {
+ stringifier =
+ _JsonUtf8StringifierPretty(toEncodable, indent, bufferSize, addChunk);
+ } else {
+ stringifier = _JsonUtf8Stringifier(toEncodable, bufferSize, addChunk);
+ }
+ stringifier.writeObject(object);
+ stringifier.flush();
+ }
+
+ /// Must be called at the end to push the last chunk to the [addChunk]
+ /// callback.
+ void flush() {
+ if (index > 0) {
+ addChunk(buffer, 0, index);
+ }
+ buffer = null;
+ index = 0;
+ }
+
+ String get _partialResult => null;
+
+ void writeNumber(num number) {
+ writeAsciiString(number.toString());
+ }
+
+ /// Write a string that is known to not have non-ASCII characters.
+ void writeAsciiString(String string) {
+ // TODO(lrn): Optimize by copying directly into buffer instead of going
+ // through writeCharCode;
+ for (var i = 0; i < string.length; i++) {
+ var char = string.codeUnitAt(i);
+ assert(char <= 0x7f);
+ writeByte(char);
+ }
+ }
+
+ void writeString(String string) {
+ writeStringSlice(string, 0, string.length);
+ }
+
+ void writeStringSlice(String string, int start, int end) {
+ // TODO(lrn): Optimize by copying directly into buffer instead of going
+ // through writeCharCode/writeByte. Assumption is the most characters
+ // in starings are plain ASCII.
+ for (var i = start; i < end; i++) {
+ var char = string.codeUnitAt(i);
+ if (char <= 0x7f) {
+ writeByte(char);
+ } else {
+ if ((char & 0xFC00) == 0xD800 && i + 1 < end) {
+ // Lead surrogate.
+ var nextChar = string.codeUnitAt(i + 1);
+ if ((nextChar & 0xFC00) == 0xDC00) {
+ // Tail surrogate.
+ char = 0x10000 + ((char & 0x3ff) << 10) + (nextChar & 0x3ff);
+ writeFourByteCharCode(char);
+ i++;
+ continue;
+ }
+ }
+ writeMultiByteCharCode(char);
+ }
+ }
+ }
+
+ void writeCharCode(int charCode) {
+ if (charCode <= 0x7f) {
+ writeByte(charCode);
+ return;
+ }
+ writeMultiByteCharCode(charCode);
+ }
+
+ void writeMultiByteCharCode(int charCode) {
+ if (charCode <= 0x7ff) {
+ writeByte(0xC0 | (charCode >> 6));
+ writeByte(0x80 | (charCode & 0x3f));
+ return;
+ }
+ if (charCode <= 0xffff) {
+ writeByte(0xE0 | (charCode >> 12));
+ writeByte(0x80 | ((charCode >> 6) & 0x3f));
+ writeByte(0x80 | (charCode & 0x3f));
+ return;
+ }
+ writeFourByteCharCode(charCode);
+ }
+
+ void writeFourByteCharCode(int charCode) {
+ assert(charCode <= 0x10ffff);
+ writeByte(0xF0 | (charCode >> 18));
+ writeByte(0x80 | ((charCode >> 12) & 0x3f));
+ writeByte(0x80 | ((charCode >> 6) & 0x3f));
+ writeByte(0x80 | (charCode & 0x3f));
+ }
+
+ void writeByte(int byte) {
+ assert(byte <= 0xff);
+ if (index == buffer.length) {
+ addChunk(buffer, 0, index);
+ buffer = Uint8List(bufferSize);
+ index = 0;
+ }
+ buffer[index++] = byte;
+ }
+}
+
+/// Pretty-printing version of [_JsonUtf8Stringifier].
+class _JsonUtf8StringifierPretty extends _JsonUtf8Stringifier
+ with _JsonPrettyPrintMixin {
+ final List<int> indent;
+ _JsonUtf8StringifierPretty(toEncodable(o), this.indent, int bufferSize,
+ void addChunk(Uint8List buffer, int start, int end))
+ : super(toEncodable, bufferSize, addChunk);
+
+ void writeIndentation(int count) {
+ var indent = this.indent;
+ var indentLength = indent.length;
+ if (indentLength == 1) {
+ var char = indent[0];
+ while (count > 0) {
+ writeByte(char);
+ count -= 1;
+ }
+ return;
+ }
+ while (count > 0) {
+ count--;
+ var end = index + indentLength;
+ if (end <= buffer.length) {
+ buffer.setRange(index, end, indent);
+ index = end;
+ } else {
+ for (var i = 0; i < indentLength; i++) {
+ writeByte(indent[i]);
+ }
+ }
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/convert/latin1.dart b/sdk_nnbd/lib/convert/latin1.dart
new file mode 100644
index 0000000..c22010c
--- /dev/null
+++ b/sdk_nnbd/lib/convert/latin1.dart
@@ -0,0 +1,182 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// An instance of the default implementation of the [Latin1Codec].
+///
+/// This instance provides a convenient access to the most common ISO Latin 1
+/// use cases.
+///
+/// Examples:
+/// ```dart
+/// var encoded = latin1.encode("blåbærgrød");
+/// var decoded = latin1.decode([0x62, 0x6c, 0xe5, 0x62, 0xe6,
+/// 0x72, 0x67, 0x72, 0xf8, 0x64]);
+/// ```
+const Latin1Codec latin1 = Latin1Codec();
+
+const int _latin1Mask = 0xFF;
+
+/// A [Latin1Codec] encodes strings to ISO Latin-1 (aka ISO-8859-1) bytes
+/// and decodes Latin-1 bytes to strings.
+class Latin1Codec extends Encoding {
+ final bool _allowInvalid;
+
+ /// Instantiates a new [Latin1Codec].
+ ///
+ /// If [allowInvalid] is true, the [decode] method and the converter
+ /// returned by [decoder] will default to allowing invalid values. Invalid
+ /// values are decoded into the Unicode Replacement character (U+FFFD).
+ /// Calls to the [decode] method can override this default.
+ ///
+ /// Encoders will not accept invalid (non Latin-1) characters.
+ const Latin1Codec({bool allowInvalid = false}) : _allowInvalid = allowInvalid;
+
+ /// The name of this codec, "iso-8859-1".
+ String get name => "iso-8859-1";
+
+ Uint8List encode(String source) => encoder.convert(source);
+
+ /// Decodes the Latin-1 [bytes] (a list of unsigned 8-bit integers) to the
+ /// corresponding string.
+ ///
+ /// If [bytes] contains values that are not in the range 0 .. 255, the decoder
+ /// will eventually throw a [FormatException].
+ ///
+ /// If [allowInvalid] is not provided, it defaults to the value used to create
+ /// this [Latin1Codec].
+ String decode(List<int> bytes, {bool allowInvalid}) {
+ allowInvalid ??= _allowInvalid;
+ if (allowInvalid) {
+ return const Latin1Decoder(allowInvalid: true).convert(bytes);
+ } else {
+ return const Latin1Decoder(allowInvalid: false).convert(bytes);
+ }
+ }
+
+ Latin1Encoder get encoder => const Latin1Encoder();
+
+ Latin1Decoder get decoder => _allowInvalid
+ ? const Latin1Decoder(allowInvalid: true)
+ : const Latin1Decoder(allowInvalid: false);
+}
+
+/// This class converts strings of only ISO Latin-1 characters to bytes.
+class Latin1Encoder extends _UnicodeSubsetEncoder {
+ const Latin1Encoder() : super(_latin1Mask);
+}
+
+/// This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
+/// to a string.
+class Latin1Decoder extends _UnicodeSubsetDecoder {
+ /// Instantiates a new [Latin1Decoder].
+ ///
+ /// The optional [allowInvalid] argument defines how [convert] deals
+ /// with invalid bytes.
+ ///
+ /// If it is `true`, [convert] replaces invalid bytes with the Unicode
+ /// Replacement character `U+FFFD` (�).
+ /// Otherwise it throws a [FormatException].
+ const Latin1Decoder({bool allowInvalid = false})
+ : super(allowInvalid, _latin1Mask);
+
+ /// Starts a chunked conversion.
+ ///
+ /// The converter works more efficiently if the given [sink] is a
+ /// [StringConversionSink].
+ ByteConversionSink startChunkedConversion(Sink<String> sink) {
+ StringConversionSink stringSink;
+ if (sink is StringConversionSink) {
+ stringSink = sink;
+ } else {
+ stringSink = StringConversionSink.from(sink);
+ }
+ // TODO(lrn): Use stringSink.asUtf16Sink() if it becomes available.
+ if (!_allowInvalid) return _Latin1DecoderSink(stringSink);
+ return _Latin1AllowInvalidDecoderSink(stringSink);
+ }
+}
+
+class _Latin1DecoderSink extends ByteConversionSinkBase {
+ StringConversionSink _sink;
+ _Latin1DecoderSink(this._sink);
+
+ void close() {
+ _sink.close();
+ _sink = null;
+ }
+
+ void add(List<int> source) {
+ addSlice(source, 0, source.length, false);
+ }
+
+ void _addSliceToSink(List<int> source, int start, int end, bool isLast) {
+ // If _sink was a UTF-16 conversion sink, just add the slice directly with
+ // _sink.addSlice(source, start, end, isLast).
+ // The code below is an moderately stupid workaround until a real
+ // solution can be made.
+ _sink.add(String.fromCharCodes(source, start, end));
+ if (isLast) close();
+ }
+
+ void addSlice(List<int> source, int start, int end, bool isLast) {
+ end = RangeError.checkValidRange(start, end, source.length);
+ if (start == end) return;
+ if (source is! Uint8List) {
+ // List may contain value outside of the 0..255 range. If so, throw.
+ // Technically, we could excuse Uint8ClampedList as well, but it unlikely
+ // to be relevant.
+ _checkValidLatin1(source, start, end);
+ }
+ _addSliceToSink(source, start, end, isLast);
+ }
+
+ static void _checkValidLatin1(List<int> source, int start, int end) {
+ var mask = 0;
+ for (var i = start; i < end; i++) {
+ mask |= source[i];
+ }
+ if (mask >= 0 && mask <= _latin1Mask) {
+ return;
+ }
+ _reportInvalidLatin1(source, start, end); // Always throws.
+ }
+
+ static void _reportInvalidLatin1(List<int> source, int start, int end) {
+ // Find the index of the first non-Latin-1 character code.
+ for (var i = start; i < end; i++) {
+ var char = source[i];
+ if (char < 0 || char > _latin1Mask) {
+ throw FormatException(
+ "Source contains non-Latin-1 characters.", source, i);
+ }
+ }
+ // Unreachable - we only call the function if the loop above throws.
+ assert(false);
+ }
+}
+
+class _Latin1AllowInvalidDecoderSink extends _Latin1DecoderSink {
+ _Latin1AllowInvalidDecoderSink(StringConversionSink sink) : super(sink);
+
+ void addSlice(List<int> source, int start, int end, bool isLast) {
+ RangeError.checkValidRange(start, end, source.length);
+ for (var i = start; i < end; i++) {
+ var char = source[i];
+ if (char > _latin1Mask || char < 0) {
+ if (i > start) _addSliceToSink(source, start, i, false);
+ // Add UTF-8 encoding of U+FFFD.
+ _addSliceToSink(const [0xFFFD], 0, 1, false);
+ start = i + 1;
+ }
+ }
+ if (start < end) {
+ _addSliceToSink(source, start, end, isLast);
+ }
+ if (isLast) {
+ close();
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/convert/line_splitter.dart b/sdk_nnbd/lib/convert/line_splitter.dart
new file mode 100644
index 0000000..71be2c0
--- /dev/null
+++ b/sdk_nnbd/lib/convert/line_splitter.dart
@@ -0,0 +1,172 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+// Character constants.
+const int _LF = 10;
+const int _CR = 13;
+
+/// A [StreamTransformer] that splits a [String] into individual lines.
+///
+/// A line is terminated by either a CR (U+000D), a LF (U+000A), a
+/// CR+LF sequence (DOS line ending),
+/// and a final non-empty line can be ended by the end of the string.
+///
+/// The returned lines do not contain the line terminators.
+
+class LineSplitter extends StreamTransformerBase<String, String> {
+ const LineSplitter();
+
+ /// Split [lines] into individual lines.
+ ///
+ /// If [start] and [end] are provided, only split the contents of
+ /// `lines.substring(start, end)`. The [start] and [end] values must
+ /// specify a valid sub-range of [lines]
+ /// (`0 <= start <= end <= lines.length`).
+ static Iterable<String> split(String lines, [int start = 0, int end]) sync* {
+ end = RangeError.checkValidRange(start, end, lines.length);
+ var sliceStart = start;
+ var char = 0;
+ for (var i = start; i < end; i++) {
+ var previousChar = char;
+ char = lines.codeUnitAt(i);
+ if (char != _CR) {
+ if (char != _LF) continue;
+ if (previousChar == _CR) {
+ sliceStart = i + 1;
+ continue;
+ }
+ }
+ yield lines.substring(sliceStart, i);
+ sliceStart = i + 1;
+ }
+ if (sliceStart < end) {
+ yield lines.substring(sliceStart, end);
+ }
+ }
+
+ List<String> convert(String data) {
+ var lines = <String>[];
+ var end = data.length;
+ var sliceStart = 0;
+ var char = 0;
+ for (var i = 0; i < end; i++) {
+ var previousChar = char;
+ char = data.codeUnitAt(i);
+ if (char != _CR) {
+ if (char != _LF) continue;
+ if (previousChar == _CR) {
+ sliceStart = i + 1;
+ continue;
+ }
+ }
+ lines.add(data.substring(sliceStart, i));
+ sliceStart = i + 1;
+ }
+ if (sliceStart < end) {
+ lines.add(data.substring(sliceStart, end));
+ }
+ return lines;
+ }
+
+ StringConversionSink startChunkedConversion(Sink<String> sink) {
+ return _LineSplitterSink(
+ sink is StringConversionSink ? sink : StringConversionSink.from(sink));
+ }
+
+ Stream<String> bind(Stream<String> stream) {
+ return Stream<String>.eventTransformed(
+ stream, (EventSink<String> sink) => _LineSplitterEventSink(sink));
+ }
+}
+
+// TODO(floitsch): deal with utf8.
+class _LineSplitterSink extends StringConversionSinkBase {
+ final StringConversionSink _sink;
+
+ /// The carry-over from the previous chunk.
+ ///
+ /// If the previous slice ended in a line without a line terminator,
+ /// then the next slice may continue the line.
+ String _carry;
+
+ /// Whether to skip a leading LF character from the next slice.
+ ///
+ /// If the previous slice ended on a CR character, a following LF
+ /// would be part of the same line termination, and should be ignored.
+ ///
+ /// Only `true` when [_carry] is `null`.
+ bool _skipLeadingLF = false;
+
+ _LineSplitterSink(this._sink);
+
+ void addSlice(String chunk, int start, int end, bool isLast) {
+ end = RangeError.checkValidRange(start, end, chunk.length);
+ // If the chunk is empty, it's probably because it's the last one.
+ // Handle that here, so we know the range is non-empty below.
+ if (start >= end) {
+ if (isLast) close();
+ return;
+ }
+ if (_carry != null) {
+ assert(!_skipLeadingLF);
+ chunk = _carry + chunk.substring(start, end);
+ start = 0;
+ end = chunk.length;
+ _carry = null;
+ } else if (_skipLeadingLF) {
+ if (chunk.codeUnitAt(start) == _LF) {
+ start += 1;
+ }
+ _skipLeadingLF = false;
+ }
+ _addLines(chunk, start, end);
+ if (isLast) close();
+ }
+
+ void close() {
+ if (_carry != null) {
+ _sink.add(_carry);
+ _carry = null;
+ }
+ _sink.close();
+ }
+
+ void _addLines(String lines, int start, int end) {
+ var sliceStart = start;
+ var char = 0;
+ for (var i = start; i < end; i++) {
+ var previousChar = char;
+ char = lines.codeUnitAt(i);
+ if (char != _CR) {
+ if (char != _LF) continue;
+ if (previousChar == _CR) {
+ sliceStart = i + 1;
+ continue;
+ }
+ }
+ _sink.add(lines.substring(sliceStart, i));
+ sliceStart = i + 1;
+ }
+ if (sliceStart < end) {
+ _carry = lines.substring(sliceStart, end);
+ } else {
+ _skipLeadingLF = (char == _CR);
+ }
+ }
+}
+
+class _LineSplitterEventSink extends _LineSplitterSink
+ implements EventSink<String> {
+ final EventSink<String> _eventSink;
+
+ _LineSplitterEventSink(EventSink<String> eventSink)
+ : _eventSink = eventSink,
+ super(StringConversionSink.from(eventSink));
+
+ void addError(Object o, [StackTrace stackTrace]) {
+ _eventSink.addError(o, stackTrace);
+ }
+}
diff --git a/sdk_nnbd/lib/convert/string_conversion.dart b/sdk_nnbd/lib/convert/string_conversion.dart
new file mode 100644
index 0000000..81e5621
--- /dev/null
+++ b/sdk_nnbd/lib/convert/string_conversion.dart
@@ -0,0 +1,318 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// This class provides an interface for converters to
+/// efficiently transmit String data.
+///
+/// Instead of limiting the interface to one non-chunked String it accepts
+/// partial strings or can be transformed into a byte sink that
+/// accepts UTF-8 code units.
+///
+/// This abstract class will likely get more methods over time. Implementers are
+/// urged to extend [StringConversionSinkBase] or to mix in
+/// [StringConversionSinkMixin], to ensure that their class covers the newly
+/// added methods.
+abstract class StringConversionSink extends ChunkedConversionSink<String> {
+ StringConversionSink();
+ factory StringConversionSink.withCallback(void callback(String accumulated)) =
+ _StringCallbackSink;
+ factory StringConversionSink.from(Sink<String> sink) = _StringAdapterSink;
+
+ /// Creates a new instance wrapping the given [sink].
+ ///
+ /// Every string that is added to the returned instance is forwarded to
+ /// the [sink]. The instance is allowed to buffer and is not required to
+ /// forward immediately.
+ factory StringConversionSink.fromStringSink(StringSink sink) =
+ _StringSinkConversionSink<StringSink>;
+
+ /// Adds the next [chunk] to `this`.
+ ///
+ /// Adds the substring defined by [start] and [end]-exclusive to `this`.
+ ///
+ /// If [isLast] is `true` closes `this`.
+ void addSlice(String chunk, int start, int end, bool isLast);
+
+ /// Returns `this` as a sink that accepts UTF-8 input.
+ ///
+ /// If used, this method must be the first and only call to `this`. It
+ /// invalidates `this`. All further operations must be performed on the result.
+ ByteConversionSink asUtf8Sink(bool allowMalformed);
+ // - asRuneSink
+ // - asCodeUnitsSink
+
+ /// Returns `this` as a [ClosableStringSink].
+ ///
+ /// If used, this method must be the first and only call to `this`. It
+ /// invalidates `this`. All further operations must be performed on the result.
+ ClosableStringSink asStringSink();
+}
+
+/// A [ClosableStringSink] extends the [StringSink] interface by adding a
+/// `close` method.
+abstract class ClosableStringSink extends StringSink {
+ /// Creates a new instance combining a [StringSink] [sink] and a callback
+ /// [onClose] which is invoked when the returned instance is closed.
+ factory ClosableStringSink.fromStringSink(StringSink sink, void onClose()) =
+ _ClosableStringSink;
+
+ /// Closes `this` and flushes any outstanding data.
+ void close();
+}
+
+/// This class wraps an existing [StringSink] and invokes a
+/// closure when [close] is invoked.
+class _ClosableStringSink implements ClosableStringSink {
+ final void Function() _callback;
+ final StringSink _sink;
+
+ _ClosableStringSink(this._sink, this._callback);
+
+ void close() {
+ _callback();
+ }
+
+ void writeCharCode(int charCode) {
+ _sink.writeCharCode(charCode);
+ }
+
+ void write(Object o) {
+ _sink.write(o);
+ }
+
+ void writeln([Object o = ""]) {
+ _sink.writeln(o);
+ }
+
+ void writeAll(Iterable objects, [String separator = ""]) {
+ _sink.writeAll(objects, separator);
+ }
+}
+
+/// This class wraps an existing [StringConversionSink] and exposes a
+/// [ClosableStringSink] interface. The wrapped sink only needs to implement
+/// `add` and `close`.
+// TODO(floitsch): make this class public?
+class _StringConversionSinkAsStringSinkAdapter implements ClosableStringSink {
+ static const _MIN_STRING_SIZE = 16;
+
+ StringBuffer _buffer;
+ StringConversionSink _chunkedSink;
+
+ _StringConversionSinkAsStringSinkAdapter(this._chunkedSink)
+ : _buffer = StringBuffer();
+
+ void close() {
+ if (_buffer.isNotEmpty) _flush();
+ _chunkedSink.close();
+ }
+
+ void writeCharCode(int charCode) {
+ _buffer.writeCharCode(charCode);
+ if (_buffer.length > _MIN_STRING_SIZE) _flush();
+ }
+
+ void write(Object o) {
+ if (_buffer.isNotEmpty) _flush();
+ _chunkedSink.add(o.toString());
+ }
+
+ void writeln([Object o = ""]) {
+ _buffer.writeln(o);
+ if (_buffer.length > _MIN_STRING_SIZE) _flush();
+ }
+
+ void writeAll(Iterable objects, [String separator = ""]) {
+ if (_buffer.isNotEmpty) _flush();
+ var iterator = objects.iterator;
+ if (!iterator.moveNext()) return;
+ if (separator.isEmpty) {
+ do {
+ _chunkedSink.add(iterator.current.toString());
+ } while (iterator.moveNext());
+ } else {
+ _chunkedSink.add(iterator.current.toString());
+ while (iterator.moveNext()) {
+ write(separator);
+ _chunkedSink.add(iterator.current.toString());
+ }
+ }
+ }
+
+ void _flush() {
+ var accumulated = _buffer.toString();
+ _buffer.clear();
+ _chunkedSink.add(accumulated);
+ }
+}
+
+/// This class provides a base-class for converters that need to accept String
+/// inputs.
+abstract class StringConversionSinkBase extends StringConversionSinkMixin {}
+
+/// This class provides a mixin for converters that need to accept String
+/// inputs.
+abstract class StringConversionSinkMixin implements StringConversionSink {
+ void addSlice(String str, int start, int end, bool isLast);
+ void close();
+
+ void add(String str) {
+ addSlice(str, 0, str.length, false);
+ }
+
+ ByteConversionSink asUtf8Sink(bool allowMalformed) {
+ return _Utf8ConversionSink(this, allowMalformed);
+ }
+
+ ClosableStringSink asStringSink() {
+ return _StringConversionSinkAsStringSinkAdapter(this);
+ }
+}
+
+/// This class is a [StringConversionSink] that wraps a [StringSink].
+class _StringSinkConversionSink<TStringSink extends StringSink>
+ extends StringConversionSinkBase {
+ TStringSink _stringSink;
+ _StringSinkConversionSink(this._stringSink);
+
+ void close() {}
+ void addSlice(String str, int start, int end, bool isLast) {
+ if (start != 0 || end != str.length) {
+ for (var i = start; i < end; i++) {
+ _stringSink.writeCharCode(str.codeUnitAt(i));
+ }
+ } else {
+ _stringSink.write(str);
+ }
+ if (isLast) close();
+ }
+
+ void add(String str) {
+ _stringSink.write(str);
+ }
+
+ ByteConversionSink asUtf8Sink(bool allowMalformed) {
+ return _Utf8StringSinkAdapter(this, _stringSink, allowMalformed);
+ }
+
+ ClosableStringSink asStringSink() {
+ return ClosableStringSink.fromStringSink(_stringSink, close);
+ }
+}
+
+/// This class accumulates all chunks into one string
+/// and invokes a callback when the sink is closed.
+///
+/// This class can be used to terminate a chunked conversion.
+class _StringCallbackSink extends _StringSinkConversionSink<StringBuffer> {
+ final void Function(String) _callback;
+ _StringCallbackSink(this._callback) : super(StringBuffer());
+
+ void close() {
+ var accumulated = _stringSink.toString();
+ _stringSink.clear();
+ _callback(accumulated);
+ }
+
+ ByteConversionSink asUtf8Sink(bool allowMalformed) {
+ return _Utf8StringSinkAdapter(this, _stringSink, allowMalformed);
+ }
+}
+
+/// This class adapts a simple [ChunkedConversionSink] to a
+/// [StringConversionSink].
+///
+/// All additional methods of the [StringConversionSink] (compared to the
+/// ChunkedConversionSink) are redirected to the `add` method.
+class _StringAdapterSink extends StringConversionSinkBase {
+ final Sink<String> _sink;
+
+ _StringAdapterSink(this._sink);
+
+ void add(String str) {
+ _sink.add(str);
+ }
+
+ void addSlice(String str, int start, int end, bool isLast) {
+ if (start == 0 && end == str.length) {
+ add(str);
+ } else {
+ add(str.substring(start, end));
+ }
+ if (isLast) close();
+ }
+
+ void close() {
+ _sink.close();
+ }
+}
+
+/// Decodes UTF-8 code units and stores them in a [StringSink].
+class _Utf8StringSinkAdapter extends ByteConversionSink {
+ final _Utf8Decoder _decoder;
+ final Sink _sink;
+
+ _Utf8StringSinkAdapter(this._sink, StringSink stringSink, bool allowMalformed)
+ : _decoder = _Utf8Decoder(stringSink, allowMalformed);
+
+ void close() {
+ _decoder.close();
+ if (_sink != null) _sink.close();
+ }
+
+ void add(List<int> chunk) {
+ addSlice(chunk, 0, chunk.length, false);
+ }
+
+ void addSlice(
+ List<int> codeUnits, int startIndex, int endIndex, bool isLast) {
+ _decoder.convert(codeUnits, startIndex, endIndex);
+ if (isLast) close();
+ }
+}
+
+/// Decodes UTF-8 code units.
+///
+/// Forwards the decoded strings to the given [StringConversionSink].
+// TODO(floitsch): make this class public?
+class _Utf8ConversionSink extends ByteConversionSink {
+ final _Utf8Decoder _decoder;
+ final StringConversionSink _chunkedSink;
+ final StringBuffer _buffer;
+ _Utf8ConversionSink(StringConversionSink sink, bool allowMalformed)
+ : this._(sink, StringBuffer(), allowMalformed);
+
+ _Utf8ConversionSink._(
+ this._chunkedSink, StringBuffer stringBuffer, bool allowMalformed)
+ : _decoder = _Utf8Decoder(stringBuffer, allowMalformed),
+ _buffer = stringBuffer;
+
+ void close() {
+ _decoder.close();
+ if (_buffer.isNotEmpty) {
+ var accumulated = _buffer.toString();
+ _buffer.clear();
+ _chunkedSink.addSlice(accumulated, 0, accumulated.length, true);
+ } else {
+ _chunkedSink.close();
+ }
+ }
+
+ void add(List<int> chunk) {
+ addSlice(chunk, 0, chunk.length, false);
+ }
+
+ void addSlice(List<int> chunk, int startIndex, int endIndex, bool isLast) {
+ _decoder.convert(chunk, startIndex, endIndex);
+ if (_buffer.isNotEmpty) {
+ var accumulated = _buffer.toString();
+ _chunkedSink.addSlice(accumulated, 0, accumulated.length, isLast);
+ _buffer.clear();
+ return;
+ }
+ if (isLast) close();
+ }
+}
diff --git a/sdk_nnbd/lib/convert/utf.dart b/sdk_nnbd/lib/convert/utf.dart
new file mode 100644
index 0000000..39eb135
--- /dev/null
+++ b/sdk_nnbd/lib/convert/utf.dart
@@ -0,0 +1,556 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/// The Unicode Replacement character `U+FFFD` (�).
+const int unicodeReplacementCharacterRune = 0xFFFD;
+
+/// The Unicode Byte Order Marker (BOM) character `U+FEFF`.
+const int unicodeBomCharacterRune = 0xFEFF;
+
+/// An instance of the default implementation of the [Utf8Codec].
+///
+/// This instance provides a convenient access to the most common UTF-8
+/// use cases.
+///
+/// Examples:
+///
+/// var encoded = utf8.encode("Îñţérñåţîöñåļîžåţîờñ");
+/// var decoded = utf8.decode([0x62, 0x6c, 0xc3, 0xa5, 0x62, 0xc3, 0xa6,
+/// 0x72, 0x67, 0x72, 0xc3, 0xb8, 0x64]);
+const Utf8Codec utf8 = Utf8Codec();
+
+/// A [Utf8Codec] encodes strings to utf-8 code units (bytes) and decodes
+/// UTF-8 code units to strings.
+class Utf8Codec extends Encoding {
+ final bool _allowMalformed;
+
+ /// Instantiates a new [Utf8Codec].
+ ///
+ /// The optional [allowMalformed] argument defines how [decoder] (and [decode])
+ /// deal with invalid or unterminated character sequences.
+ ///
+ /// If it is `true` (and not overridden at the method invocation) [decode] and
+ /// the [decoder] replace invalid (or unterminated) octet
+ /// sequences with the Unicode Replacement character `U+FFFD` (�). Otherwise
+ /// they throw a [FormatException].
+ const Utf8Codec({bool allowMalformed = false})
+ : _allowMalformed = allowMalformed;
+
+ /// The name of this codec, "utf-8".
+ String get name => "utf-8";
+
+ /// Decodes the UTF-8 [codeUnits] (a list of unsigned 8-bit integers) to the
+ /// corresponding string.
+ ///
+ /// If the [codeUnits] start with the encoding of a
+ /// [unicodeBomCharacterRune], that character is discarded.
+ ///
+ /// If [allowMalformed] is `true` the decoder replaces invalid (or
+ /// unterminated) character sequences with the Unicode Replacement character
+ /// `U+FFFD` (�). Otherwise it throws a [FormatException].
+ ///
+ /// If [allowMalformed] is not given, it defaults to the `allowMalformed` that
+ /// was used to instantiate `this`.
+ String decode(List<int> codeUnits, {bool allowMalformed}) {
+ allowMalformed ??= _allowMalformed;
+ return Utf8Decoder(allowMalformed: allowMalformed).convert(codeUnits);
+ }
+
+ Utf8Encoder get encoder => const Utf8Encoder();
+ Utf8Decoder get decoder {
+ return Utf8Decoder(allowMalformed: _allowMalformed);
+ }
+}
+
+/// This class converts strings to their UTF-8 code units (a list of
+/// unsigned 8-bit integers).
+class Utf8Encoder extends Converter<String, List<int>> {
+ const Utf8Encoder();
+
+ /// Converts [string] to its UTF-8 code units (a list of
+ /// unsigned 8-bit integers).
+ ///
+ /// If [start] and [end] are provided, only the substring
+ /// `string.substring(start, end)` is converted.
+ Uint8List convert(String string, [int start = 0, int end]) {
+ var stringLength = string.length;
+ end = RangeError.checkValidRange(start, end, stringLength);
+ var length = end - start;
+ if (length == 0) return Uint8List(0);
+ // Create a new encoder with a length that is guaranteed to be big enough.
+ // A single code unit uses at most 3 bytes, a surrogate pair at most 4.
+ var encoder = _Utf8Encoder.withBufferSize(length * 3);
+ var endPosition = encoder._fillBuffer(string, start, end);
+ assert(endPosition >= end - 1);
+ if (endPosition != end) {
+ // Encoding skipped the last code unit.
+ // That can only happen if the last code unit is a leadsurrogate.
+ // Force encoding of the lead surrogate by itself.
+ var lastCodeUnit = string.codeUnitAt(end - 1);
+ assert(_isLeadSurrogate(lastCodeUnit));
+ // We use a non-surrogate as `nextUnit` so that _writeSurrogate just
+ // writes the lead-surrogate.
+ var wasCombined = encoder._writeSurrogate(lastCodeUnit, 0);
+ assert(!wasCombined);
+ }
+ return encoder._buffer.sublist(0, encoder._bufferIndex);
+ }
+
+ /// Starts a chunked conversion.
+ ///
+ /// The converter works more efficiently if the given [sink] is a
+ /// [ByteConversionSink].
+ StringConversionSink startChunkedConversion(Sink<List<int>> sink) {
+ return _Utf8EncoderSink(
+ sink is ByteConversionSink ? sink : ByteConversionSink.from(sink));
+ }
+
+ // Override the base-classes bind, to provide a better type.
+ Stream<List<int>> bind(Stream<String> stream) => super.bind(stream);
+}
+
+/// This class encodes Strings to UTF-8 code units (unsigned 8 bit integers).
+// TODO(floitsch): make this class public.
+class _Utf8Encoder {
+ int _carry = 0;
+ int _bufferIndex = 0;
+ final Uint8List _buffer;
+
+ static const _DEFAULT_BYTE_BUFFER_SIZE = 1024;
+
+ _Utf8Encoder() : this.withBufferSize(_DEFAULT_BYTE_BUFFER_SIZE);
+
+ _Utf8Encoder.withBufferSize(int bufferSize)
+ : _buffer = _createBuffer(bufferSize);
+
+ /// Allow an implementation to pick the most efficient way of storing bytes.
+ static Uint8List _createBuffer(int size) => Uint8List(size);
+
+ /// Tries to combine the given [leadingSurrogate] with the [nextCodeUnit] and
+ /// writes it to [_buffer].
+ ///
+ /// Returns true if the [nextCodeUnit] was combined with the
+ /// [leadingSurrogate]. If it wasn't then nextCodeUnit was not a trailing
+ /// surrogate and has not been written yet.
+ ///
+ /// It is safe to pass 0 for [nextCodeUnit] in which case only the leading
+ /// surrogate is written.
+ bool _writeSurrogate(int leadingSurrogate, int nextCodeUnit) {
+ if (_isTailSurrogate(nextCodeUnit)) {
+ var rune = _combineSurrogatePair(leadingSurrogate, nextCodeUnit);
+ // If the rune is encoded with 2 code-units then it must be encoded
+ // with 4 bytes in UTF-8.
+ assert(rune > _THREE_BYTE_LIMIT);
+ assert(rune <= _FOUR_BYTE_LIMIT);
+ _buffer[_bufferIndex++] = 0xF0 | (rune >> 18);
+ _buffer[_bufferIndex++] = 0x80 | ((rune >> 12) & 0x3f);
+ _buffer[_bufferIndex++] = 0x80 | ((rune >> 6) & 0x3f);
+ _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f);
+ return true;
+ } else {
+ // TODO(floitsch): allow to throw on malformed strings.
+ // Encode the half-surrogate directly into UTF-8. This yields
+ // invalid UTF-8, but we started out with invalid UTF-16.
+
+ // Surrogates are always encoded in 3 bytes in UTF-8.
+ _buffer[_bufferIndex++] = 0xE0 | (leadingSurrogate >> 12);
+ _buffer[_bufferIndex++] = 0x80 | ((leadingSurrogate >> 6) & 0x3f);
+ _buffer[_bufferIndex++] = 0x80 | (leadingSurrogate & 0x3f);
+ return false;
+ }
+ }
+
+ /// Fills the [_buffer] with as many characters as possible.
+ ///
+ /// Does not encode any trailing lead-surrogate. This must be done by the
+ /// caller.
+ ///
+ /// Returns the position in the string. The returned index points to the
+ /// first code unit that hasn't been encoded.
+ int _fillBuffer(String str, int start, int end) {
+ if (start != end && _isLeadSurrogate(str.codeUnitAt(end - 1))) {
+ // Don't handle a trailing lead-surrogate in this loop. The caller has
+ // to deal with those.
+ end--;
+ }
+ int stringIndex;
+ for (stringIndex = start; stringIndex < end; stringIndex++) {
+ var codeUnit = str.codeUnitAt(stringIndex);
+ // ASCII has the same representation in UTF-8 and UTF-16.
+ if (codeUnit <= _ONE_BYTE_LIMIT) {
+ if (_bufferIndex >= _buffer.length) break;
+ _buffer[_bufferIndex++] = codeUnit;
+ } else if (_isLeadSurrogate(codeUnit)) {
+ if (_bufferIndex + 3 >= _buffer.length) break;
+ // Note that it is safe to read the next code unit. We decremented
+ // [end] above when the last valid code unit was a leading surrogate.
+ var nextCodeUnit = str.codeUnitAt(stringIndex + 1);
+ var wasCombined = _writeSurrogate(codeUnit, nextCodeUnit);
+ if (wasCombined) stringIndex++;
+ } else {
+ var rune = codeUnit;
+ if (rune <= _TWO_BYTE_LIMIT) {
+ if (_bufferIndex + 1 >= _buffer.length) break;
+ _buffer[_bufferIndex++] = 0xC0 | (rune >> 6);
+ _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f);
+ } else {
+ assert(rune <= _THREE_BYTE_LIMIT);
+ if (_bufferIndex + 2 >= _buffer.length) break;
+ _buffer[_bufferIndex++] = 0xE0 | (rune >> 12);
+ _buffer[_bufferIndex++] = 0x80 | ((rune >> 6) & 0x3f);
+ _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f);
+ }
+ }
+ }
+ return stringIndex;
+ }
+}
+
+/// This class encodes chunked strings to UTF-8 code units (unsigned 8-bit
+/// integers).
+class _Utf8EncoderSink extends _Utf8Encoder with StringConversionSinkMixin {
+ final ByteConversionSink _sink;
+
+ _Utf8EncoderSink(this._sink);
+
+ void close() {
+ if (_carry != 0) {
+ // addSlice will call close again, but then the carry must be equal to 0.
+ addSlice("", 0, 0, true);
+ return;
+ }
+ _sink.close();
+ }
+
+ void addSlice(String str, int start, int end, bool isLast) {
+ _bufferIndex = 0;
+
+ if (start == end && !isLast) {
+ return;
+ }
+
+ if (_carry != 0) {
+ var nextCodeUnit = 0;
+ if (start != end) {
+ nextCodeUnit = str.codeUnitAt(start);
+ } else {
+ assert(isLast);
+ }
+ var wasCombined = _writeSurrogate(_carry, nextCodeUnit);
+ // Either we got a non-empty string, or we must not have been combined.
+ assert(!wasCombined || start != end);
+ if (wasCombined) start++;
+ _carry = 0;
+ }
+ do {
+ start = _fillBuffer(str, start, end);
+ var isLastSlice = isLast && (start == end);
+ if (start == end - 1 && _isLeadSurrogate(str.codeUnitAt(start))) {
+ if (isLast && _bufferIndex < _buffer.length - 3) {
+ // There is still space for the last incomplete surrogate.
+ // We use a non-surrogate as second argument. This way the
+ // function will just add the surrogate-half to the buffer.
+ var hasBeenCombined = _writeSurrogate(str.codeUnitAt(start), 0);
+ assert(!hasBeenCombined);
+ } else {
+ // Otherwise store it in the carry. If isLast is true, then
+ // close will flush the last carry.
+ _carry = str.codeUnitAt(start);
+ }
+ start++;
+ }
+ _sink.addSlice(_buffer, 0, _bufferIndex, isLastSlice);
+ _bufferIndex = 0;
+ } while (start < end);
+ if (isLast) close();
+ }
+
+ // TODO(floitsch): implement asUtf8Sink. Sligthly complicated because it
+ // needs to deal with malformed input.
+}
+
+/// This class converts UTF-8 code units (lists of unsigned 8-bit integers)
+/// to a string.
+class Utf8Decoder extends Converter<List<int>, String> {
+ final bool _allowMalformed;
+
+ /// Instantiates a new [Utf8Decoder].
+ ///
+ /// The optional [allowMalformed] argument defines how [convert] deals
+ /// with invalid or unterminated character sequences.
+ ///
+ /// If it is `true` [convert] replaces invalid (or unterminated) character
+ /// sequences with the Unicode Replacement character `U+FFFD` (�). Otherwise
+ /// it throws a [FormatException].
+ const Utf8Decoder({bool allowMalformed = false})
+ : _allowMalformed = allowMalformed;
+
+ /// Converts the UTF-8 [codeUnits] (a list of unsigned 8-bit integers) to the
+ /// corresponding string.
+ ///
+ /// Uses the code units from [start] to, but no including, [end].
+ /// If [end] is omitted, it defaults to `codeUnits.length`.
+ ///
+ /// If the [codeUnits] start with the encoding of a
+ /// [unicodeBomCharacterRune], that character is discarded.
+ String convert(List<int> codeUnits, [int start = 0, int end]) {
+ // Allow the implementation to intercept and specialize based on the type
+ // of codeUnits.
+ var result = _convertIntercepted(_allowMalformed, codeUnits, start, end);
+ if (result != null) {
+ return result;
+ }
+
+ var length = codeUnits.length;
+ end = RangeError.checkValidRange(start, end, length);
+
+ // Fast case for ASCII strings avoids StringBuffer/_Utf8Decoder.
+ int oneBytes = _scanOneByteCharacters(codeUnits, start, end);
+ StringBuffer buffer;
+ bool isFirstCharacter = true;
+ if (oneBytes > 0) {
+ var firstPart = String.fromCharCodes(codeUnits, start, start + oneBytes);
+ start += oneBytes;
+ if (start == end) {
+ return firstPart;
+ }
+ buffer = StringBuffer(firstPart);
+ isFirstCharacter = false;
+ }
+
+ buffer ??= StringBuffer();
+ var decoder = _Utf8Decoder(buffer, _allowMalformed);
+ decoder._isFirstCharacter = isFirstCharacter;
+ decoder.convert(codeUnits, start, end);
+ decoder.flush(codeUnits, end);
+ return buffer.toString();
+ }
+
+ /// Starts a chunked conversion.
+ ///
+ /// The converter works more efficiently if the given [sink] is a
+ /// [StringConversionSink].
+ ByteConversionSink startChunkedConversion(Sink<String> sink) {
+ StringConversionSink stringSink;
+ if (sink is StringConversionSink) {
+ stringSink = sink;
+ } else {
+ stringSink = StringConversionSink.from(sink);
+ }
+ return stringSink.asUtf8Sink(_allowMalformed);
+ }
+
+ // Override the base-classes bind, to provide a better type.
+ Stream<String> bind(Stream<List<int>> stream) => super.bind(stream);
+
+ external Converter<List<int>, T> fuse<T>(Converter<String, T> next);
+
+ external static String _convertIntercepted(
+ bool allowMalformed, List<int> codeUnits, int start, int end);
+}
+
+// UTF-8 constants.
+const int _ONE_BYTE_LIMIT = 0x7f; // 7 bits
+const int _TWO_BYTE_LIMIT = 0x7ff; // 11 bits
+const int _THREE_BYTE_LIMIT = 0xffff; // 16 bits
+const int _FOUR_BYTE_LIMIT = 0x10ffff; // 21 bits, truncated to Unicode max.
+
+// UTF-16 constants.
+const int _SURROGATE_TAG_MASK = 0xFC00;
+const int _SURROGATE_VALUE_MASK = 0x3FF;
+const int _LEAD_SURROGATE_MIN = 0xD800;
+const int _TAIL_SURROGATE_MIN = 0xDC00;
+
+bool _isLeadSurrogate(int codeUnit) =>
+ (codeUnit & _SURROGATE_TAG_MASK) == _LEAD_SURROGATE_MIN;
+bool _isTailSurrogate(int codeUnit) =>
+ (codeUnit & _SURROGATE_TAG_MASK) == _TAIL_SURROGATE_MIN;
+int _combineSurrogatePair(int lead, int tail) =>
+ 0x10000 + ((lead & _SURROGATE_VALUE_MASK) << 10) |
+ (tail & _SURROGATE_VALUE_MASK);
+
+/// Decodes UTF-8.
+///
+/// The decoder handles chunked input.
+// TODO(floitsch): make this class public.
+class _Utf8Decoder {
+ final bool _allowMalformed;
+ final StringSink _stringSink;
+ bool _isFirstCharacter = true;
+ int _value = 0;
+ int _expectedUnits = 0;
+ int _extraUnits = 0;
+
+ _Utf8Decoder(this._stringSink, this._allowMalformed);
+
+ bool get hasPartialInput => _expectedUnits > 0;
+
+ // Limits of one through four byte encodings.
+ static const List<int> _LIMITS = <int>[
+ _ONE_BYTE_LIMIT,
+ _TWO_BYTE_LIMIT,
+ _THREE_BYTE_LIMIT,
+ _FOUR_BYTE_LIMIT
+ ];
+
+ void close() {
+ flush();
+ }
+
+ /// Flushes this decoder as if closed.
+ ///
+ /// This method throws if the input was partial and the decoder was
+ /// constructed with `allowMalformed` set to `false`.
+ ///
+ /// The [source] and [offset] of the current position may be provided,
+ /// and are included in the exception if one is thrown.
+ void flush([List<int> source, int offset]) {
+ if (hasPartialInput) {
+ if (!_allowMalformed) {
+ throw FormatException(
+ "Unfinished UTF-8 octet sequence", source, offset);
+ }
+ _stringSink.writeCharCode(unicodeReplacementCharacterRune);
+ _value = 0;
+ _expectedUnits = 0;
+ _extraUnits = 0;
+ }
+ }
+
+ void convert(List<int> codeUnits, int startIndex, int endIndex) {
+ var value = _value;
+ var expectedUnits = _expectedUnits;
+ var extraUnits = _extraUnits;
+ _value = 0;
+ _expectedUnits = 0;
+ _extraUnits = 0;
+
+ var i = startIndex;
+ loop:
+ while (true) {
+ multibyte:
+ if (expectedUnits > 0) {
+ do {
+ if (i == endIndex) {
+ break loop;
+ }
+ var unit = codeUnits[i];
+ if ((unit & 0xC0) != 0x80) {
+ expectedUnits = 0;
+ if (!_allowMalformed) {
+ throw FormatException(
+ "Bad UTF-8 encoding 0x${unit.toRadixString(16)}",
+ codeUnits,
+ i);
+ }
+ _isFirstCharacter = false;
+ _stringSink.writeCharCode(unicodeReplacementCharacterRune);
+ break multibyte;
+ } else {
+ value = (value << 6) | (unit & 0x3f);
+ expectedUnits--;
+ i++;
+ }
+ } while (expectedUnits > 0);
+ if (value <= _LIMITS[extraUnits - 1]) {
+ // Overly long encoding. The value could be encoded with a shorter
+ // encoding.
+ if (!_allowMalformed) {
+ throw FormatException(
+ "Overlong encoding of 0x${value.toRadixString(16)}",
+ codeUnits,
+ i - extraUnits - 1);
+ }
+ expectedUnits = extraUnits = 0;
+ value = unicodeReplacementCharacterRune;
+ }
+ if (value > _FOUR_BYTE_LIMIT) {
+ if (!_allowMalformed) {
+ throw FormatException(
+ "Character outside valid Unicode range: "
+ "0x${value.toRadixString(16)}",
+ codeUnits,
+ i - extraUnits - 1);
+ }
+ value = unicodeReplacementCharacterRune;
+ }
+ if (!_isFirstCharacter || value != unicodeBomCharacterRune) {
+ _stringSink.writeCharCode(value);
+ }
+ _isFirstCharacter = false;
+ }
+
+ while (i < endIndex) {
+ var oneBytes = _scanOneByteCharacters(codeUnits, i, endIndex);
+ if (oneBytes > 0) {
+ _isFirstCharacter = false;
+ assert(i + oneBytes <= endIndex);
+ _stringSink.write(String.fromCharCodes(codeUnits, i, i + oneBytes));
+
+ i += oneBytes;
+ if (i == endIndex) break;
+ }
+ var unit = codeUnits[i++];
+ // TODO(floitsch): the way we test we could potentially allow
+ // units that are too large, if they happen to have the
+ // right bit-pattern. (Same is true for the multibyte loop above).
+ // TODO(floitsch): optimize this loop. See:
+ // https://codereview.chromium.org/22929022/diff/1/sdk/lib/convert/utf.dart?column_width=80
+ if (unit < 0) {
+ // TODO(floitsch): should this be unit <= 0 ?
+ if (!_allowMalformed) {
+ throw FormatException(
+ "Negative UTF-8 code unit: -0x${(-unit).toRadixString(16)}",
+ codeUnits,
+ i - 1);
+ }
+ _stringSink.writeCharCode(unicodeReplacementCharacterRune);
+ } else {
+ assert(unit > _ONE_BYTE_LIMIT);
+ if ((unit & 0xE0) == 0xC0) {
+ value = unit & 0x1F;
+ expectedUnits = extraUnits = 1;
+ continue loop;
+ }
+ if ((unit & 0xF0) == 0xE0) {
+ value = unit & 0x0F;
+ expectedUnits = extraUnits = 2;
+ continue loop;
+ }
+ // 0xF5, 0xF6 ... 0xFF never appear in valid UTF-8 sequences.
+ if ((unit & 0xF8) == 0xF0 && unit < 0xF5) {
+ value = unit & 0x07;
+ expectedUnits = extraUnits = 3;
+ continue loop;
+ }
+ if (!_allowMalformed) {
+ throw FormatException(
+ "Bad UTF-8 encoding 0x${unit.toRadixString(16)}",
+ codeUnits,
+ i - 1);
+ }
+ value = unicodeReplacementCharacterRune;
+ expectedUnits = extraUnits = 0;
+ _isFirstCharacter = false;
+ _stringSink.writeCharCode(value);
+ }
+ }
+ break loop;
+ }
+ if (expectedUnits > 0) {
+ _value = value;
+ _expectedUnits = expectedUnits;
+ _extraUnits = extraUnits;
+ }
+ }
+}
+
+// Returns the number of bytes in [units] starting at offset [from] which have
+// the leftmost bit set to 0.
+//
+// To increase performance of this critical method we have a special variant of
+// it implemented in the VM's patch files, which is why we make it external.
+external int _scanOneByteCharacters(List<int> units, int from, int endIndex);
diff --git a/sdk_nnbd/lib/core/annotations.dart b/sdk_nnbd/lib/core/annotations.dart
new file mode 100644
index 0000000..2d30f1c
--- /dev/null
+++ b/sdk_nnbd/lib/core/annotations.dart
@@ -0,0 +1,240 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * The annotation `@Deprecated('migration')` marks a feature as deprecated.
+ *
+ * The annotation [deprecated] is a shorthand for deprecating until
+ * an unspecified "next release" without migration instructions.
+ *
+ * The intent of the `@Deprecated` annotation is to inform users of a feature
+ * that they should change their code, even if it is currently still working
+ * correctly.
+ *
+ * A deprecated feature is scheduled to be removed at a later time, possibly
+ * specified in [message]. A deprecated feature should not be used, code using
+ * it will break at some point in the future. If existing code is using the
+ * feature it should be rewritten to not use the deprecated feature.
+ *
+ * A deprecated feature should document how the same effect can be achieved in
+ * [message], so the programmer knows how to rewrite the code.
+ *
+ * The `@Deprecated` annotation applies to libraries, top-level declarations
+ * (variables, getters, setters, functions, classes and typedefs),
+ * class-level declarations (variables, getters, setters, methods, operators or
+ * constructors, whether static or not), named optional arguments and
+ * trailing optional positional parameters.
+ *
+ * Deprecation is transitive:
+ *
+ * - If a library is deprecated, so is every member of it.
+ * - If a class is deprecated, so is every member of it.
+ * - If a variable is deprecated, so are its implicit getter and setter.
+ *
+ *
+ * A tool that processes Dart source code may report when:
+ *
+ * - the code imports a deprecated library.
+ * - the code exports a deprecated library, or any deprecated member of
+ * a non-deprecated library.
+ * - the code refers statically to a deprecated declaration.
+ * - the code dynamically uses a member of an object with a statically known
+ * type, where the member is deprecated on the static type of the object.
+ * - the code dynamically calls a method with an argument where the
+ * corresponding optional parameter is deprecated on the object's static type.
+ *
+ *
+ * If the deprecated use is inside a library, class or method which is itself
+ * deprecated, the tool should not bother the user about it.
+ * A deprecated feature is expected to use other deprecated features.
+ */
+class Deprecated {
+ /**
+ * Message provided to the user when they use the deprecated feature.
+ *
+ * The message should explain how to migrate away from the feature if an
+ * alternative is available, and when the deprecated feature is expected to be
+ * removed.
+ */
+ final String message;
+
+ /**
+ * Create a deprecation annotation which specifies the migration path and
+ * expiration of the annotated feature.
+ *
+ * The [message] argument should be readable by programmers, and should state
+ * an alternative feature (if available) as well as when an annotated feature
+ * is expected to be removed.
+ */
+ const Deprecated(this.message);
+
+ @Deprecated('Use `message` instead. Will be removed in Dart 3.0.0')
+ String get expires => message;
+
+ String toString() => "Deprecated feature: $message";
+}
+
+/**
+ * Marks a feature as [Deprecated] until the next release.
+ */
+const Deprecated deprecated = Deprecated("next release");
+
+class _Override {
+ const _Override();
+}
+
+/**
+ * The annotation `@override` marks an instance member as overriding a
+ * superclass member with the same name.
+ *
+ * The annotation applies to instance methods, getters and setters, and to
+ * instance fields, where it means that the implicit getter and setter of the
+ * field is marked as overriding, but the field itself is not.
+ *
+ * The intent of the `@override` notation is to catch situations where a
+ * superclass renames a member, and an independent subclass which used to
+ * override the member, could silently continue working using the
+ * superclass implementation.
+ *
+ * The editor, or a similar tool aimed at the programmer, may report if no
+ * declaration of an annotated member is inherited by the class from either a
+ * superclass or an interface.
+ *
+ * Use the `@override` annotation judiciously and only for methods where
+ * the superclass is not under the programmer's control, the superclass is in a
+ * different library or package, and it is not considered stable.
+ * In any case, the use of `@override` is optional.
+ *
+ * For example, the annotation is intentionally not used in the Dart platform
+ * libraries, since they only depend on themselves.
+ */
+const Object override = _Override();
+
+/**
+ * An annotation class that was used during development of Dart 2.
+ *
+ * Should not be used any more.
+ */
+@deprecated
+class Provisional {
+ String get message => null;
+ const Provisional({String message});
+}
+
+/**
+ * An annotation that was used during development of Dart 2.
+ *
+ * Should not be used any more.
+ */
+@deprecated
+const Null provisional = null;
+
+class _Proxy {
+ const _Proxy();
+}
+
+/**
+ * This annotation is deprecated and will be removed in Dart 2.
+ *
+ * Dart 2 has a more restrictive type system than Dart 1, and it requires
+ * method access to be either through a known interface or by using
+ * dynamic invocations. The original intent of `@proxy` (to implement a class
+ * that isn't known statically, as documented at the end of this text),
+ * is not supported by Dart 2.
+ * To continue to perform dynamic invocations on an object,
+ * it should be accessed through a reference of type `dynamic`.
+ *
+ * The annotation `@proxy` marks a class as implementing members dynamically
+ * through `noSuchMethod`.
+ *
+ * The annotation applies to any class. It is inherited by subclasses from both
+ * superclass and interfaces.
+ *
+ * If a class is annotated with `@proxy`, or it implements any class that is
+ * annotated, then all member accesses are allowed on an object of that type.
+ * As such, it is not a static type warning to access any member of the object
+ * which is not implemented by the class, or to call a method with a different
+ * number of parameters than it is declared with.
+ *
+ * The annotation does not change which classes the annotated class implements,
+ * and does not prevent static warnings for assigning an object to a variable
+ * with a static type not implemented by the object.
+ *
+ * The suppression of warnings only affect static type warnings about
+ * member access.
+ * The runtime type of the object is unaffected.
+ * It is not considered to implement any special interfaces,
+ * so assigning it to a typed variable may fail in checked mode,
+ * and testing it with the `is` operator
+ * will only return true for types it actually implements or extends.
+ * Accessing a member which isn't implemented by the class
+ * will cause the `noSuchMethod` method to be called normally,
+ * the `@proxy` annotation merely states the intent to handle (some of) those
+ * `noSuchMethod` calls gracefully.
+ *
+ * A class that marked as `@proxy` should override the `noSuchMethod`
+ * declared on [Object].
+ *
+ * The intent of the `@proxy` notation is to create objects that implement a
+ * type (or multiple types) that are not known at compile time. If the types
+ * are known at compile time, a class can be written that implements these
+ * types.
+ */
+@deprecated
+const Object proxy = _Proxy();
+
+/**
+ * A hint to tools.
+ *
+ * Tools that work with Dart programs may accept hints to guide their behavior
+ * as `pragma` annotations on declarations.
+ * Each tool decides which hints it accepts, what they mean, and whether and
+ * how they apply to sub-parts of the annotated entity.
+ *
+ * Tools that recognize pragma hints should pick a pragma prefix to identify
+ * the tool. They should recognize any hint with a [name] starting with their
+ * prefix followed by `:` as if it was intended for that tool. A hint with a
+ * prefix for another tool should be ignored (unless compatibility with that
+ * other tool is a goal).
+ *
+ * A tool may recognize unprefixed names as well, if they would recognize that
+ * name with their own prefix in front.
+ *
+ * If the hint can be parameterized, an extra [options] object can be added as well.
+ *
+ * For example:
+ *
+ * ```dart
+ * @pragma('Tool:pragma-name', [param1, param2, ...])
+ * class Foo { }
+ *
+ * @pragma('OtherTool:other-pragma')
+ * void foo() { }
+ * ```
+ *
+ * Here class Foo is annotated with a Tool specific pragma 'pragma-name' and
+ * function foo is annotated with a pragma 'other-pragma' specific to OtherTool.
+ *
+ */
+@pragma('vm:entry-point')
+class pragma {
+ /**
+ * The name of the hint.
+ *
+ * A string that is recognized by one or more tools, or such a string prefixed
+ * by a tool identifier and a colon, which is only recognized by that
+ * particular tool.
+ */
+ final String name;
+
+ /** Optional extra data parameterizing the hint. */
+ final Object options;
+
+ /** Creates a hint named [name] with optional [options]. */
+ const factory pragma(String name, [Object options]) = pragma._;
+
+ const pragma._(this.name, [this.options]);
+}
diff --git a/sdk_nnbd/lib/core/bigint.dart b/sdk_nnbd/lib/core/bigint.dart
new file mode 100644
index 0000000..b495a9e
--- /dev/null
+++ b/sdk_nnbd/lib/core/bigint.dart
@@ -0,0 +1,414 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An arbitrarily large integer.
+ */
+abstract class BigInt implements Comparable<BigInt> {
+ external static BigInt get zero;
+ external static BigInt get one;
+ external static BigInt get two;
+
+ /**
+ * Parses [source] as a, possibly signed, integer literal and returns its
+ * value.
+ *
+ * The [source] must be a non-empty sequence of base-[radix] digits,
+ * optionally prefixed with a minus or plus sign ('-' or '+').
+ *
+ * The [radix] must be in the range 2..36. The digits used are
+ * first the decimal digits 0..9, and then the letters 'a'..'z' with
+ * values 10 through 35. Also accepts upper-case letters with the same
+ * values as the lower-case ones.
+ *
+ * If no [radix] is given then it defaults to 10. In this case, the [source]
+ * digits may also start with `0x`, in which case the number is interpreted
+ * as a hexadecimal literal, which effectively means that the `0x` is ignored
+ * and the radix is instead set to 16.
+ *
+ * For any int `n` and radix `r`, it is guaranteed that
+ * `n == int.parse(n.toRadixString(r), radix: r)`.
+ *
+ * Throws a [FormatException] if the [source] is not a valid integer literal,
+ * optionally prefixed by a sign.
+ */
+ external static BigInt parse(String source, {int radix});
+
+ /**
+ * Parses [source] as a, possibly signed, integer literal and returns its
+ * value.
+ *
+ * As [parse] except that this method returns `null` if the input is not
+ * valid
+ */
+ external static BigInt tryParse(String source, {int radix});
+
+ /// Allocates a big integer from the provided [value] number.
+ external factory BigInt.from(num value);
+
+ /**
+ * Returns the absolute value of this integer.
+ *
+ * For any integer `x`, the result is the same as `x < 0 ? -x : x`.
+ */
+ BigInt abs();
+
+ /**
+ * Return the negative value of this integer.
+ *
+ * The result of negating an integer always has the opposite sign, except
+ * for zero, which is its own negation.
+ */
+ BigInt operator -();
+
+ /// Addition operator.
+ BigInt operator +(BigInt other);
+
+ /// Subtraction operator.
+ BigInt operator -(BigInt other);
+
+ /// Multiplication operator.
+ BigInt operator *(BigInt other);
+
+ /// Division operator.
+ double operator /(BigInt other);
+
+ /**
+ * Truncating division operator.
+ *
+ * Performs a truncating integer division, where the remainder is discarded.
+ *
+ * The remainder can be computed using the [remainder] method.
+ *
+ * Examples:
+ * ```
+ * var seven = new BigInt.from(7);
+ * var three = new BigInt.from(3);
+ * seven ~/ three; // => 2
+ * (-seven) ~/ three; // => -2
+ * seven ~/ -three; // => -2
+ * seven.remainder(three); // => 1
+ * (-seven).remainder(three); // => -1
+ * seven.remainder(-three); // => 1
+ * ```
+ */
+ BigInt operator ~/(BigInt other);
+
+ /**
+ * Euclidean modulo operator.
+ *
+ * Returns the remainder of the Euclidean division. The Euclidean division of
+ * two integers `a` and `b` yields two integers `q` and `r` such that
+ * `a == b * q + r` and `0 <= r < b.abs()`.
+ *
+ * The sign of the returned value `r` is always positive.
+ *
+ * See [remainder] for the remainder of the truncating division.
+ */
+ BigInt operator %(BigInt other);
+
+ /**
+ * Returns the remainder of the truncating division of `this` by [other].
+ *
+ * The result `r` of this operation satisfies:
+ * `this == (this ~/ other) * other + r`.
+ * As a consequence the remainder `r` has the same sign as the divider `this`.
+ */
+ BigInt remainder(BigInt other);
+
+ /**
+ * Shift the bits of this integer to the left by [shiftAmount].
+ *
+ * Shifting to the left makes the number larger, effectively multiplying
+ * the number by `pow(2, shiftIndex)`.
+ *
+ * There is no limit on the size of the result. It may be relevant to
+ * limit intermediate values by using the "and" operator with a suitable
+ * mask.
+ *
+ * It is an error if [shiftAmount] is negative.
+ */
+ BigInt operator <<(int shiftAmount);
+
+ /**
+ * Shift the bits of this integer to the right by [shiftAmount].
+ *
+ * Shifting to the right makes the number smaller and drops the least
+ * significant bits, effectively doing an integer division by
+ *`pow(2, shiftIndex)`.
+ *
+ * It is an error if [shiftAmount] is negative.
+ */
+ BigInt operator >>(int shiftAmount);
+
+ /**
+ * Bit-wise and operator.
+ *
+ * Treating both `this` and [other] as sufficiently large two's component
+ * integers, the result is a number with only the bits set that are set in
+ * both `this` and [other]
+ *
+ * Of both operands are negative, the result is negative, otherwise
+ * the result is non-negative.
+ */
+ BigInt operator &(BigInt other);
+
+ /**
+ * Bit-wise or operator.
+ *
+ * Treating both `this` and [other] as sufficiently large two's component
+ * integers, the result is a number with the bits set that are set in either
+ * of `this` and [other]
+ *
+ * If both operands are non-negative, the result is non-negative,
+ * otherwise the result us negative.
+ */
+ BigInt operator |(BigInt other);
+
+ /**
+ * Bit-wise exclusive-or operator.
+ *
+ * Treating both `this` and [other] as sufficiently large two's component
+ * integers, the result is a number with the bits set that are set in one,
+ * but not both, of `this` and [other]
+ *
+ * If the operands have the same sign, the result is non-negative,
+ * otherwise the result is negative.
+ */
+ BigInt operator ^(BigInt other);
+
+ /**
+ * The bit-wise negate operator.
+ *
+ * Treating `this` as a sufficiently large two's component integer,
+ * the result is a number with the opposite bits set.
+ *
+ * This maps any integer `x` to `-x - 1`.
+ */
+ BigInt operator ~();
+
+ /** Relational less than operator. */
+ bool operator <(BigInt other);
+
+ /** Relational less than or equal operator. */
+ bool operator <=(BigInt other);
+
+ /** Relational greater than operator. */
+ bool operator >(BigInt other);
+
+ /** Relational greater than or equal operator. */
+ bool operator >=(BigInt other);
+
+ /**
+ * Compares this to `other`.
+ *
+ * Returns a negative number if `this` is less than `other`, zero if they are
+ * equal, and a positive number if `this` is greater than `other`.
+ */
+ int compareTo(BigInt other);
+
+ /**
+ * Returns the minimum number of bits required to store this big integer.
+ *
+ * The number of bits excludes the sign bit, which gives the natural length
+ * for non-negative (unsigned) values. Negative values are complemented to
+ * return the bit position of the first bit that differs from the sign bit.
+ *
+ * To find the number of bits needed to store the value as a signed value,
+ * add one, i.e. use `x.bitLength + 1`.
+ *
+ * ```
+ * x.bitLength == (-x-1).bitLength
+ *
+ * new BigInt.from(3).bitLength == 2; // 00000011
+ * new BigInt.from(2).bitLength == 2; // 00000010
+ * new BigInt.from(1).bitLength == 1; // 00000001
+ * new BigInt.from(0).bitLength == 0; // 00000000
+ * new BigInt.from(-1).bitLength == 0; // 11111111
+ * new BigInt.from(-2).bitLength == 1; // 11111110
+ * new BigInt.from(-3).bitLength == 2; // 11111101
+ * new BigInt.from(-4).bitLength == 2; // 11111100
+ * ```
+ */
+ int get bitLength;
+
+ /**
+ * Returns the sign of this big integer.
+ *
+ * Returns 0 for zero, -1 for values less than zero and
+ * +1 for values greater than zero.
+ */
+ int get sign;
+
+ /// Whether this big integer is even.
+ bool get isEven;
+
+ /// Whether this big integer is odd.
+ bool get isOdd;
+
+ /// Whether this number is negative.
+ bool get isNegative;
+
+ /**
+ * Returns `this` to the power of [exponent].
+ *
+ * Returns [one] if the [exponent] equals 0.
+ *
+ * The [exponent] must otherwise be positive.
+ *
+ * The result is always equal to the mathematical result of this to the power
+ * [exponent], only limited by the available memory.
+ */
+ BigInt pow(int exponent);
+
+ /**
+ * Returns this integer to the power of [exponent] modulo [modulus].
+ *
+ * The [exponent] must be non-negative and [modulus] must be
+ * positive.
+ */
+ BigInt modPow(BigInt exponent, BigInt modulus);
+
+ /**
+ * Returns the modular multiplicative inverse of this big integer
+ * modulo [modulus].
+ *
+ * The [modulus] must be positive.
+ *
+ * It is an error if no modular inverse exists.
+ */
+ // Returns 1/this % modulus, with modulus > 0.
+ BigInt modInverse(BigInt modulus);
+
+ /**
+ * Returns the greatest common divisor of this big integer and [other].
+ *
+ * If either number is non-zero, the result is the numerically greatest
+ * integer dividing both `this` and `other`.
+ *
+ * The greatest common divisor is independent of the order,
+ * so `x.gcd(y)` is always the same as `y.gcd(x)`.
+ *
+ * For any integer `x`, `x.gcd(x)` is `x.abs()`.
+ *
+ * If both `this` and `other` is zero, the result is also zero.
+ */
+ BigInt gcd(BigInt other);
+
+ /**
+ * Returns the least significant [width] bits of this big integer as a
+ * non-negative number (i.e. unsigned representation). The returned value has
+ * zeros in all bit positions higher than [width].
+ *
+ * ```
+ * new BigInt.from(-1).toUnsigned(5) == 31 // 11111111 -> 00011111
+ * ```
+ *
+ * This operation can be used to simulate arithmetic from low level languages.
+ * For example, to increment an 8 bit quantity:
+ *
+ * ```
+ * q = (q + 1).toUnsigned(8);
+ * ```
+ *
+ * `q` will count from `0` up to `255` and then wrap around to `0`.
+ *
+ * If the input fits in [width] bits without truncation, the result is the
+ * same as the input. The minimum width needed to avoid truncation of `x` is
+ * given by `x.bitLength`, i.e.
+ *
+ * ```
+ * x == x.toUnsigned(x.bitLength);
+ * ```
+ */
+ BigInt toUnsigned(int width);
+
+ /**
+ * Returns the least significant [width] bits of this integer, extending the
+ * highest retained bit to the sign. This is the same as truncating the value
+ * to fit in [width] bits using an signed 2-s complement representation. The
+ * returned value has the same bit value in all positions higher than [width].
+ *
+ * ```
+ * var big15 = new BigInt.from(15);
+ * var big16 = new BigInt.from(16);
+ * var big239 = new BigInt.from(239);
+ * V--sign bit-V
+ * big16.toSigned(5) == -big16 // 00010000 -> 11110000
+ * big239.toSigned(5) == big15 // 11101111 -> 00001111
+ * ^ ^
+ * ```
+ *
+ * This operation can be used to simulate arithmetic from low level languages.
+ * For example, to increment an 8 bit signed quantity:
+ *
+ * ```
+ * q = (q + 1).toSigned(8);
+ * ```
+ *
+ * `q` will count from `0` up to `127`, wrap to `-128` and count back up to
+ * `127`.
+ *
+ * If the input value fits in [width] bits without truncation, the result is
+ * the same as the input. The minimum width needed to avoid truncation of `x`
+ * is `x.bitLength + 1`, i.e.
+ *
+ * ```
+ * x == x.toSigned(x.bitLength + 1);
+ * ```
+ */
+ BigInt toSigned(int width);
+
+ /**
+ * Whether this big integer can be represented as an `int` without losing
+ * precision.
+ *
+ * Warning: this function may give a different result on
+ * dart2js, dev compiler, and the VM, due to the differences in
+ * integer precision.
+ */
+ bool get isValidInt;
+
+ /**
+ * Returns this [BigInt] as an [int].
+ *
+ * If the number does not fit, clamps to the max (or min)
+ * integer.
+ *
+ * Warning: the clamping behaves differently on dart2js, dev
+ * compiler, and the VM, due to the differences in integer
+ * precision.
+ */
+ int toInt();
+
+ /**
+ * Returns this [BigInt] as a [double].
+ *
+ * If the number is not representable as a [double], an
+ * approximation is returned. For numerically large integers, the
+ * approximation may be infinite.
+ */
+ double toDouble();
+
+ /**
+ * Returns a String-representation of this integer.
+ *
+ * The returned string is parsable by [parse].
+ * For any `BigInt` `i`, it is guaranteed that
+ * `i == BigInt.parse(i.toString())`.
+ */
+ String toString();
+
+ /**
+ * Converts [this] to a string representation in the given [radix].
+ *
+ * In the string representation, lower-case letters are used for digits above
+ * '9', with 'a' being 10 an 'z' being 35.
+ *
+ * The [radix] argument must be an integer in the range 2 to 36.
+ */
+ String toRadixString(int radix);
+}
diff --git a/sdk_nnbd/lib/core/bool.dart b/sdk_nnbd/lib/core/bool.dart
new file mode 100644
index 0000000..5ed1065
--- /dev/null
+++ b/sdk_nnbd/lib/core/bool.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * The reserved words `true` and `false` denote objects that are the only two
+ * instances of this class.
+ *
+ * It is a compile-time error for a class to attempt to extend or implement
+ * bool.
+ */
+@pragma("vm:entry-point")
+class bool {
+ /**
+ * Returns the boolean value of the environment declaration [name].
+ *
+ * The boolean value of the declaration is `true` if the declared value is
+ * the string `"true"`, and `false` if the value is `"false"`.
+ *
+ * In all other cases, including when there is no declaration for `name`,
+ * the result is the [defaultValue].
+ *
+ * The result is the same as would be returned by:
+ * ```dart
+ * (const String.fromEnvironment(name) == "true")
+ * ? true
+ * : (const String.fromEnvironment(name) == "false")
+ * ? false
+ * : defaultValue
+ * ```
+ * Example:
+ * ```dart
+ * const loggingFlag = const bool.fromEnvironment("logging");
+ * ```
+ * If you want to use a different truth-string than `"true"`, you can use the
+ * [String.fromEnvironment] constructor directly:
+ * ```dart
+ * const isLoggingOn = (const String.fromEnvironment("logging") == "on");
+ * ```
+ */
+ // The .fromEnvironment() constructors are special in that we do not want
+ // users to call them using "new". We prohibit that by giving them bodies
+ // that throw, even though const constructors are not allowed to have bodies.
+ // Disable those static errors.
+ //ignore: const_constructor_with_body
+ //ignore: const_factory
+ external const factory bool.fromEnvironment(String name,
+ {bool defaultValue = false});
+
+ external int get hashCode;
+
+ /// The logical conjunction ("and") of this and [other].
+ ///
+ /// Returns `true` if both this and [other] are `true`, and `false` otherwise.
+ //TODO(lrn): Remove "as bool" in Dart 2.
+ @Since("2.1")
+ bool operator &(bool other) => (other as bool) && this;
+
+ /// The logical disjunction ("inclusive or") of this and [other].
+ ///
+ /// Returns `true` if either this or [other] is `true`, and `false` otherwise.
+ @Since("2.1")
+ bool operator |(bool other) => (other as bool) || this;
+
+ /// The logical exclusive disjunction ("exclusive or") of this and [other].
+ ///
+ /// Returns whether this and [other] are neither both `true` nor both `false`.
+ @Since("2.1")
+ bool operator ^(bool other) => !(other as bool) == this;
+
+ /**
+ * Returns either `"true"` for `true` and `"false"` for `false`.
+ */
+ String toString() {
+ return this ? "true" : "false";
+ }
+}
diff --git a/sdk_nnbd/lib/core/comparable.dart b/sdk_nnbd/lib/core/comparable.dart
new file mode 100644
index 0000000..835aa34
--- /dev/null
+++ b/sdk_nnbd/lib/core/comparable.dart
@@ -0,0 +1,94 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * The signature of a generic comparison function.
+ *
+ * A comparison function represents an ordering on a type of objects.
+ * A total ordering on a type means that for two values, either they
+ * are equal or one is greater than the other (and the latter must then be
+ * smaller than the former).
+ *
+ * A [Comparator] function represents such a total ordering by returning
+ *
+ * * a negative integer if [a] is smaller than [b],
+ * * zero if [a] is equal to [b], and
+ * * a positive integer if [a] is greater than [b].
+ */
+typedef Comparator<T> = int Function(T a, T b);
+
+/**
+ * Interface used by types that have an intrinsic ordering.
+ *
+ * The [compareTo] operation defines a total ordering of objects,
+ * which can be used for ordering and sorting.
+ *
+ * The [Comparable] interface should be used for the natural ordering of a type.
+ * If a type can be ordered in more than one way,
+ * and none of them is the obvious natural ordering,
+ * then it might be better not to use the [Comparable] interface,
+ * and to provide separate [Comparator]s instead.
+ *
+ * It is recommended that the order of a [Comparable] agrees
+ * with its operator [operator ==] equality (`a.compareTo(b) == 0` iff `a == b`),
+ * but this is not a requirement.
+ * For example, [double] and [DateTime] have `compareTo` methods
+ * that do not agree with operator [operator ==].
+ * For doubles the [compareTo] method is more precise than the equality,
+ * and for [DateTime] it is less precise.
+ *
+ * Examples:
+ *
+ * (0.0).compareTo(-0.0); // => 1
+ * 0.0 == -0.0; // => true
+ * var dt = new DateTime.now();
+ * var dt2 = dt.toUtc();
+ * dt == dt2; // => false
+ * dt.compareTo(dt2); // => 0
+ *
+ * The [Comparable] interface does not imply the existence
+ * of the comparison operators `<`, `<=`, `>` and `>=`.
+ * These should only be defined
+ * if the ordering is a less-than/greater-than ordering,
+ * that is, an ordering where you would naturally
+ * use the words "less than" about the order of two elements.
+ *
+ * If the equality operator and [compareTo] disagree,
+ * the comparison operators should follow the equality operator,
+ * and will likely also disagree with [compareTo].
+ * Otherwise they should match the [compareTo] method,
+ * so that `a < b` iff `a.compareTo(b) < 0`.
+ *
+ * The [double] class defines comparison operators
+ * that are compatible with equality.
+ * The operators differ from `double.compareTo` on -0.0 and NaN.
+ *
+ * The [DateTime] class has no comparison operators, instead it has the more
+ * precisely named [DateTime.isBefore] and [DateTime.isAfter].
+ */
+abstract class Comparable<T> {
+ /**
+ * Compares this object to another [Comparable]
+ *
+ * Returns a value like a [Comparator] when comparing `this` to [other].
+ * That is, it returns a negative integer if `this` is ordered before [other],
+ * a positive integer if `this` is ordered after [other],
+ * and zero if `this` and [other] are ordered together.
+ *
+ * The [other] argument must be a value that is comparable to this object.
+ */
+ int compareTo(T other);
+
+ /**
+ * A [Comparator] that compares one comparable to another.
+ *
+ * It returns the result of `a.compareTo(b)`.
+ *
+ * This utility function is used as the default comparator
+ * for ordering collections, for example in the [List] sort function.
+ */
+ static int compare(Comparable a, Comparable b) => a.compareTo(b);
+}
diff --git a/sdk_nnbd/lib/core/core.dart b/sdk_nnbd/lib/core/core.dart
new file mode 100644
index 0000000..9ab8ed4
--- /dev/null
+++ b/sdk_nnbd/lib/core/core.dart
@@ -0,0 +1,208 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ *
+ * Built-in types, collections,
+ * and other core functionality for every Dart program.
+ *
+ * This library is automatically imported.
+ *
+ * Some classes in this library,
+ * such as [String] and [num],
+ * support Dart's built-in data types.
+ * Other classes, such as [List] and [Map], provide data structures
+ * for managing collections of objects.
+ * And still other classes represent commonly used types of data
+ * such as URIs, dates and times, and errors.
+ *
+ * ## Numbers and booleans
+ *
+ * [int] and [double] provide support for Dart's built-in numerical data types:
+ * integers and double-precision floating point numbers, respectively.
+ * An object of type [bool] is either true or false.
+ * Variables of these types can be constructed from literals:
+ *
+ * int meaningOfLife = 42;
+ * double valueOfPi = 3.141592;
+ * bool visible = true;
+ *
+ * ## Strings and regular expressions
+ *
+ * A [String] is immutable and represents a sequence of characters.
+ *
+ * String shakespeareQuote = "All the world's a stage, ...";
+ *
+ * [StringBuffer] provides a way to construct strings efficiently.
+ *
+ * StringBuffer moreShakespeare = new StringBuffer();
+ * moreShakespeare.write('And all the men and women ');
+ * moreShakespeare.write('merely players; ...');
+ *
+ * The String and StringBuffer classes implement string concatenation,
+ * interpolation, and other string manipulation features.
+ *
+ * String philosophy = 'Live on ';
+ * String get palindrome => philosophy + philosophy.split('').reversed.join();
+ *
+ * [RegExp] implements Dart regular expressions,
+ * which provide a grammar for matching patterns within text.
+ * For example, here's a regular expression that matches
+ * a string of one or more digits:
+ *
+ * var numbers = new RegExp(r'\d+');
+ *
+ * Dart regular expressions have the same syntax and semantics as
+ * JavaScript regular expressions. See
+ * <http://ecma-international.org/ecma-262/5.1/#sec-15.10>
+ * for the specification of JavaScript regular expressions.
+ *
+ * ## Collections
+ *
+ * The dart:core library provides basic collections,
+ * such as [List], [Map], and [Set].
+ *
+ * A List is an ordered collection of objects, with a length.
+ * Lists are sometimes called arrays.
+ * Use a List when you need to access objects by index.
+ *
+ * List superheroes = [ 'Batman', 'Superman', 'Harry Potter' ];
+ *
+ * A Set is an unordered collection of unique objects.
+ * You cannot get an item by index (position).
+ * Adding a duplicate item has no effect.
+ *
+ * Set villains = new Set();
+ * villains.add('Joker');
+ * villains.addAll( ['Lex Luther', 'Voldemort'] );
+ *
+ * A Map is an unordered collection of key-value pairs.
+ * Maps are sometimes called associative arrays because
+ * maps associate a key to some value for easy retrieval.
+ * Keys are unique.
+ * Use a Map when you need to access objects
+ * by a unique identifier.
+ *
+ * Map sidekicks = { 'Batman': 'Robin',
+ * 'Superman': 'Lois Lane',
+ * 'Harry Potter': 'Ron and Hermione' };
+ *
+ * In addition to these classes,
+ * dart:core contains [Iterable],
+ * an interface that defines functionality
+ * common in collections of objects.
+ * Examples include the ability
+ * to run a function on each element in the collection,
+ * to apply a test to each element,
+ * to retrieve an object, and to determine length.
+ *
+ * Iterable is implemented by List and Set,
+ * and used by Map for its keys and values.
+ *
+ * For other kinds of collections, check out the
+ * `dart:collection` library.
+ *
+ * ## Date and time
+ *
+ * Use [DateTime] to represent a point in time
+ * and [Duration] to represent a span of time.
+ *
+ * You can create DateTime objects with constructors
+ * or by parsing a correctly formatted string.
+ *
+ * DateTime now = new DateTime.now();
+ * DateTime berlinWallFell = new DateTime(1989, 11, 9);
+ * DateTime moonLanding = DateTime.parse("1969-07-20");
+ *
+ * Create a Duration object specifying the individual time units.
+ *
+ * Duration timeRemaining = new Duration(hours:56, minutes:14);
+ *
+ * In addition to DateTime and Duration,
+ * dart:core contains the [Stopwatch] class for measuring elapsed time.
+ *
+ * ## Uri
+ *
+ * A [Uri] object represents a uniform resource identifier,
+ * which identifies a resource on the web.
+ *
+ * Uri dartlang = Uri.parse('http://dartlang.org/');
+ *
+ * ## Errors
+ *
+ * The [Error] class represents the occurrence of an error
+ * during runtime.
+ * Subclasses of this class represent specific kinds of errors.
+ *
+ * ## Other documentation
+ *
+ * For more information about how to use the built-in types, refer to [Built-in
+ * Types](http://www.dartlang.org/docs/dart-up-and-running/contents/ch02.html#built-in-types)
+ * in Chapter 2 of
+ * [Dart: Up and Running](http://www.dartlang.org/docs/dart-up-and-running/).
+ *
+ * Also, see [dart:core - Numbers, Collections, Strings, and
+ * More](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartcore---numbers-collections-strings-and-more)
+ * for more coverage of classes in this package.
+ *
+ * The
+ * [Dart Language Specification](http://www.dartlang.org/docs/spec/)
+ * provides technical details.
+ *
+ * {@category Core}
+ */
+library dart.core;
+
+import "dart:collection";
+import "dart:_internal" hide Symbol, LinkedList, LinkedListEntry;
+import "dart:_internal" as internal show Symbol;
+import "dart:convert"
+ show
+ ascii,
+ base64,
+ Base64Codec,
+ Encoding,
+ latin1,
+ StringConversionSink,
+ utf8;
+import "dart:math" show Random; // Used by List.shuffle.
+import "dart:typed_data" show Uint8List, Uint16List, Endian;
+
+@Since("2.1")
+export "dart:async" show Future, Stream;
+
+part "annotations.dart";
+part "bigint.dart";
+part "bool.dart";
+part "comparable.dart";
+part "date_time.dart";
+part "double.dart";
+part "duration.dart";
+part "errors.dart";
+part "exceptions.dart";
+part "expando.dart";
+part "function.dart";
+part "identical.dart";
+part "int.dart";
+part "invocation.dart";
+part "iterable.dart";
+part "iterator.dart";
+part "list.dart";
+part "map.dart";
+part "null.dart";
+part "num.dart";
+part "object.dart";
+part "pattern.dart";
+part "print.dart";
+part "regexp.dart";
+part "set.dart";
+part "sink.dart";
+part "stacktrace.dart";
+part "stopwatch.dart";
+part "string.dart";
+part "string_buffer.dart";
+part "string_sink.dart";
+part "symbol.dart";
+part "type.dart";
+part "uri.dart";
diff --git a/sdk_nnbd/lib/core/core_sources.gni b/sdk_nnbd/lib/core/core_sources.gni
new file mode 100644
index 0000000..ce2785e
--- /dev/null
+++ b/sdk_nnbd/lib/core/core_sources.gni
@@ -0,0 +1,43 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+core_sdk_sources = [
+ "core.dart",
+
+ # The above file needs to be first as it lists the parts below.
+ "annotations.dart",
+ "bigint.dart",
+ "bool.dart",
+ "comparable.dart",
+ "date_time.dart",
+ "double.dart",
+ "duration.dart",
+ "errors.dart",
+ "exceptions.dart",
+ "expando.dart",
+ "function.dart",
+ "identical.dart",
+ "int.dart",
+ "invocation.dart",
+ "iterable.dart",
+ "iterator.dart",
+ "list.dart",
+ "map.dart",
+ "null.dart",
+ "num.dart",
+ "object.dart",
+ "pattern.dart",
+ "print.dart",
+ "regexp.dart",
+ "set.dart",
+ "sink.dart",
+ "stacktrace.dart",
+ "stopwatch.dart",
+ "string.dart",
+ "string_buffer.dart",
+ "string_sink.dart",
+ "symbol.dart",
+ "type.dart",
+ "uri.dart",
+]
diff --git a/sdk_nnbd/lib/core/date_time.dart b/sdk_nnbd/lib/core/date_time.dart
new file mode 100644
index 0000000..dd242de
--- /dev/null
+++ b/sdk_nnbd/lib/core/date_time.dart
@@ -0,0 +1,873 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An instant in time, such as July 20, 1969, 8:18pm GMT.
+ *
+ * DateTimes can represent time values that are at a distance of at most
+ * 100,000,000 days from epoch (1970-01-01 UTC): -271821-04-20 to 275760-09-13.
+ *
+ * Create a DateTime object by using one of the constructors
+ * or by parsing a correctly formatted string,
+ * which complies with a subset of ISO 8601.
+ * Note that hours are specified between 0 and 23,
+ * as in a 24-hour clock.
+ * For example:
+ *
+ * ```
+ * var now = new DateTime.now();
+ * var berlinWallFell = new DateTime.utc(1989, 11, 9);
+ * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z"); // 8:18pm
+ * ```
+ *
+ * A DateTime object is anchored either in the UTC time zone
+ * or in the local time zone of the current computer
+ * when the object is created.
+ *
+ * Once created, neither the value nor the time zone
+ * of a DateTime object may be changed.
+ *
+ * You can use properties to get
+ * the individual units of a DateTime object.
+ *
+ * ```
+ * assert(berlinWallFell.month == 11);
+ * assert(moonLanding.hour == 20);
+ * ```
+ *
+ * For convenience and readability,
+ * the DateTime class provides a constant for each day and month
+ * name - for example, [august] and [friday].
+ * You can use these constants to improve code readability:
+ *
+ * ```
+ * var berlinWallFell = new DateTime.utc(1989, DateTime.november, 9);
+ * assert(berlinWallFell.weekday == DateTime.thursday);
+ * ```
+ *
+ * Day and month values begin at 1, and the week starts on Monday.
+ * That is, the constants [january] and [monday] are both 1.
+ *
+ * ## Working with UTC and local time
+ *
+ * A DateTime object is in the local time zone
+ * unless explicitly created in the UTC time zone.
+ *
+ * ```
+ * var dDay = new DateTime.utc(1944, 6, 6);
+ * ```
+ *
+ * Use [isUtc] to determine whether a DateTime object is based in UTC.
+ * Use the methods [toLocal] and [toUtc]
+ * to get the equivalent date/time value specified in the other time zone.
+ * Use [timeZoneName] to get an abbreviated name of the time zone
+ * for the DateTime object.
+ * To find the difference
+ * between UTC and the time zone of a DateTime object
+ * call [timeZoneOffset].
+ *
+ * ## Comparing DateTime objects
+ *
+ * The DateTime class contains several handy methods,
+ * such as [isAfter], [isBefore], and [isAtSameMomentAs],
+ * for comparing DateTime objects.
+ *
+ * ```
+ * assert(berlinWallFell.isAfter(moonLanding) == true);
+ * assert(berlinWallFell.isBefore(moonLanding) == false);
+ * ```
+ *
+ * ## Using DateTime with Duration
+ *
+ * Use the [add] and [subtract] methods with a [Duration] object
+ * to create a new DateTime object based on another.
+ * For example, to find the date that is sixty days (24 * 60 hours) after today,
+ * write:
+ *
+ * ```
+ * var now = new DateTime.now();
+ * var sixtyDaysFromNow = now.add(new Duration(days: 60));
+ * ```
+ *
+ * To find out how much time is between two DateTime objects use
+ * [difference], which returns a [Duration] object:
+ *
+ * ```
+ * var difference = berlinWallFell.difference(moonLanding);
+ * assert(difference.inDays == 7416);
+ * ```
+ *
+ * The difference between two dates in different time zones
+ * is just the number of nanoseconds between the two points in time.
+ * It doesn't take calendar days into account.
+ * That means that the difference between two midnights in local time may be
+ * less than 24 hours times the number of days between them,
+ * if there is a daylight saving change in between.
+ * If the difference above is calculated using Australian local time, the
+ * difference is 7415 days and 23 hours, which is only 7415 whole days as
+ * reported by `inDays`.
+ *
+ * ## Other resources
+ *
+ * See [Duration] to represent a span of time.
+ * See [Stopwatch] to measure timespans.
+ *
+ * The DateTime class does not provide internationalization.
+ * To internationalize your code, use
+ * the [intl](https://pub.dartlang.org/packages/intl) package.
+ *
+ */
+class DateTime implements Comparable<DateTime> {
+ // Weekday constants that are returned by [weekday] method:
+ static const int monday = 1;
+ static const int tuesday = 2;
+ static const int wednesday = 3;
+ static const int thursday = 4;
+ static const int friday = 5;
+ static const int saturday = 6;
+ static const int sunday = 7;
+ static const int daysPerWeek = 7;
+
+ // Month constants that are returned by the [month] getter.
+ static const int january = 1;
+ static const int february = 2;
+ static const int march = 3;
+ static const int april = 4;
+ static const int may = 5;
+ static const int june = 6;
+ static const int july = 7;
+ static const int august = 8;
+ static const int september = 9;
+ static const int october = 10;
+ static const int november = 11;
+ static const int december = 12;
+ static const int monthsPerYear = 12;
+
+ /**
+ * The value of this DateTime.
+ *
+ * The content of this field is implementation dependent. On JavaScript it is
+ * equal to [millisecondsSinceEpoch]. On the VM it is equal to
+ * [microsecondsSinceEpoch].
+ */
+ final int _value;
+
+ /**
+ * True if this [DateTime] is set to UTC time.
+ *
+ * ```
+ * var dDay = new DateTime.utc(1944, 6, 6);
+ * assert(dDay.isUtc);
+ * ```
+ *
+ */
+ final bool isUtc;
+
+ /**
+ * Constructs a [DateTime] instance specified in the local time zone.
+ *
+ * For example,
+ * to create a new DateTime object representing the 7th of September 2017,
+ * 5:30pm
+ *
+ * ```
+ * var dentistAppointment = new DateTime(2017, 9, 7, 17, 30);
+ * ```
+ */
+ DateTime(int year,
+ [int month = 1,
+ int day = 1,
+ int hour = 0,
+ int minute = 0,
+ int second = 0,
+ int millisecond = 0,
+ int microsecond = 0])
+ : this._internal(year, month, day, hour, minute, second, millisecond,
+ microsecond, false);
+
+ /**
+ * Constructs a [DateTime] instance specified in the UTC time zone.
+ *
+ * ```
+ * var moonLanding = new DateTime.utc(1969, 7, 20, 20, 18, 04);
+ * ```
+ *
+ * When dealing with dates or historic events prefer to use UTC DateTimes,
+ * since they are unaffected by daylight-saving changes and are unaffected
+ * by the local timezone.
+ */
+ DateTime.utc(int year,
+ [int month = 1,
+ int day = 1,
+ int hour = 0,
+ int minute = 0,
+ int second = 0,
+ int millisecond = 0,
+ int microsecond = 0])
+ : this._internal(year, month, day, hour, minute, second, millisecond,
+ microsecond, true);
+
+ /**
+ * Constructs a [DateTime] instance with current date and time in the
+ * local time zone.
+ *
+ * ```
+ * var thisInstant = new DateTime.now();
+ * ```
+ */
+ DateTime.now() : this._now();
+
+ /**
+ * Constructs a new [DateTime] instance based on [formattedString].
+ *
+ * The [formattedString] must not be `null`.
+ * Throws a [FormatException] if the input string cannot be parsed.
+ *
+ * The function parses a subset of ISO 8601
+ * which includes the subset accepted by RFC 3339.
+ *
+ * The accepted inputs are currently:
+ *
+ * * A date: A signed four-to-six digit year, two digit month and
+ * two digit day, optionally separated by `-` characters.
+ * Examples: "19700101", "-0004-12-24", "81030-04-01".
+ * * An optional time part, separated from the date by either `T` or a space.
+ * The time part is a two digit hour,
+ * then optionally a two digit minutes value,
+ * then optionally a two digit seconds value, and
+ * then optionally a '.' or ',' followed by a one-to-six digit second fraction.
+ * The minutes and seconds may be separated from the previous parts by a
+ * ':'.
+ * Examples: "12", "12:30:24.124", "12:30:24,124", "123010.50".
+ * * An optional time-zone offset part,
+ * possibly separated from the previous by a space.
+ * The time zone is either 'z' or 'Z', or it is a signed two digit hour
+ * part and an optional two digit minute part. The sign must be either
+ * "+" or "-", and can not be omitted.
+ * The minutes may be separated from the hours by a ':'.
+ * Examples: "Z", "-10", "+01:30", "+1130".
+ *
+ * This includes the output of both [toString] and [toIso8601String], which
+ * will be parsed back into a `DateTime` object with the same time as the
+ * original.
+ *
+ * The result is always in either local time or UTC.
+ * If a time zone offset other than UTC is specified,
+ * the time is converted to the equivalent UTC time.
+ *
+ * Examples of accepted strings:
+ *
+ * * `"2012-02-27 13:27:00"`
+ * * `"2012-02-27 13:27:00.123456z"`
+ * * `"2012-02-27 13:27:00,123456z"`
+ * * `"20120227 13:27:00"`
+ * * `"20120227T132700"`
+ * * `"20120227"`
+ * * `"+20120227"`
+ * * `"2012-02-27T14Z"`
+ * * `"2012-02-27T14+00:00"`
+ * * `"-123450101 00:00:00 Z"`: in the year -12345.
+ * * `"2002-02-27T14:00:00-0500"`: Same as `"2002-02-27T19:00:00Z"`
+ */
+ // TODO(lrn): restrict incorrect values like 2003-02-29T50:70:80.
+ // Or not, that may be a breaking change.
+ static DateTime parse(String formattedString) {
+ var re = _parseFormat;
+ Match match = re.firstMatch(formattedString);
+ if (match != null) {
+ int parseIntOrZero(String matched) {
+ if (matched == null) return 0;
+ return int.parse(matched);
+ }
+
+ // Parses fractional second digits of '.(\d{1,6})' into the combined
+ // microseconds.
+ int parseMilliAndMicroseconds(String matched) {
+ if (matched == null) return 0;
+ int length = matched.length;
+ assert(length >= 1);
+ assert(length <= 6);
+
+ int result = 0;
+ for (int i = 0; i < 6; i++) {
+ result *= 10;
+ if (i < matched.length) {
+ result += matched.codeUnitAt(i) ^ 0x30;
+ }
+ }
+ return result;
+ }
+
+ int years = int.parse(match[1]);
+ int month = int.parse(match[2]);
+ int day = int.parse(match[3]);
+ int hour = parseIntOrZero(match[4]);
+ int minute = parseIntOrZero(match[5]);
+ int second = parseIntOrZero(match[6]);
+ bool addOneMillisecond = false;
+ int milliAndMicroseconds = parseMilliAndMicroseconds(match[7]);
+ int millisecond =
+ milliAndMicroseconds ~/ Duration.microsecondsPerMillisecond;
+ int microsecond =
+ milliAndMicroseconds.remainder(Duration.microsecondsPerMillisecond);
+ bool isUtc = false;
+ if (match[8] != null) {
+ // timezone part
+ isUtc = true;
+ if (match[9] != null) {
+ // timezone other than 'Z' and 'z'.
+ int sign = (match[9] == '-') ? -1 : 1;
+ int hourDifference = int.parse(match[10]);
+ int minuteDifference = parseIntOrZero(match[11]);
+ minuteDifference += 60 * hourDifference;
+ minute -= sign * minuteDifference;
+ }
+ }
+ int value = _brokenDownDateToValue(years, month, day, hour, minute,
+ second, millisecond, microsecond, isUtc);
+ if (value == null) {
+ throw FormatException("Time out of range", formattedString);
+ }
+ return DateTime._withValue(value, isUtc: isUtc);
+ } else {
+ throw FormatException("Invalid date format", formattedString);
+ }
+ }
+
+ /**
+ * Constructs a new [DateTime] instance based on [formattedString].
+ *
+ * Works like [parse] except that this function returns `null`
+ * where [parse] would throw a [FormatException].
+ */
+ static DateTime tryParse(String formattedString) {
+ // TODO: Optimize to avoid throwing.
+ try {
+ return parse(formattedString);
+ } on FormatException {
+ return null;
+ }
+ }
+
+ static const int _maxMillisecondsSinceEpoch = 8640000000000000;
+
+ /**
+ * Constructs a new [DateTime] instance
+ * with the given [millisecondsSinceEpoch].
+ *
+ * If [isUtc] is false then the date is in the local time zone.
+ *
+ * The constructed [DateTime] represents
+ * 1970-01-01T00:00:00Z + [millisecondsSinceEpoch] ms in the given
+ * time zone (local or UTC).
+ */
+ external DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
+ {bool isUtc = false});
+
+ /**
+ * Constructs a new [DateTime] instance
+ * with the given [microsecondsSinceEpoch].
+ *
+ * If [isUtc] is false then the date is in the local time zone.
+ *
+ * The constructed [DateTime] represents
+ * 1970-01-01T00:00:00Z + [microsecondsSinceEpoch] us in the given
+ * time zone (local or UTC).
+ */
+ external DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
+ {bool isUtc = false});
+
+ /**
+ * Constructs a new [DateTime] instance with the given value.
+ *
+ * If [isUtc] is false then the date is in the local time zone.
+ */
+ DateTime._withValue(this._value, {this.isUtc}) {
+ if (millisecondsSinceEpoch.abs() > _maxMillisecondsSinceEpoch ||
+ (millisecondsSinceEpoch.abs() == _maxMillisecondsSinceEpoch &&
+ microsecond != 0)) {
+ throw ArgumentError(
+ "DateTime is outside valid range: $millisecondsSinceEpoch");
+ }
+ if (isUtc == null) {
+ throw ArgumentError("'isUtc' flag may not be 'null'");
+ }
+ }
+
+ /**
+ * Returns true if [other] is a [DateTime] at the same moment and in the
+ * same time zone (UTC or local).
+ *
+ * ```
+ * var dDayUtc = new DateTime.utc(1944, 6, 6);
+ * var dDayLocal = dDayUtc.toLocal();
+ *
+ * // These two dates are at the same moment, but are in different zones.
+ * assert(dDayUtc != dDayLocal);
+ * ```
+ *
+ * See [isAtSameMomentAs] for a comparison that compares moments in time
+ * independently of their zones.
+ */
+ external bool operator ==(dynamic other);
+
+ /**
+ * Returns true if [this] occurs before [other].
+ *
+ * The comparison is independent
+ * of whether the time is in UTC or in the local time zone.
+ *
+ * ```
+ * var now = new DateTime.now();
+ * var earlier = now.subtract(const Duration(seconds: 5));
+ * assert(earlier.isBefore(now));
+ * assert(!now.isBefore(now));
+ *
+ * // This relation stays the same, even when changing timezones.
+ * assert(earlier.isBefore(now.toUtc()));
+ * assert(earlier.toUtc().isBefore(now));
+ *
+ * assert(!now.toUtc().isBefore(now));
+ * assert(!now.isBefore(now.toUtc()));
+ * ```
+ */
+ external bool isBefore(DateTime other);
+
+ /**
+ * Returns true if [this] occurs after [other].
+ *
+ * The comparison is independent
+ * of whether the time is in UTC or in the local time zone.
+ *
+ * ```
+ * var now = new DateTime.now();
+ * var later = now.add(const Duration(seconds: 5));
+ * assert(later.isAfter(now));
+ * assert(!now.isBefore(now));
+ *
+ * // This relation stays the same, even when changing timezones.
+ * assert(later.isAfter(now.toUtc()));
+ * assert(later.toUtc().isAfter(now));
+ *
+ * assert(!now.toUtc().isBefore(now));
+ * assert(!now.isBefore(now.toUtc()));
+ * ```
+ */
+ external bool isAfter(DateTime other);
+
+ /**
+ * Returns true if [this] occurs at the same moment as [other].
+ *
+ * The comparison is independent of whether the time is in UTC or in the local
+ * time zone.
+ *
+ * ```
+ * var now = new DateTime.now();
+ * var later = now.add(const Duration(seconds: 5));
+ * assert(!later.isAtSameMomentAs(now));
+ * assert(now.isAtSameMomentAs(now));
+ *
+ * // This relation stays the same, even when changing timezones.
+ * assert(!later.isAtSameMomentAs(now.toUtc()));
+ * assert(!later.toUtc().isAtSameMomentAs(now));
+ *
+ * assert(now.toUtc().isAtSameMomentAs(now));
+ * assert(now.isAtSameMomentAs(now.toUtc()));
+ * ```
+ */
+ external bool isAtSameMomentAs(DateTime other);
+
+ /**
+ * Compares this DateTime object to [other],
+ * returning zero if the values are equal.
+ *
+ * Returns a negative value if this DateTime [isBefore] [other]. It returns 0
+ * if it [isAtSameMomentAs] [other], and returns a positive value otherwise
+ * (when this [isAfter] [other]).
+ */
+ external int compareTo(DateTime other);
+
+ int get hashCode => (_value ^ (_value >> 30)) & 0x3FFFFFFF;
+
+ /**
+ * Returns this DateTime value in the local time zone.
+ *
+ * Returns [this] if it is already in the local time zone.
+ * Otherwise this method is equivalent to:
+ *
+ * ```
+ * new DateTime.fromMicrosecondsSinceEpoch(microsecondsSinceEpoch,
+ * isUtc: false)
+ * ```
+ */
+ DateTime toLocal() {
+ if (isUtc) {
+ return DateTime._withValue(_value, isUtc: false);
+ }
+ return this;
+ }
+
+ /**
+ * Returns this DateTime value in the UTC time zone.
+ *
+ * Returns [this] if it is already in UTC.
+ * Otherwise this method is equivalent to:
+ *
+ * ```
+ * new DateTime.fromMicrosecondsSinceEpoch(microsecondsSinceEpoch,
+ * isUtc: true)
+ * ```
+ */
+ DateTime toUtc() {
+ if (isUtc) return this;
+ return DateTime._withValue(_value, isUtc: true);
+ }
+
+ static String _fourDigits(int n) {
+ int absN = n.abs();
+ String sign = n < 0 ? "-" : "";
+ if (absN >= 1000) return "$n";
+ if (absN >= 100) return "${sign}0$absN";
+ if (absN >= 10) return "${sign}00$absN";
+ return "${sign}000$absN";
+ }
+
+ static String _sixDigits(int n) {
+ assert(n < -9999 || n > 9999);
+ int absN = n.abs();
+ String sign = n < 0 ? "-" : "+";
+ if (absN >= 100000) return "$sign$absN";
+ return "${sign}0$absN";
+ }
+
+ static String _threeDigits(int n) {
+ if (n >= 100) return "${n}";
+ if (n >= 10) return "0${n}";
+ return "00${n}";
+ }
+
+ static String _twoDigits(int n) {
+ if (n >= 10) return "${n}";
+ return "0${n}";
+ }
+
+ /**
+ * Returns a human-readable string for this instance.
+ *
+ * The returned string is constructed for the time zone of this instance.
+ * The `toString()` method provides a simply formatted string.
+ * It does not support internationalized strings.
+ * Use the [intl](https://pub.dartlang.org/packages/intl) package
+ * at the pub shared packages repo.
+ *
+ * The resulting string can be parsed back using [parse].
+ */
+ String toString() {
+ String y = _fourDigits(year);
+ String m = _twoDigits(month);
+ String d = _twoDigits(day);
+ String h = _twoDigits(hour);
+ String min = _twoDigits(minute);
+ String sec = _twoDigits(second);
+ String ms = _threeDigits(millisecond);
+ String us = microsecond == 0 ? "" : _threeDigits(microsecond);
+ if (isUtc) {
+ return "$y-$m-$d $h:$min:$sec.$ms${us}Z";
+ } else {
+ return "$y-$m-$d $h:$min:$sec.$ms$us";
+ }
+ }
+
+ /**
+ * Returns an ISO-8601 full-precision extended format representation.
+ *
+ * The format is `yyyy-MM-ddTHH:mm:ss.mmmuuuZ` for UTC time, and
+ * `yyyy-MM-ddTHH:mm:ss.mmmuuu` (no trailing "Z") for local/non-UTC time,
+ * where:
+ *
+ * * `yyyy` is a, possibly negative, four digit representation of the year,
+ * if the year is in the range -9999 to 9999,
+ * otherwise it is a signed six digit representation of the year.
+ * * `MM` is the month in the range 01 to 12,
+ * * `dd` is the day of the month in the range 01 to 31,
+ * * `HH` are hours in the range 00 to 23,
+ * * `mm` are minutes in the range 00 to 59,
+ * * `ss` are seconds in the range 00 to 59 (no leap seconds),
+ * * `mmm` are milliseconds in the range 000 to 999, and
+ * * `uuu` are microseconds in the range 001 to 999. If [microsecond] equals
+ * 0, then this part is omitted.
+ *
+ * The resulting string can be parsed back using [parse].
+ */
+ String toIso8601String() {
+ String y =
+ (year >= -9999 && year <= 9999) ? _fourDigits(year) : _sixDigits(year);
+ String m = _twoDigits(month);
+ String d = _twoDigits(day);
+ String h = _twoDigits(hour);
+ String min = _twoDigits(minute);
+ String sec = _twoDigits(second);
+ String ms = _threeDigits(millisecond);
+ String us = microsecond == 0 ? "" : _threeDigits(microsecond);
+ if (isUtc) {
+ return "$y-$m-${d}T$h:$min:$sec.$ms${us}Z";
+ } else {
+ return "$y-$m-${d}T$h:$min:$sec.$ms$us";
+ }
+ }
+
+ /**
+ * Returns a new [DateTime] instance with [duration] added to [this].
+ *
+ * ```
+ * var today = new DateTime.now();
+ * var fiftyDaysFromNow = today.add(new Duration(days: 50));
+ * ```
+ *
+ * Notice that the duration being added is actually 50 * 24 * 60 * 60
+ * seconds. If the resulting `DateTime` has a different daylight saving offset
+ * than `this`, then the result won't have the same time-of-day as `this`, and
+ * may not even hit the calendar date 50 days later.
+ *
+ * Be careful when working with dates in local time.
+ */
+ external DateTime add(Duration duration);
+
+ /**
+ * Returns a new [DateTime] instance with [duration] subtracted from [this].
+ *
+ * ```
+ * DateTime today = new DateTime.now();
+ * DateTime fiftyDaysAgo = today.subtract(new Duration(days: 50));
+ * ```
+ *
+ * Notice that the duration being subtracted is actually 50 * 24 * 60 * 60
+ * seconds. If the resulting `DateTime` has a different daylight saving offset
+ * than `this`, then the result won't have the same time-of-day as `this`, and
+ * may not even hit the calendar date 50 days earlier.
+ *
+ * Be careful when working with dates in local time.
+ */
+ external DateTime subtract(Duration duration);
+
+ /**
+ * Returns a [Duration] with the difference between [this] and [other].
+ *
+ * ```
+ * var berlinWallFell = new DateTime.utc(1989, DateTime.november, 9);
+ * var dDay = new DateTime.utc(1944, DateTime.june, 6);
+ *
+ * Duration difference = berlinWallFell.difference(dDay);
+ * assert(difference.inDays == 16592);
+ * ```
+ *
+ * The difference is measured in seconds and fractions of seconds.
+ * The difference above counts the number of fractional seconds between
+ * midnight at the beginning of those dates.
+ * If the dates above had been in local time, not UTC, then the difference
+ * between two midnights may not be a multiple of 24 hours due to daylight
+ * saving differences.
+ *
+ * For example, in Australia, similar code using local time instead of UTC:
+ *
+ * ```
+ * var berlinWallFell = new DateTime(1989, DateTime.november, 9);
+ * var dDay = new DateTime(1944, DateTime.june, 6);
+ * Duration difference = berlinWallFell.difference(dDay);
+ * assert(difference.inDays == 16592);
+ * ```
+ * will fail because the difference is actually 16591 days and 23 hours, and
+ * [Duration.inDays] only returns the number of whole days.
+ */
+ external Duration difference(DateTime other);
+
+ external DateTime._internal(int year, int month, int day, int hour,
+ int minute, int second, int millisecond, int microsecond, bool isUtc);
+
+ external DateTime._now();
+
+ /// Returns the time as value (millisecond or microsecond since epoch), or
+ /// null if the values are out of range.
+ external static int _brokenDownDateToValue(
+ int year,
+ int month,
+ int day,
+ int hour,
+ int minute,
+ int second,
+ int millisecond,
+ int microsecond,
+ bool isUtc);
+
+ /**
+ * The number of milliseconds since
+ * the "Unix epoch" 1970-01-01T00:00:00Z (UTC).
+ *
+ * This value is independent of the time zone.
+ *
+ * This value is at most
+ * 8,640,000,000,000,000ms (100,000,000 days) from the Unix epoch.
+ * In other words: `millisecondsSinceEpoch.abs() <= 8640000000000000`.
+ */
+ external int get millisecondsSinceEpoch;
+
+ /**
+ * The number of microseconds since
+ * the "Unix epoch" 1970-01-01T00:00:00Z (UTC).
+ *
+ * This value is independent of the time zone.
+ *
+ * This value is at most
+ * 8,640,000,000,000,000,000us (100,000,000 days) from the Unix epoch.
+ * In other words: `microsecondsSinceEpoch.abs() <= 8640000000000000000`.
+ *
+ * Note that this value does not fit into 53 bits (the size of a IEEE double).
+ * A JavaScript number is not able to hold this value.
+ */
+ external int get microsecondsSinceEpoch;
+
+ /**
+ * The time zone name.
+ *
+ * This value is provided by the operating system and may be an
+ * abbreviation or a full name.
+ *
+ * In the browser or on Unix-like systems commonly returns abbreviations,
+ * such as "CET" or "CEST". On Windows returns the full name, for example
+ * "Pacific Standard Time".
+ */
+ external String get timeZoneName;
+
+ /**
+ * The time zone offset, which
+ * is the difference between local time and UTC.
+ *
+ * The offset is positive for time zones east of UTC.
+ *
+ * Note, that JavaScript, Python and C return the difference between UTC and
+ * local time. Java, C# and Ruby return the difference between local time and
+ * UTC.
+ */
+ external Duration get timeZoneOffset;
+
+ /**
+ * The year.
+ *
+ * ```
+ * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+ * assert(moonLanding.year == 1969);
+ * ```
+ */
+ external int get year;
+
+ /**
+ * The month [1..12].
+ *
+ * ```
+ * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+ * assert(moonLanding.month == 7);
+ * assert(moonLanding.month == DateTime.july);
+ * ```
+ */
+ external int get month;
+
+ /**
+ * The day of the month [1..31].
+ *
+ * ```
+ * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+ * assert(moonLanding.day == 20);
+ * ```
+ */
+ external int get day;
+
+ /**
+ * The hour of the day, expressed as in a 24-hour clock [0..23].
+ *
+ * ```
+ * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+ * assert(moonLanding.hour == 20);
+ * ```
+ */
+ external int get hour;
+
+ /**
+ * The minute [0...59].
+ *
+ * ```
+ * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+ * assert(moonLanding.minute == 18);
+ * ```
+ */
+ external int get minute;
+
+ /**
+ * The second [0...59].
+ *
+ * ```
+ * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+ * assert(moonLanding.second == 4);
+ * ```
+ */
+ external int get second;
+
+ /**
+ * The millisecond [0...999].
+ *
+ * ```
+ * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+ * assert(moonLanding.millisecond == 0);
+ * ```
+ */
+ external int get millisecond;
+
+ /**
+ * The microsecond [0...999].
+ *
+ * ```
+ * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+ * assert(moonLanding.microsecond == 0);
+ * ```
+ */
+ external int get microsecond;
+
+ /**
+ * The day of the week [monday]..[sunday].
+ *
+ * In accordance with ISO 8601
+ * a week starts with Monday, which has the value 1.
+ *
+ * ```
+ * var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
+ * assert(moonLanding.weekday == 7);
+ * assert(moonLanding.weekday == DateTime.sunday);
+ * ```
+ */
+ external int get weekday;
+
+ /*
+ * date ::= yeardate time_opt timezone_opt
+ * yeardate ::= year colon_opt month colon_opt day
+ * year ::= sign_opt digit{4,6}
+ * colon_opt :: <empty> | ':'
+ * sign ::= '+' | '-'
+ * sign_opt ::= <empty> | sign
+ * month ::= digit{2}
+ * day ::= digit{2}
+ * time_opt ::= <empty> | (' ' | 'T') hour minutes_opt
+ * minutes_opt ::= <empty> | colon_opt digit{2} seconds_opt
+ * seconds_opt ::= <empty> | colon_opt digit{2} millis_opt
+ * micros_opt ::= <empty> | ('.' | ',') digit{1,6}
+ * timezone_opt ::= <empty> | space_opt timezone
+ * space_opt :: ' ' | <empty>
+ * timezone ::= 'z' | 'Z' | sign digit{2} timezonemins_opt
+ * timezonemins_opt ::= <empty> | colon_opt digit{2}
+ */
+ static final RegExp _parseFormat = RegExp(
+ r'^([+-]?\d{4,6})-?(\d\d)-?(\d\d)' // Day part.
+ r'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,6}))?)?)?' // Time part.
+ r'( ?[zZ]| ?([-+])(\d\d)(?::?(\d\d))?)?)?$'); // Timezone part.
+}
diff --git a/sdk_nnbd/lib/core/double.dart b/sdk_nnbd/lib/core/double.dart
new file mode 100644
index 0000000..61191ec
--- /dev/null
+++ b/sdk_nnbd/lib/core/double.dart
@@ -0,0 +1,218 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+// TODO: Convert this abstract class into a concrete class double
+// that uses the patch class functionality to account for the
+// different platform implementations.
+
+/**
+ * A double-precision floating point number.
+ *
+ * Representation of Dart doubles containing double specific constants
+ * and operations and specializations of operations inherited from
+ * [num]. Dart doubles are 64-bit floating-point numbers as specified in the
+ * IEEE 754 standard.
+ *
+ * The [double] type is contagious. Operations on [double]s return
+ * [double] results.
+ *
+ * It is a compile-time error for a class to attempt to extend or implement
+ * double.
+ */
+abstract class double extends num {
+ static const double nan = 0.0 / 0.0;
+ static const double infinity = 1.0 / 0.0;
+ static const double negativeInfinity = -infinity;
+ static const double minPositive = 5e-324;
+ static const double maxFinite = 1.7976931348623157e+308;
+
+ double remainder(num other);
+
+ /** Addition operator. */
+ double operator +(num other);
+
+ /** Subtraction operator. */
+ double operator -(num other);
+
+ /** Multiplication operator. */
+ double operator *(num other);
+
+ double operator %(num other);
+
+ /** Division operator. */
+ double operator /(num other);
+
+ /**
+ * Truncating division operator.
+ *
+ * The result of the truncating division `a ~/ b` is equivalent to
+ * `(a / b).truncate()`.
+ */
+ int operator ~/(num other);
+
+ /** Negate operator. */
+ double operator -();
+
+ /** Returns the absolute value of this [double]. */
+ double abs();
+
+ /**
+ * Returns the sign of the double's numerical value.
+ *
+ * Returns -1.0 if the value is less than zero,
+ * +1.0 if the value is greater than zero,
+ * and the value itself if it is -0.0, 0.0 or NaN.
+ */
+ double get sign;
+
+ /**
+ * Returns the integer closest to `this`.
+ *
+ * Rounds away from zero when there is no closest integer:
+ * `(3.5).round() == 4` and `(-3.5).round() == -4`.
+ *
+ * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+ */
+ int round();
+
+ /**
+ * Returns the greatest integer no greater than `this`.
+ *
+ * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+ */
+ int floor();
+
+ /**
+ * Returns the least integer no smaller than `this`.
+ *
+ * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+ */
+ int ceil();
+
+ /**
+ * Returns the integer obtained by discarding any fractional
+ * digits from `this`.
+ *
+ * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+ */
+ int truncate();
+
+ /**
+ * Returns the integer double value closest to `this`.
+ *
+ * Rounds away from zero when there is no closest integer:
+ * `(3.5).roundToDouble() == 4` and `(-3.5).roundToDouble() == -4`.
+ *
+ * If this is already an integer valued double, including `-0.0`, or it is not
+ * a finite value, the value is returned unmodified.
+ *
+ * For the purpose of rounding, `-0.0` is considered to be below `0.0`,
+ * and `-0.0` is therefore considered closer to negative numbers than `0.0`.
+ * This means that for a value, `d` in the range `-0.5 < d < 0.0`,
+ * the result is `-0.0`.
+ */
+ double roundToDouble();
+
+ /**
+ * Returns the greatest integer double value no greater than `this`.
+ *
+ * If this is already an integer valued double, including `-0.0`, or it is not
+ * a finite value, the value is returned unmodified.
+ *
+ * For the purpose of rounding, `-0.0` is considered to be below `0.0`.
+ * A number `d` in the range `0.0 < d < 1.0` will return `0.0`.
+ */
+ double floorToDouble();
+
+ /**
+ * Returns the least integer double value no smaller than `this`.
+ *
+ * If this is already an integer valued double, including `-0.0`, or it is not
+ * a finite value, the value is returned unmodified.
+ *
+ * For the purpose of rounding, `-0.0` is considered to be below `0.0`.
+ * A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`.
+ */
+ double ceilToDouble();
+
+ /**
+ * Returns the integer double value obtained by discarding any fractional
+ * digits from `this`.
+ *
+ * If this is already an integer valued double, including `-0.0`, or it is not
+ * a finite value, the value is returned unmodified.
+ *
+ * For the purpose of rounding, `-0.0` is considered to be below `0.0`.
+ * A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`, and
+ * in the range `0.0 < d < 1.0` it will return 0.0.
+ */
+ double truncateToDouble();
+
+ /**
+ * Provide a representation of this [double] value.
+ *
+ * The representation is a number literal such that the closest double value
+ * to the representation's mathematical value is this [double].
+ *
+ * Returns "NaN" for the Not-a-Number value.
+ * Returns "Infinity" and "-Infinity" for positive and negative Infinity.
+ * Returns "-0.0" for negative zero.
+ *
+ * For all doubles, `d`, converting to a string and parsing the string back
+ * gives the same value again: `d == double.parse(d.toString())` (except when
+ * `d` is NaN).
+ */
+ String toString();
+
+ /**
+ * Parse [source] as an double literal and return its value.
+ *
+ * Accepts an optional sign (`+` or `-`) followed by either the characters
+ * "Infinity", the characters "NaN" or a floating-point representation.
+ * A floating-point representation is composed of a mantissa and an optional
+ * exponent part. The mantissa is either a decimal point (`.`) followed by a
+ * sequence of (decimal) digits, or a sequence of digits
+ * optionally followed by a decimal point and optionally more digits. The
+ * (optional) exponent part consists of the character "e" or "E", an optional
+ * sign, and one or more digits.
+ * The [source] must not be `null`.
+ *
+ * Leading and trailing whitespace is ignored.
+ *
+ * If the [source] string is not a valid double literal, the [onError]
+ * is called with the [source] as argument, and its return value is
+ * used instead. If no `onError` is provided, a [FormatException]
+ * is thrown instead.
+ *
+ * The [onError] function is only invoked if [source] is a [String] with an
+ * invalid format. It is not invoked if [source] is `null`.
+ *
+ * Examples of accepted strings:
+ *
+ * "3.14"
+ * " 3.14 \xA0"
+ * "0."
+ * ".0"
+ * "-1.e3"
+ * "1234E+7"
+ * "+.12e-9"
+ * "-NaN"
+ *
+ * The [onError] parameter is deprecated and will be removed.
+ * Instead of `double.parse(string, (string) { ... })`,
+ * you should use `double.tryParse(string) ?? (...)`.
+ */
+ external static double parse(String source,
+ [@deprecated double onError(String source)]);
+
+ /**
+ * Parse [source] as an double literal and return its value.
+ *
+ * Like [parse] except that this function returns `null` for invalid inputs
+ * instead of throwing, and the [source] must still not be `null`.
+ */
+ external static double tryParse(String source);
+}
diff --git a/sdk_nnbd/lib/core/duration.dart b/sdk_nnbd/lib/core/duration.dart
new file mode 100644
index 0000000..914f05a
--- /dev/null
+++ b/sdk_nnbd/lib/core/duration.dart
@@ -0,0 +1,293 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A span of time, such as 27 days, 4 hours, 12 minutes, and 3 seconds.
+ *
+ * A `Duration` represents a difference from one point in time to another. The
+ * duration may be "negative" if the difference is from a later time to an
+ * earlier.
+ *
+ * Durations are context independent. For example, a duration of 2 days is
+ * always 48 hours, even when it is added to a `DateTime` just when the
+ * time zone is about to do a daylight-savings switch. (See [DateTime.add]).
+ *
+ * Despite the same name, a `Duration` object does not implement "Durations"
+ * as specified by ISO 8601. In particular, a duration object does not keep
+ * track of the individually provided members (such as "days" or "hours"), but
+ * only uses these arguments to compute the length of the corresponding time
+ * interval.
+ *
+ * To create a new Duration object, use this class's single constructor
+ * giving the appropriate arguments:
+ * ```dart
+ * Duration fastestMarathon = new Duration(hours:2, minutes:3, seconds:2);
+ * ```
+ * The [Duration] is the sum of all individual parts.
+ * This means that individual parts can be larger than the next-bigger unit.
+ * For example, [inMinutes] can be greater than 59.
+ * ```dart
+ * assert(fastestMarathon.inMinutes == 123);
+ * ```
+ * All individual parts are allowed to be negative.
+ *
+ * Use one of the properties, such as [inDays],
+ * to retrieve the integer value of the Duration in the specified time unit.
+ * Note that the returned value is rounded down.
+ * For example,
+ * ```dart
+ * Duration aLongWeekend = new Duration(hours:88);
+ * assert(aLongWeekend.inDays == 3);
+ * ```
+ * This class provides a collection of arithmetic
+ * and comparison operators,
+ * plus a set of constants useful for converting time units.
+ *
+ * See [DateTime] to represent a point in time.
+ * See [Stopwatch] to measure time-spans.
+ */
+class Duration implements Comparable<Duration> {
+ static const int microsecondsPerMillisecond = 1000;
+ static const int millisecondsPerSecond = 1000;
+ static const int secondsPerMinute = 60;
+ static const int minutesPerHour = 60;
+ static const int hoursPerDay = 24;
+
+ static const int microsecondsPerSecond =
+ microsecondsPerMillisecond * millisecondsPerSecond;
+ static const int microsecondsPerMinute =
+ microsecondsPerSecond * secondsPerMinute;
+ static const int microsecondsPerHour = microsecondsPerMinute * minutesPerHour;
+ static const int microsecondsPerDay = microsecondsPerHour * hoursPerDay;
+
+ static const int millisecondsPerMinute =
+ millisecondsPerSecond * secondsPerMinute;
+ static const int millisecondsPerHour = millisecondsPerMinute * minutesPerHour;
+ static const int millisecondsPerDay = millisecondsPerHour * hoursPerDay;
+
+ static const int secondsPerHour = secondsPerMinute * minutesPerHour;
+ static const int secondsPerDay = secondsPerHour * hoursPerDay;
+
+ static const int minutesPerDay = minutesPerHour * hoursPerDay;
+
+ static const Duration zero = Duration(seconds: 0);
+
+ /*
+ * The value of this Duration object in microseconds.
+ */
+ final int _duration;
+
+ /**
+ * Creates a new Duration object whose value
+ * is the sum of all individual parts.
+ *
+ * Individual parts can be larger than the next-bigger unit.
+ * For example, [hours] can be greater than 23.
+ *
+ * All individual parts are allowed to be negative.
+ * All arguments are 0 by default.
+ */
+ const Duration(
+ {int days = 0,
+ int hours = 0,
+ int minutes = 0,
+ int seconds = 0,
+ int milliseconds = 0,
+ int microseconds = 0})
+ : this._microseconds(microsecondsPerDay * days +
+ microsecondsPerHour * hours +
+ microsecondsPerMinute * minutes +
+ microsecondsPerSecond * seconds +
+ microsecondsPerMillisecond * milliseconds +
+ microseconds);
+
+ // Fast path internal direct constructor to avoids the optional arguments and
+ // [_microseconds] recomputation.
+ const Duration._microseconds(this._duration);
+
+ /**
+ * Adds this Duration and [other] and
+ * returns the sum as a new Duration object.
+ */
+ Duration operator +(Duration other) {
+ return Duration._microseconds(_duration + other._duration);
+ }
+
+ /**
+ * Subtracts [other] from this Duration and
+ * returns the difference as a new Duration object.
+ */
+ Duration operator -(Duration other) {
+ return Duration._microseconds(_duration - other._duration);
+ }
+
+ /**
+ * Multiplies this Duration by the given [factor] and returns the result
+ * as a new Duration object.
+ *
+ * Note that when [factor] is a double, and the duration is greater than
+ * 53 bits, precision is lost because of double-precision arithmetic.
+ */
+ Duration operator *(num factor) {
+ return Duration._microseconds((_duration * factor).round());
+ }
+
+ /**
+ * Divides this Duration by the given [quotient] and returns the truncated
+ * result as a new Duration object.
+ *
+ * Throws an [IntegerDivisionByZeroException] if [quotient] is `0`.
+ */
+ Duration operator ~/(int quotient) {
+ // By doing the check here instead of relying on "~/" below we get the
+ // exception even with dart2js.
+ if (quotient == 0) throw IntegerDivisionByZeroException();
+ return Duration._microseconds(_duration ~/ quotient);
+ }
+
+ /**
+ * Returns `true` if the value of this Duration
+ * is less than the value of [other].
+ */
+ bool operator <(Duration other) => this._duration < other._duration;
+
+ /**
+ * Returns `true` if the value of this Duration
+ * is greater than the value of [other].
+ */
+ bool operator >(Duration other) => this._duration > other._duration;
+
+ /**
+ * Returns `true` if the value of this Duration
+ * is less than or equal to the value of [other].
+ */
+ bool operator <=(Duration other) => this._duration <= other._duration;
+
+ /**
+ * Returns `true` if the value of this Duration
+ * is greater than or equal to the value of [other].
+ */
+ bool operator >=(Duration other) => this._duration >= other._duration;
+
+ /**
+ * Returns the number of whole days spanned by this Duration.
+ */
+ int get inDays => _duration ~/ Duration.microsecondsPerDay;
+
+ /**
+ * Returns the number of whole hours spanned by this Duration.
+ *
+ * The returned value can be greater than 23.
+ */
+ int get inHours => _duration ~/ Duration.microsecondsPerHour;
+
+ /**
+ * Returns the number of whole minutes spanned by this Duration.
+ *
+ * The returned value can be greater than 59.
+ */
+ int get inMinutes => _duration ~/ Duration.microsecondsPerMinute;
+
+ /**
+ * Returns the number of whole seconds spanned by this Duration.
+ *
+ * The returned value can be greater than 59.
+ */
+ int get inSeconds => _duration ~/ Duration.microsecondsPerSecond;
+
+ /**
+ * Returns number of whole milliseconds spanned by this Duration.
+ *
+ * The returned value can be greater than 999.
+ */
+ int get inMilliseconds => _duration ~/ Duration.microsecondsPerMillisecond;
+
+ /**
+ * Returns number of whole microseconds spanned by this Duration.
+ */
+ int get inMicroseconds => _duration;
+
+ /**
+ * Returns `true` if this [Duration] has the same value as [other].
+ */
+ bool operator ==(dynamic other) =>
+ other is Duration && _duration == other.inMicroseconds;
+
+ int get hashCode => _duration.hashCode;
+
+ /**
+ * Compares this [Duration] to [other], returning zero if the values are equal.
+ *
+ * Returns a negative integer if this `Duration` is shorter than
+ * [other], or a positive integer if it is longer.
+ *
+ * A negative `Duration` is always considered shorter than a positive one.
+ *
+ * It is always the case that `duration1.compareTo(duration2) < 0` iff
+ * `(someDate + duration1).compareTo(someDate + duration2) < 0`.
+ */
+ int compareTo(Duration other) => _duration.compareTo(other._duration);
+
+ /**
+ * Returns a string representation of this `Duration`.
+ *
+ * Returns a string with hours, minutes, seconds, and microseconds, in the
+ * following format: `HH:MM:SS.mmmmmm`. For example,
+ *
+ * var d = new Duration(days:1, hours:1, minutes:33, microseconds: 500);
+ * d.toString(); // "25:33:00.000500"
+ */
+ String toString() {
+ String sixDigits(int n) {
+ if (n >= 100000) return "$n";
+ if (n >= 10000) return "0$n";
+ if (n >= 1000) return "00$n";
+ if (n >= 100) return "000$n";
+ if (n >= 10) return "0000$n";
+ return "00000$n";
+ }
+
+ String twoDigits(int n) {
+ if (n >= 10) return "$n";
+ return "0$n";
+ }
+
+ if (inMicroseconds < 0) {
+ return "-${-this}";
+ }
+ String twoDigitMinutes = twoDigits(inMinutes.remainder(minutesPerHour));
+ String twoDigitSeconds = twoDigits(inSeconds.remainder(secondsPerMinute));
+ String sixDigitUs =
+ sixDigits(inMicroseconds.remainder(microsecondsPerSecond));
+ return "$inHours:$twoDigitMinutes:$twoDigitSeconds.$sixDigitUs";
+ }
+
+ /**
+ * Returns whether this `Duration` is negative.
+ *
+ * A negative `Duration` represents the difference from a later time to an
+ * earlier time.
+ */
+ bool get isNegative => _duration < 0;
+
+ /**
+ * Returns a new `Duration` representing the absolute value of this
+ * `Duration`.
+ *
+ * The returned `Duration` has the same length as this one, but is always
+ * positive.
+ */
+ Duration abs() => Duration._microseconds(_duration.abs());
+
+ /**
+ * Returns a new `Duration` representing this `Duration` negated.
+ *
+ * The returned `Duration` has the same length as this one, but will have the
+ * opposite sign of this one.
+ */
+ // Using subtraction helps dart2js avoid negative zeros.
+ Duration operator -() => Duration._microseconds(0 - _duration);
+}
diff --git a/sdk_nnbd/lib/core/errors.dart b/sdk_nnbd/lib/core/errors.dart
new file mode 100644
index 0000000..53f3d35
--- /dev/null
+++ b/sdk_nnbd/lib/core/errors.dart
@@ -0,0 +1,588 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * Error objects thrown in the case of a program failure.
+ *
+ * An `Error` object represents a program failure that the programmer
+ * should have avoided.
+ *
+ * Examples include calling a function with invalid arguments,
+ * or even with the wrong number of arguments,
+ * or calling it at a time when it is not allowed.
+ *
+ * These are not errors that a caller should expect or catch -
+ * if they occur, the program is erroneous,
+ * and terminating the program may be the safest response.
+ *
+ * When deciding that a function throws an error,
+ * the conditions where it happens should be clearly described,
+ * and they should be detectable and predictable,
+ * so the programmer using the function can avoid triggering the error.
+ *
+ * Such descriptions often uses words like
+ * "must" or "must not" to describe the condition,
+ * and if you see words like that in a function's documentation,
+ * then not satisfying the requirement
+ * is very likely to cause an error to be thrown.
+ *
+ * Example (from [String.contains]):
+ *
+ * `startIndex` must not be negative or greater than `length`.
+ *
+ * In this case, an error will be thrown if `startIndex` is negative
+ * or too large.
+ *
+ * If the conditions are not detectable before calling a function,
+ * the called function should not throw an `Error`.
+ * It may still throw a value,
+ * but the caller will have to catch the thrown value,
+ * effectively making it an alternative result rather than an error.
+ * The thrown object can choose to implement [Exception]
+ * to document that it represents an exceptional, but not erroneous, occurrence,
+ * but it has no other effect than documentation.
+ *
+ * All non-`null` values can be thrown in Dart.
+ * Objects extending `Error` are handled specially:
+ * The first time they are thrown,
+ * the stack trace at the throw point is recorded
+ * and stored in the error object.
+ * It can be retrieved using the [stackTrace] getter.
+ * An error object that merely implements `Error`, and doesn't extend it,
+ * will not store the stack trace automatically.
+ *
+ * Error objects are also used for system wide failures
+ * like stack overflow or an out-of-memory situation.
+ *
+ * Since errors are not created to be caught,
+ * there is no need for subclasses to distinguish the errors.
+ * Instead subclasses have been created in order to make groups
+ * of related errors easy to create with consistent error messages.
+ * For example, the [String.contains] method will use a [RangeError]
+ * if its `startIndex` isn't in the range `0..length`,
+ * which is easily created by `new RangeError.range(startIndex, 0, length)`.
+ */
+class Error {
+ Error(); // Prevent use as mixin.
+
+ /**
+ * Safely convert a value to a [String] description.
+ *
+ * The conversion is guaranteed to not throw, so it won't use the object's
+ * toString method.
+ */
+ static String safeToString(Object object) {
+ if (object is num || object is bool || null == object) {
+ return object.toString();
+ }
+ if (object is String) {
+ return _stringToSafeString(object);
+ }
+ return _objectToString(object);
+ }
+
+ /** Convert string to a valid string literal with no control characters. */
+ external static String _stringToSafeString(String string);
+
+ external static String _objectToString(Object object);
+
+ external StackTrace get stackTrace;
+}
+
+/**
+ * Error thrown by the runtime system when an assert statement fails.
+ */
+class AssertionError extends Error {
+ /** Message describing the assertion error. */
+ final Object message;
+ AssertionError([this.message]);
+ String toString() => "Assertion failed";
+}
+
+/**
+ * Error thrown by the runtime system when a type assertion fails.
+ */
+class TypeError extends AssertionError {}
+
+/**
+ * Error thrown by the runtime system when a cast operation fails.
+ */
+class CastError extends Error {}
+
+/**
+ * Error thrown when attempting to throw [:null:].
+ */
+class NullThrownError extends Error {
+ @pragma("vm:entry-point")
+ NullThrownError();
+ String toString() => "Throw of null.";
+}
+
+/**
+ * Error thrown when a function is passed an unacceptable argument.
+ */
+class ArgumentError extends Error {
+ /** Whether value was provided. */
+ final bool _hasValue;
+ /** The invalid value. */
+ final invalidValue;
+ /** Name of the invalid argument, if available. */
+ final String name;
+ /** Message describing the problem. */
+ final message;
+
+ /**
+ * The [message] describes the erroneous argument.
+ *
+ * Existing code may be using `message` to hold the invalid value.
+ * If the `message` is not a [String], it is assumed to be a value instead
+ * of a message.
+ */
+ @pragma("vm:entry-point")
+ ArgumentError([this.message])
+ : invalidValue = null,
+ _hasValue = false,
+ name = null;
+
+ /**
+ * Creates error containing the invalid [value].
+ *
+ * A message is built by suffixing the [message] argument with
+ * the [name] argument (if provided) and the value. Example
+ *
+ * "Invalid argument (foo): null"
+ *
+ * The `name` should match the argument name of the function, but if
+ * the function is a method implementing an interface, and its argument
+ * names differ from the interface, it might be more useful to use the
+ * interface method's argument name (or just rename arguments to match).
+ */
+ @pragma("vm:entry-point")
+ ArgumentError.value(value, [this.name, this.message])
+ : invalidValue = value,
+ _hasValue = true;
+
+ /**
+ * Create an argument error for a `null` argument that must not be `null`.
+ */
+ ArgumentError.notNull([this.name])
+ : _hasValue = false,
+ message = "Must not be null",
+ invalidValue = null;
+
+ /**
+ * Throws if [argument] is `null`.
+ */
+ @Since("2.1")
+ static void checkNotNull(Object argument, [String name]) {
+ if (argument == null) throw ArgumentError.notNull(name);
+ }
+
+ // Helper functions for toString overridden in subclasses.
+ String get _errorName => "Invalid argument${!_hasValue ? "(s)" : ""}";
+ String get _errorExplanation => "";
+
+ String toString() {
+ String nameString = "";
+ if (name != null) {
+ nameString = " ($name)";
+ }
+ var message = (this.message == null) ? "" : ": ${this.message}";
+ String prefix = "$_errorName$nameString$message";
+ if (!_hasValue) return prefix;
+ // If we know the invalid value, we can try to describe the problem.
+ String explanation = _errorExplanation;
+ String errorValue = Error.safeToString(invalidValue);
+ return "$prefix$explanation: $errorValue";
+ }
+}
+
+/**
+ * Error thrown due to an index being outside a valid range.
+ */
+class RangeError extends ArgumentError {
+ /** The minimum value that [value] is allowed to assume. */
+ final num start;
+ /** The maximum value that [value] is allowed to assume. */
+ final num end;
+
+ // TODO(lrn): This constructor should be called only with string values.
+ // It currently isn't in all cases.
+ /**
+ * Create a new [RangeError] with the given [message].
+ */
+ @pragma("vm:entry-point")
+ RangeError(var message)
+ : start = null,
+ end = null,
+ super(message);
+
+ /**
+ * Create a new [RangeError] with a message for the given [value].
+ *
+ * An optional [name] can specify the argument name that has the
+ * invalid value, and the [message] can override the default error
+ * description.
+ */
+ RangeError.value(num value, [String name, String message])
+ : start = null,
+ end = null,
+ super.value(
+ value, name, (message != null) ? message : "Value not in range");
+
+ /**
+ * Create a new [RangeError] for a value being outside the valid range.
+ *
+ * The allowed range is from [minValue] to [maxValue], inclusive.
+ * If `minValue` or `maxValue` are `null`, the range is infinite in
+ * that direction.
+ *
+ * For a range from 0 to the length of something, end exclusive, use
+ * [RangeError.index].
+ *
+ * An optional [name] can specify the argument name that has the
+ * invalid value, and the [message] can override the default error
+ * description.
+ */
+ @pragma("vm:entry-point")
+ RangeError.range(num invalidValue, int minValue, int maxValue,
+ [String name, String message])
+ : start = minValue,
+ end = maxValue,
+ super.value(
+ invalidValue, name, (message != null) ? message : "Invalid value");
+
+ /**
+ * Creates a new [RangeError] stating that [index] is not a valid index
+ * into [indexable].
+ *
+ * An optional [name] can specify the argument name that has the
+ * invalid value, and the [message] can override the default error
+ * description.
+ *
+ * The [length] is the length of [indexable] at the time of the error.
+ * If `length` is omitted, it defaults to `indexable.length`.
+ */
+ factory RangeError.index(int index, dynamic indexable,
+ [String name, String message, int length]) = IndexError;
+
+ /**
+ * Check that a [value] lies in a specific interval.
+ *
+ * Throws if [value] is not in the interval.
+ * The interval is from [minValue] to [maxValue], both inclusive.
+ */
+ static void checkValueInInterval(int value, int minValue, int maxValue,
+ [String name, String message]) {
+ if (value < minValue || value > maxValue) {
+ throw RangeError.range(value, minValue, maxValue, name, message);
+ }
+ }
+
+ /**
+ * Check that a value is a valid index into an indexable object.
+ *
+ * Throws if [index] is not a valid index into [indexable].
+ *
+ * An indexable object is one that has a `length` and a and index-operator
+ * `[]` that accepts an index if `0 <= index < length`.
+ *
+ * If [length] is provided, it is used as the length of the indexable object,
+ * otherwise the length is found as `indexable.length`.
+ */
+ static void checkValidIndex(int index, dynamic indexable,
+ [String name, int length, String message]) {
+ length ??= indexable.length;
+ // Comparing with `0` as receiver produces better dart2js type inference.
+ if (0 > index || index >= length) {
+ name ??= "index";
+ throw RangeError.index(index, indexable, name, message, length);
+ }
+ }
+
+ /**
+ * Check that a range represents a slice of an indexable object.
+ *
+ * Throws if the range is not valid for an indexable object with
+ * the given [length].
+ * A range is valid for an indexable object with a given [length]
+ *
+ * if `0 <= [start] <= [end] <= [length]`.
+ * An `end` of `null` is considered equivalent to `length`.
+ *
+ * The [startName] and [endName] defaults to `"start"` and `"end"`,
+ * respectively.
+ *
+ * Returns the actual `end` value, which is `length` if `end` is `null`,
+ * and `end` otherwise.
+ */
+ static int checkValidRange(int start, int end, int length,
+ [String startName, String endName, String message]) {
+ // Comparing with `0` as receiver produces better dart2js type inference.
+ // Ditto `start > end` below.
+ if (0 > start || start > length) {
+ startName ??= "start";
+ throw RangeError.range(start, 0, length, startName, message);
+ }
+ if (end != null) {
+ if (start > end || end > length) {
+ endName ??= "end";
+ throw RangeError.range(end, start, length, endName, message);
+ }
+ return end;
+ }
+ return length;
+ }
+
+ /**
+ * Check that an integer value isn't negative.
+ *
+ * Throws if the value is negative.
+ */
+ static void checkNotNegative(int value, [String name, String message]) {
+ if (value < 0) throw RangeError.range(value, 0, null, name, message);
+ }
+
+ String get _errorName => "RangeError";
+ String get _errorExplanation {
+ assert(_hasValue);
+ String explanation = "";
+ if (start == null) {
+ if (end != null) {
+ explanation = ": Not less than or equal to $end";
+ }
+ // If both are null, we don't add a description of the limits.
+ } else if (end == null) {
+ explanation = ": Not greater than or equal to $start";
+ } else if (end > start) {
+ explanation = ": Not in range $start..$end, inclusive";
+ } else if (end < start) {
+ explanation = ": Valid value range is empty";
+ } else {
+ // end == start.
+ explanation = ": Only valid value is $start";
+ }
+ return explanation;
+ }
+}
+
+/**
+ * A specialized [RangeError] used when an index is not in the range
+ * `0..indexable.length-1`.
+ *
+ * Also contains the indexable object, its length at the time of the error,
+ * and the invalid index itself.
+ */
+class IndexError extends ArgumentError implements RangeError {
+ /** The indexable object that [invalidValue] was not a valid index into. */
+ final indexable;
+ /** The length of [indexable] at the time of the error. */
+ final int length;
+
+ /**
+ * Creates a new [IndexError] stating that [invalidValue] is not a valid index
+ * into [indexable].
+ *
+ * The [length] is the length of [indexable] at the time of the error.
+ * If `length` is omitted, it defaults to `indexable.length`.
+ *
+ * The message is used as part of the string representation of the error.
+ */
+ IndexError(int invalidValue, dynamic indexable,
+ [String name, String message, int length])
+ : this.indexable = indexable,
+ this.length = length ?? indexable.length,
+ super.value(invalidValue, name,
+ (message != null) ? message : "Index out of range");
+
+ // Getters inherited from RangeError.
+ int get start => 0;
+ int get end => length - 1;
+
+ String get _errorName => "RangeError";
+ String get _errorExplanation {
+ assert(_hasValue);
+ int invalidValue = this.invalidValue;
+ if (invalidValue < 0) {
+ return ": index must not be negative";
+ }
+ if (length == 0) {
+ return ": no indices are valid";
+ }
+ return ": index should be less than $length";
+ }
+}
+
+/**
+ * Error thrown when control reaches the end of a switch case.
+ *
+ * The Dart specification requires this error to be thrown when
+ * control reaches the end of a switch case (except the last case
+ * of a switch) without meeting a break or similar end of the control
+ * flow.
+ */
+class FallThroughError extends Error {
+ FallThroughError();
+ @pragma("vm:entry-point")
+ external FallThroughError._create(String url, int line);
+
+ external String toString();
+}
+
+/**
+ * Error thrown when trying to instantiate an abstract class.
+ */
+class AbstractClassInstantiationError extends Error {
+ final String _className;
+ AbstractClassInstantiationError(String className) : _className = className;
+
+ external String toString();
+}
+
+/**
+ * Error thrown by the default implementation of [:noSuchMethod:] on [Object].
+ */
+class NoSuchMethodError extends Error {
+ /**
+ * Create a [NoSuchMethodError] corresponding to a failed method call.
+ *
+ * The [receiver] is the receiver of the method call.
+ * That is, the object on which the method was attempted called.
+ *
+ * The [invocation] represents the method call that failed. It
+ * should not be `null`.
+ */
+ external NoSuchMethodError.withInvocation(
+ Object receiver, Invocation invocation);
+
+ // Deprecated constructor to be removed after dart2js updates to the above.
+ /**
+ * Create a [NoSuchMethodError] corresponding to a failed method call.
+ *
+ * The [receiver] is the receiver of the method call.
+ * That is, the object on which the method was attempted called.
+ * If the receiver is `null`, it is interpreted as a call to a top-level
+ * function of a library.
+ *
+ * The [memberName] is a [Symbol] representing the name of the called method
+ * or accessor. It should not be `null`.
+ *
+ * The [positionalArguments] is a list of the positional arguments that the
+ * method was called with. If `null`, it is considered equivalent to the
+ * empty list.
+ *
+ * The [namedArguments] is a map from [Symbol]s to the values of named
+ * arguments that the method was called with.
+ *
+ * This constructor does not handle type arguments.
+ * To include type variables, create an [Invocation] and use
+ * [NoSuchMethodError.withInvocation].
+ */
+ @Deprecated("Use NoSuchMethod.withInvocation instead")
+ external NoSuchMethodError(Object receiver, Symbol memberName,
+ List positionalArguments, Map<Symbol, dynamic> namedArguments,
+ [@deprecated List existingArgumentNames]);
+
+ external String toString();
+}
+
+/**
+ * The operation was not allowed by the object.
+ *
+ * This [Error] is thrown when an instance cannot implement one of the methods
+ * in its signature.
+ */
+@pragma("vm:entry-point")
+class UnsupportedError extends Error {
+ final String message;
+ @pragma("vm:entry-point")
+ UnsupportedError(this.message);
+ String toString() => "Unsupported operation: $message";
+}
+
+/**
+ * Thrown by operations that have not been implemented yet.
+ *
+ * This [Error] is thrown by unfinished code that hasn't yet implemented
+ * all the features it needs.
+ *
+ * If a class is not intending to implement the feature, it should throw
+ * an [UnsupportedError] instead. This error is only intended for
+ * use during development.
+ */
+class UnimplementedError extends Error implements UnsupportedError {
+ final String message;
+ UnimplementedError([this.message]);
+ String toString() => (this.message != null
+ ? "UnimplementedError: $message"
+ : "UnimplementedError");
+}
+
+/**
+ * The operation was not allowed by the current state of the object.
+ *
+ * This is a generic error used for a variety of different erroneous
+ * actions. The message should be descriptive.
+ */
+class StateError extends Error {
+ final String message;
+ StateError(this.message);
+ String toString() => "Bad state: $message";
+}
+
+/**
+ * Error occurring when a collection is modified during iteration.
+ *
+ * Some modifications may be allowed for some collections, so each collection
+ * ([Iterable] or similar collection of values) should declare which operations
+ * are allowed during an iteration.
+ */
+class ConcurrentModificationError extends Error {
+ /** The object that was modified in an incompatible way. */
+ final Object modifiedObject;
+
+ ConcurrentModificationError([this.modifiedObject]);
+
+ String toString() {
+ if (modifiedObject == null) {
+ return "Concurrent modification during iteration.";
+ }
+ return "Concurrent modification during iteration: "
+ "${Error.safeToString(modifiedObject)}.";
+ }
+}
+
+class OutOfMemoryError implements Error {
+ @pragma("vm:entry-point")
+ const OutOfMemoryError();
+ String toString() => "Out of Memory";
+
+ StackTrace get stackTrace => null;
+}
+
+class StackOverflowError implements Error {
+ @pragma("vm:entry-point")
+ const StackOverflowError();
+ String toString() => "Stack Overflow";
+
+ StackTrace get stackTrace => null;
+}
+
+/**
+ * Error thrown when a lazily initialized variable cannot be initialized.
+ *
+ * A static/library variable with an initializer expression is initialized
+ * the first time it is read. If evaluating the initializer expression causes
+ * another read of the variable, this error is thrown.
+ */
+class CyclicInitializationError extends Error {
+ final String variableName;
+ @pragma("vm:entry-point")
+ CyclicInitializationError([this.variableName]);
+ String toString() => variableName == null
+ ? "Reading static variable during its initialization"
+ : "Reading static variable '$variableName' during its initialization";
+}
diff --git a/sdk_nnbd/lib/core/exceptions.dart b/sdk_nnbd/lib/core/exceptions.dart
new file mode 100644
index 0000000..2e137e5
--- /dev/null
+++ b/sdk_nnbd/lib/core/exceptions.dart
@@ -0,0 +1,184 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+// Exceptions are thrown either by the VM or from Dart code.
+
+/**
+ * A marker interface implemented by all core library exceptions.
+ *
+ * An [Exception] is intended to convey information to the user about a failure,
+ * so that the error can be addressed programmatically. It is intended to be
+ * caught, and it should contain useful data fields.
+ *
+ * Creating instances of [Exception] directly with [:new Exception("message"):]
+ * is discouraged, and only included as a temporary measure during development,
+ * until the actual exceptions used by a library are done.
+ */
+abstract class Exception {
+ factory Exception([var message]) => _Exception(message);
+}
+
+/** Default implementation of [Exception] which carries a message. */
+class _Exception implements Exception {
+ final message;
+
+ _Exception([this.message]);
+
+ String toString() {
+ if (message == null) return "Exception";
+ return "Exception: $message";
+ }
+}
+
+/**
+ * Exception thrown when a string or some other data does not have an expected
+ * format and cannot be parsed or processed.
+ */
+class FormatException implements Exception {
+ /**
+ * A message describing the format error.
+ */
+ final String message;
+
+ /**
+ * The actual source input which caused the error.
+ *
+ * This is usually a [String], but can be other types too.
+ * If it is a string, parts of it may be included in the [toString] message.
+ *
+ * The source is `null` if omitted or unknown.
+ */
+ final source;
+
+ /**
+ * The offset in [source] where the error was detected.
+ *
+ * A zero-based offset into the source that marks the format error causing
+ * this exception to be created. If `source` is a string, this should be a
+ * string index in the range `0 <= offset <= source.length`.
+ *
+ * If input is a string, the [toString] method may represent this offset as
+ * a line and character position. The offset should be inside the string,
+ * or at the end of the string.
+ *
+ * May be omitted. If present, [source] should also be present if possible.
+ */
+ final int offset;
+
+ /**
+ * Creates a new FormatException with an optional error [message].
+ *
+ * Optionally also supply the actual [source] with the incorrect format,
+ * and the [offset] in the format where a problem was detected.
+ */
+ @pragma("vm:entry-point")
+ const FormatException([this.message = "", this.source, this.offset]);
+
+ /**
+ * Returns a description of the format exception.
+ *
+ * The description always contains the [message].
+ *
+ * If [source] is present and is a string, the description will contain
+ * (at least a part of) the source.
+ * If [offset] is also provided, the part of the source included will
+ * contain that offset, and the offset will be marked.
+ *
+ * If the source is a string and it contains a line break before offset,
+ * only the line containing offset will be included, and its line number
+ * will also be part of the description. Line and character offsets are
+ * 1-based.
+ */
+ String toString() {
+ String report = "FormatException";
+ if (message != null && "" != message) {
+ report = "$report: $message";
+ }
+ int offset = this.offset;
+ Object objectSource = this.source;
+ if (objectSource is String) {
+ String source = objectSource;
+ if (offset != null && (offset < 0 || offset > source.length)) {
+ offset = null;
+ }
+ // Source is string and offset is null or valid.
+ if (offset == null) {
+ if (source.length > 78) {
+ source = source.substring(0, 75) + "...";
+ }
+ return "$report\n$source";
+ }
+ int lineNum = 1;
+ int lineStart = 0;
+ bool previousCharWasCR = false;
+ for (int i = 0; i < offset; i++) {
+ int char = source.codeUnitAt(i);
+ if (char == 0x0a) {
+ if (lineStart != i || !previousCharWasCR) {
+ lineNum++;
+ }
+ lineStart = i + 1;
+ previousCharWasCR = false;
+ } else if (char == 0x0d) {
+ lineNum++;
+ lineStart = i + 1;
+ previousCharWasCR = true;
+ }
+ }
+ if (lineNum > 1) {
+ report += " (at line $lineNum, character ${offset - lineStart + 1})\n";
+ } else {
+ report += " (at character ${offset + 1})\n";
+ }
+ int lineEnd = source.length;
+ for (int i = offset; i < source.length; i++) {
+ int char = source.codeUnitAt(i);
+ if (char == 0x0a || char == 0x0d) {
+ lineEnd = i;
+ break;
+ }
+ }
+ int length = lineEnd - lineStart;
+ int start = lineStart;
+ int end = lineEnd;
+ String prefix = "";
+ String postfix = "";
+ if (length > 78) {
+ // Can't show entire line. Try to anchor at the nearest end, if
+ // one is within reach.
+ int index = offset - lineStart;
+ if (index < 75) {
+ end = start + 75;
+ postfix = "...";
+ } else if (end - offset < 75) {
+ start = end - 75;
+ prefix = "...";
+ } else {
+ // Neither end is near, just pick an area around the offset.
+ start = offset - 36;
+ end = offset + 36;
+ prefix = postfix = "...";
+ }
+ }
+ String slice = source.substring(start, end);
+ int markOffset = offset - start + prefix.length;
+ return "$report$prefix$slice$postfix\n${" " * markOffset}^\n";
+ } else {
+ // The source is not a string.
+ if (offset != null) {
+ report += " (at offset $offset)";
+ }
+ return report;
+ }
+ }
+}
+
+// Exception thrown when doing integer division with a zero divisor.
+class IntegerDivisionByZeroException implements Exception {
+ @pragma("vm:entry-point")
+ const IntegerDivisionByZeroException();
+ String toString() => "IntegerDivisionByZeroException";
+}
diff --git a/sdk_nnbd/lib/core/expando.dart b/sdk_nnbd/lib/core/expando.dart
new file mode 100644
index 0000000..92cf90c
--- /dev/null
+++ b/sdk_nnbd/lib/core/expando.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An [Expando] allows adding new properties to objects.
+ *
+ * Does not work on numbers, strings, booleans or null.
+ *
+ * An `Expando` does not hold on to the added property value after an object
+ * becomes inaccessible.
+ *
+ * Since you can always create a new number that is identical to an existing
+ * number, it means that an expando property on a number could never be
+ * released. To avoid this, expando properties cannot be added to numbers.
+ * The same argument applies to strings, booleans and null, which also have
+ * literals that evaluate to identical values when they occur more than once.
+ *
+ * There is no restriction on other classes, even for compile time constant
+ * objects. Be careful if adding expando properties to compile time constants,
+ * since they will stay alive forever.
+ */
+class Expando<T> {
+ /**
+ * The name of the this [Expando] as passed to the constructor. If
+ * no name was passed to the constructor, the name is [:null:].
+ */
+ final String name;
+
+ /**
+ * Creates a new [Expando]. The optional name is only used for
+ * debugging purposes and creating two different [Expando]s with the
+ * same name yields two [Expando]s that work on different properties
+ * of the objects they are used on.
+ */
+ external Expando([String name]);
+
+ /**
+ * Expando toString method override.
+ */
+ String toString() => "Expando:$name";
+
+ /**
+ * Gets the value of this [Expando]'s property on the given
+ * object. If the object hasn't been expanded, the method returns
+ * [:null:].
+ *
+ * The object must not be a number, a string, a boolean or null.
+ */
+ external T operator [](Object object);
+
+ /**
+ * Sets the value of this [Expando]'s property on the given
+ * object. Properties can effectively be removed again by setting
+ * their value to null.
+ *
+ * The object must not be a number, a string, a boolean or null.
+ */
+ external void operator []=(Object object, T value);
+}
diff --git a/sdk_nnbd/lib/core/function.dart b/sdk_nnbd/lib/core/function.dart
new file mode 100644
index 0000000..7ff40e9
--- /dev/null
+++ b/sdk_nnbd/lib/core/function.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * The base class for all function types.
+ *
+ * A function value, or an instance of a class with a "call" method, is a
+ * subtype of a function type, and as such, a subtype of [Function].
+ */
+abstract class Function {
+ /**
+ * Dynamically call [function] with the specified arguments.
+ *
+ * Acts the same as calling function with positional arguments
+ * corresponding to the elements of [positionalArguments] and
+ * named arguments corresponding to the elements of [namedArguments].
+ *
+ * This includes giving the same errors if [function] isn't callable or
+ * if it expects different parameters.
+ *
+ * Example:
+ * ```
+ * Function.apply(foo, [1,2,3], {#f: 4, #g: 5});
+ * ```
+ *
+ * gives exactly the same result as
+ * ```
+ * foo(1, 2, 3, f: 4, g: 5).
+ * ```
+ *
+ * If [positionalArguments] is null, it's considered an empty list.
+ * If [namedArguments] is omitted or null, it is considered an empty map.
+ */
+ external static apply(Function function, List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]);
+
+ /**
+ * Returns a hash code value that is compatible with `operator==`.
+ */
+ int get hashCode;
+
+ /**
+ * Test whether another object is equal to this function.
+ *
+ * System-created function objects are only equal to other functions.
+ *
+ * Two function objects are known to represent the same function if
+ *
+ * - It is the same object. Static and top-level functions are compile time
+ * constants when used as values, so referring to the same function twice
+ * always give the same object,
+ * - or if they refer to the same member method extracted from the same object.
+ * Extracting a member method as a function value twice gives equal, but
+ * not necessarily identical, function values.
+ *
+ * Function expressions never give rise to equal function objects. Each time
+ * a function expression is evaluated, it creates a new closure value that
+ * is not known to be equal to other closures created by the same expression.
+ *
+ * Classes implementing `Function` by having a `call` method should have their
+ * own `operator==` and `hashCode` depending on the object.
+ */
+ bool operator ==(Object other);
+}
diff --git a/sdk_nnbd/lib/core/identical.dart b/sdk_nnbd/lib/core/identical.dart
new file mode 100644
index 0000000..68da9f3
--- /dev/null
+++ b/sdk_nnbd/lib/core/identical.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * Check whether two references are to the same object.
+ */
+external bool identical(Object a, Object b);
+
+/**
+ * Returns the identity hash code of `object`.
+ *
+ * Returns the same value as `object.hashCode` if [object] has not overridden
+ * [Object.hashCode]. Returns the value that [Object.hashCode] would return
+ * on this object, even if `hashCode` has been overridden.
+ *
+ * This hash code is compatible with [identical].
+ */
+@pragma("vm:entry-point")
+external int identityHashCode(Object object);
diff --git a/sdk_nnbd/lib/core/int.dart b/sdk_nnbd/lib/core/int.dart
new file mode 100644
index 0000000..bc493fb
--- /dev/null
+++ b/sdk_nnbd/lib/core/int.dart
@@ -0,0 +1,355 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An integer number.
+ *
+ * The default implementation of `int` is 64-bit two's complement integers
+ * with operations that wrap to that range on overflow.
+ *
+ * **Note:** When compiling to JavaScript, integers are restricted to values
+ * that can be represented exactly by double-precision floating point values.
+ * The available integer values include all integers between -2^53 and 2^53,
+ * and some integers with larger magnitude. That includes some integers larger
+ * than 2^63.
+ * The behavior of the operators and methods in the [int]
+ * class therefore sometimes differs between the Dart VM and Dart code
+ * compiled to JavaScript. For example, the bitwise operators truncate their
+ * operands to 32-bit integers when compiled to JavaScript.
+ *
+ * Classes cannot extend, implement, or mix in `int`.
+ */
+abstract class int extends num {
+ /**
+ * Returns the integer value of the given environment declaration [name].
+ *
+ * The result is the same as would be returned by:
+ * ```
+ * int.tryParse(const String.fromEnvironment(name, defaultValue: ""))
+ * ?? defaultValue
+ * ```
+ * Example:
+ * ```
+ * const int.fromEnvironment("defaultPort", defaultValue: 80)
+ * ```
+ */
+ // The .fromEnvironment() constructors are special in that we do not want
+ // users to call them using "new". We prohibit that by giving them bodies
+ // that throw, even though const constructors are not allowed to have bodies.
+ // Disable those static errors.
+ //ignore: const_constructor_with_body
+ //ignore: const_factory
+ external const factory int.fromEnvironment(String name, {int defaultValue});
+
+ /**
+ * Bit-wise and operator.
+ *
+ * Treating both `this` and [other] as sufficiently large two's component
+ * integers, the result is a number with only the bits set that are set in
+ * both `this` and [other]
+ *
+ * Of both operands are negative, the result is negative, otherwise
+ * the result is non-negative.
+ */
+ int operator &(int other);
+
+ /**
+ * Bit-wise or operator.
+ *
+ * Treating both `this` and [other] as sufficiently large two's component
+ * integers, the result is a number with the bits set that are set in either
+ * of `this` and [other]
+ *
+ * If both operands are non-negative, the result is non-negative,
+ * otherwise the result is negative.
+ */
+ int operator |(int other);
+
+ /**
+ * Bit-wise exclusive-or operator.
+ *
+ * Treating both `this` and [other] as sufficiently large two's component
+ * integers, the result is a number with the bits set that are set in one,
+ * but not both, of `this` and [other]
+ *
+ * If the operands have the same sign, the result is non-negative,
+ * otherwise the result is negative.
+ */
+ int operator ^(int other);
+
+ /**
+ * The bit-wise negate operator.
+ *
+ * Treating `this` as a sufficiently large two's component integer,
+ * the result is a number with the opposite bits set.
+ *
+ * This maps any integer `x` to `-x - 1`.
+ */
+ int operator ~();
+
+ /**
+ * Shift the bits of this integer to the left by [shiftAmount].
+ *
+ * Shifting to the left makes the number larger, effectively multiplying
+ * the number by `pow(2, shiftIndex)`.
+ *
+ * There is no limit on the size of the result. It may be relevant to
+ * limit intermediate values by using the "and" operator with a suitable
+ * mask.
+ *
+ * It is an error if [shiftAmount] is negative.
+ */
+ int operator <<(int shiftAmount);
+
+ /**
+ * Shift the bits of this integer to the right by [shiftAmount].
+ *
+ * Shifting to the right makes the number smaller and drops the least
+ * significant bits, effectively doing an integer division by
+ *`pow(2, shiftIndex)`.
+ *
+ * It is an error if [shiftAmount] is negative.
+ */
+ int operator >>(int shiftAmount);
+
+ /**
+ * Returns this integer to the power of [exponent] modulo [modulus].
+ *
+ * The [exponent] must be non-negative and [modulus] must be
+ * positive.
+ */
+ int modPow(int exponent, int modulus);
+
+ /**
+ * Returns the modular multiplicative inverse of this integer
+ * modulo [modulus].
+ *
+ * The [modulus] must be positive.
+ *
+ * It is an error if no modular inverse exists.
+ */
+ int modInverse(int modulus);
+
+ /**
+ * Returns the greatest common divisor of this integer and [other].
+ *
+ * If either number is non-zero, the result is the numerically greatest
+ * integer dividing both `this` and `other`.
+ *
+ * The greatest common divisor is independent of the order,
+ * so `x.gcd(y)` is always the same as `y.gcd(x)`.
+ *
+ * For any integer `x`, `x.gcd(x)` is `x.abs()`.
+ *
+ * If both `this` and `other` is zero, the result is also zero.
+ */
+ int gcd(int other);
+
+ /** Returns true if and only if this integer is even. */
+ bool get isEven;
+
+ /** Returns true if and only if this integer is odd. */
+ bool get isOdd;
+
+ /**
+ * Returns the minimum number of bits required to store this integer.
+ *
+ * The number of bits excludes the sign bit, which gives the natural length
+ * for non-negative (unsigned) values. Negative values are complemented to
+ * return the bit position of the first bit that differs from the sign bit.
+ *
+ * To find the number of bits needed to store the value as a signed value,
+ * add one, i.e. use `x.bitLength + 1`.
+ * ```
+ * x.bitLength == (-x-1).bitLength
+ *
+ * 3.bitLength == 2; // 00000011
+ * 2.bitLength == 2; // 00000010
+ * 1.bitLength == 1; // 00000001
+ * 0.bitLength == 0; // 00000000
+ * (-1).bitLength == 0; // 11111111
+ * (-2).bitLength == 1; // 11111110
+ * (-3).bitLength == 2; // 11111101
+ * (-4).bitLength == 2; // 11111100
+ * ```
+ */
+ int get bitLength;
+
+ /**
+ * Returns the least significant [width] bits of this integer as a
+ * non-negative number (i.e. unsigned representation). The returned value has
+ * zeros in all bit positions higher than [width].
+ * ```
+ * (-1).toUnsigned(5) == 31 // 11111111 -> 00011111
+ * ```
+ * This operation can be used to simulate arithmetic from low level languages.
+ * For example, to increment an 8 bit quantity:
+ * ```
+ * q = (q + 1).toUnsigned(8);
+ * ```
+ * `q` will count from `0` up to `255` and then wrap around to `0`.
+ *
+ * If the input fits in [width] bits without truncation, the result is the
+ * same as the input. The minimum width needed to avoid truncation of `x` is
+ * given by `x.bitLength`, i.e.
+ * ```
+ * x == x.toUnsigned(x.bitLength);
+ * ```
+ */
+ int toUnsigned(int width);
+
+ /**
+ * Returns the least significant [width] bits of this integer, extending the
+ * highest retained bit to the sign. This is the same as truncating the value
+ * to fit in [width] bits using an signed 2-s complement representation. The
+ * returned value has the same bit value in all positions higher than [width].
+ *
+ * ```
+ * V--sign bit-V
+ * 16.toSigned(5) == -16 // 00010000 -> 11110000
+ * 239.toSigned(5) == 15 // 11101111 -> 00001111
+ * ^ ^
+ * ```
+ * This operation can be used to simulate arithmetic from low level languages.
+ * For example, to increment an 8 bit signed quantity:
+ * ```
+ * q = (q + 1).toSigned(8);
+ * ```
+ * `q` will count from `0` up to `127`, wrap to `-128` and count back up to
+ * `127`.
+ *
+ * If the input value fits in [width] bits without truncation, the result is
+ * the same as the input. The minimum width needed to avoid truncation of `x`
+ * is `x.bitLength + 1`, i.e.
+ * ```
+ * x == x.toSigned(x.bitLength + 1);
+ * ```
+ */
+ int toSigned(int width);
+
+ /**
+ * Return the negative value of this integer.
+ *
+ * The result of negating an integer always has the opposite sign, except
+ * for zero, which is its own negation.
+ */
+ int operator -();
+
+ /**
+ * Returns the absolute value of this integer.
+ *
+ * For any integer `x`, the result is the same as `x < 0 ? -x : x`.
+ */
+ int abs();
+
+ /**
+ * Returns the sign of this integer.
+ *
+ * Returns 0 for zero, -1 for values less than zero and
+ * +1 for values greater than zero.
+ */
+ int get sign;
+
+ /** Returns `this`. */
+ int round();
+
+ /** Returns `this`. */
+ int floor();
+
+ /** Returns `this`. */
+ int ceil();
+
+ /** Returns `this`. */
+ int truncate();
+
+ /** Returns `this.toDouble()`. */
+ double roundToDouble();
+
+ /** Returns `this.toDouble()`. */
+ double floorToDouble();
+
+ /** Returns `this.toDouble()`. */
+ double ceilToDouble();
+
+ /** Returns `this.toDouble()`. */
+ double truncateToDouble();
+
+ /**
+ * Returns a string representation of this integer.
+ *
+ * The returned string is parsable by [parse].
+ * For any `int` `i`, it is guaranteed that
+ * `i == int.parse(i.toString())`.
+ */
+ String toString();
+
+ /**
+ * Converts [this] to a string representation in the given [radix].
+ *
+ * In the string representation, lower-case letters are used for digits above
+ * '9', with 'a' being 10 an 'z' being 35.
+ *
+ * The [radix] argument must be an integer in the range 2 to 36.
+ */
+ String toRadixString(int radix);
+
+ /**
+ * Parse [source] as a, possibly signed, integer literal and return its value.
+ *
+ * The [source] must be a non-empty sequence of base-[radix] digits,
+ * optionally prefixed with a minus or plus sign ('-' or '+').
+ * It must not be `null`.
+ *
+ * The [radix] must be in the range 2..36. The digits used are
+ * first the decimal digits 0..9, and then the letters 'a'..'z' with
+ * values 10 through 35. Also accepts upper-case letters with the same
+ * values as the lower-case ones.
+ *
+ * If no [radix] is given then it defaults to 10. In this case, the [source]
+ * digits may also start with `0x`, in which case the number is interpreted
+ * as a hexadecimal integer literal,
+ * When `int` is implemented by 64-bit signed integers,
+ * hexadecimal integer literals may represent values larger than
+ * 2<sup>63</sup>, in which case the value is parsed as if it is an
+ * *unsigned* number, and the resulting value is the corresponding
+ * signed integer value.
+ *
+ * For any int `n` and valid radix `r`, it is guaranteed that
+ * `n == int.parse(n.toRadixString(r), radix: r)`.
+ *
+ * If the [source] string does not contain a valid integer literal,
+ * optionally prefixed by a sign, a [FormatException] is thrown
+ * (unless the deprecated [onError] parameter is used, see below).
+ *
+ * Instead of throwing and immediately catching the [FormatException],
+ * instead use [tryParse] to handle a parsing error.
+ * Example:
+ * ```dart
+ * var value = int.tryParse(text);
+ * if (value == null) ... handle the problem
+ * ```
+ *
+ * The [onError] parameter is deprecated and will be removed.
+ * Instead of `int.parse(string, onError: (string) => ...)`,
+ * you should use `int.tryParse(string) ?? (...)`.
+ *
+ * When the source string is not valid and [onError] is provided,
+ * whenever a [FormatException] would be thrown,
+ * [onError] is instead called with [source] as argument,
+ * and the result of that call is returned by [parse].
+ */
+ external static int parse(String source,
+ {int radix, @deprecated int onError(String source)});
+
+ /**
+ * Parse [source] as a, possibly signed, integer literal and return its value.
+ *
+ * Like [parse] except that this function returns `null` where a
+ * similar call to [parse] would throw a [FormatException],
+ * and the [source] must still not be `null`.
+ */
+ external static int tryParse(String source, {int radix});
+}
diff --git a/sdk_nnbd/lib/core/invocation.dart b/sdk_nnbd/lib/core/invocation.dart
new file mode 100644
index 0000000..e9ea57e
--- /dev/null
+++ b/sdk_nnbd/lib/core/invocation.dart
@@ -0,0 +1,162 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * Representation of the invocation of a member on an object.
+ *
+ * This is the type of objects passed to [Object.noSuchMethod] when
+ * an object doesn't support the member invocation that was attempted
+ * on it.
+ */
+abstract class Invocation {
+ Invocation();
+
+ /**
+ * Creates an invocation corresponding to a method invocation.
+ *
+ * The method invocation has no type arguments.
+ * If the named arguments are omitted, they default to no named arguments.
+ */
+ factory Invocation.method(
+ Symbol memberName, Iterable<Object> positionalArguments,
+ [Map<Symbol, Object> namedArguments]) =>
+ _Invocation.method(memberName, null, positionalArguments, namedArguments);
+
+ /**
+ * Creates an invocation corresponding to a generic method invocation.
+ *
+ * If [typeArguments] is `null` or empty, the constructor is equivalent to
+ * calling [Invocation.method] with the remaining arguments.
+ * All the individual type arguments must be non-null.
+ *
+ * If the named arguments are omitted, they default to no named arguments.
+ */
+ factory Invocation.genericMethod(Symbol memberName,
+ Iterable<Type> typeArguments, Iterable<Object> positionalArguments,
+ [Map<Symbol, Object> namedArguments]) =>
+ _Invocation.method(
+ memberName, typeArguments, positionalArguments, namedArguments);
+
+ /**
+ * Creates an invocation corresponding to a getter invocation.
+ */
+ factory Invocation.getter(Symbol name) = _Invocation.getter;
+
+ /**
+ * Creates an invocation corresponding to a setter invocation.
+ *
+ * This constructor accepts any [Symbol] as [memberName], but remember that
+ * *actual setter names* end in `=`, so the invocation corresponding
+ * to `object.member = value` is
+ * ```dart
+ * Invocation.setter(const Symbol("member="), value)
+ * ```
+ */
+ factory Invocation.setter(Symbol memberName, Object argument) =
+ _Invocation.setter;
+
+ /** The name of the invoked member. */
+ Symbol get memberName;
+
+ /**
+ * An unmodifiable view of the type arguments of the call.
+ *
+ * If the member is a getter, setter or operator,
+ * the type argument list is always empty.
+ */
+ List<Type> get typeArguments => const <Type>[];
+
+ /**
+ * An unmodifiable view of the positional arguments of the call.
+ *
+ * If the member is a getter, the positional arguments list is
+ * always empty.
+ */
+ List<dynamic> get positionalArguments;
+
+ /**
+ * An unmodifiable view of the named arguments of the call.
+ *
+ * If the member is a getter, setter or operator,
+ * the named arguments map is always empty.
+ */
+ Map<Symbol, dynamic> get namedArguments;
+
+ /** Whether the invocation was a method call. */
+ bool get isMethod;
+
+ /**
+ * Whether the invocation was a getter call.
+ * If so, all three types of arguments lists are empty.
+ */
+ bool get isGetter;
+
+ /**
+ * Whether the invocation was a setter call.
+ *
+ * If so, [positionalArguments] has exactly one positional
+ * argument, [namedArguments] is empty, and typeArguments is
+ * empty.
+ */
+ bool get isSetter;
+
+ /** Whether the invocation was a getter or a setter call. */
+ bool get isAccessor => isGetter || isSetter;
+}
+
+/** Implementation of [Invocation] used by its factory constructors. */
+class _Invocation implements Invocation {
+ final Symbol memberName;
+ final List<Type> typeArguments;
+ // Positional arguments is `null` for getters only.
+ final List<Object> _positional;
+ // Named arguments is `null` for accessors only.
+ final Map<Symbol, Object> _named;
+
+ _Invocation.method(this.memberName, Iterable<Type> types,
+ Iterable<Object> positional, Map<Symbol, Object> named)
+ : typeArguments = _ensureNonNullTypes(_makeUnmodifiable<Type>(types)),
+ _positional = _makeUnmodifiable<Object>(positional) ?? const <Object>[],
+ _named = (named == null || named.isEmpty)
+ ? const <Symbol, Object>{}
+ : Map<Symbol, Object>.unmodifiable(named);
+
+ _Invocation.getter(this.memberName)
+ : typeArguments = const <Type>[],
+ _positional = null,
+ _named = null;
+
+ _Invocation.setter(this.memberName, Object argument)
+ : typeArguments = const <Type>[],
+ _positional = List<Object>.unmodifiable([argument]),
+ _named = null;
+
+ List<dynamic> get positionalArguments => _positional ?? const <Object>[];
+
+ Map<Symbol, dynamic> get namedArguments => _named ?? const <Symbol, Object>{};
+
+ bool get isMethod => _named != null;
+ bool get isGetter => _positional == null;
+ bool get isSetter => _positional != null && _named == null;
+ bool get isAccessor => _named == null;
+
+ /// Checks that the elements of [types] are not null.
+ static List<Type> _ensureNonNullTypes(List<Type> types) {
+ if (types == null) return const <Type>[];
+ for (int i = 0; i < types.length; i++) {
+ if (types[i] == null) {
+ throw ArgumentError(
+ "Type arguments must be non-null, was null at index $i.");
+ }
+ }
+ return types;
+ }
+
+ static List<T> _makeUnmodifiable<T>(Iterable<T> elements) {
+ if (elements == null) return null;
+ return List<T>.unmodifiable(elements);
+ }
+}
diff --git a/sdk_nnbd/lib/core/iterable.dart b/sdk_nnbd/lib/core/iterable.dart
new file mode 100644
index 0000000..0744937
--- /dev/null
+++ b/sdk_nnbd/lib/core/iterable.dart
@@ -0,0 +1,707 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A collection of values, or "elements", that can be accessed sequentially.
+ *
+ * The elements of the iterable are accessed by getting an [Iterator]
+ * using the [iterator] getter, and using it to step through the values.
+ * Stepping with the iterator is done by calling [Iterator.moveNext],
+ * and if the call returns `true`,
+ * the iterator has now moved to the next element,
+ * which is then available as [Iterator.current].
+ * If the call returns `false`, there are no more elements,
+ * and `iterator.current` returns `null`.
+ *
+ * You can create more than one iterator from the same `Iterable`.
+ * Each time `iterator` is read, it returns a new iterator,
+ * and different iterators can be stepped through independently,
+ * each giving access to all the elements of the iterable.
+ * The iterators of the same iterable *should* provide the same values
+ * in the same order (unless the underlying collection is modified between
+ * the iterations, which some collections allow).
+ *
+ * You can also iterate over the elements of an `Iterable`
+ * using the for-in loop construct, which uses the `iterator` getter behind the
+ * scenes.
+ * For example, you can iterate over all of the keys of a [Map],
+ * because `Map` keys are iterable.
+ *
+ * Map kidsBooks = {'Matilda': 'Roald Dahl',
+ * 'Green Eggs and Ham': 'Dr Seuss',
+ * 'Where the Wild Things Are': 'Maurice Sendak'};
+ * for (var book in kidsBooks.keys) {
+ * print('$book was written by ${kidsBooks[book]}');
+ * }
+ *
+ * The [List] and [Set] classes are both `Iterable`,
+ * as are most classes in the `dart:collection` library.
+ *
+ * Some [Iterable] collections can be modified.
+ * Adding an element to a `List` or `Set` will change which elements it
+ * contains, and adding a new key to a `Map` changes the elements of [Map.keys].
+ * Iterators created after the change will provide the new elements, and may
+ * or may not preserve the order of existing elements
+ * (for example, a [HashSet] may completely change its order when a single
+ * element is added).
+ *
+ * Changing a collection *while* it is being iterated
+ * is generally *not* allowed.
+ * Doing so will break the iteration, which is typically signalled
+ * by throwing a [ConcurrentModificationError]
+ * the next time [Iterator.moveNext] is called.
+ * The current value of [Iterator.current] getter
+ * should not be affected by the change in the collection,
+ * the `current` value was set by the previous call to [Iterator.moveNext].
+ *
+ * Some iterables compute their elements dynamically every time they are
+ * iterated, like the one returned by [Iterable.generate] or the iterable
+ * returned by a `sync*` generator function. If the computation doesn't depend
+ * on other objects that may change, then the generated sequence should be
+ * the same one every time it's iterated.
+ *
+ * The members of `Iterable`, other than `iterator` itself,
+ * work by looking at the elements of the iterable.
+ * This can be implemented by running through the [iterator], but some classes
+ * may have more efficient ways of finding the result
+ * (like [last] or [length] on a [List], or [contains] on a [Set]).
+ *
+ * The methods that return another `Iterable` (like [map] and [where])
+ * are all *lazy* - they will iterate the original (as necessary)
+ * every time the returned iterable is iterated, and not before.
+ *
+ * Since an iterable may be iterated more than once, it's not recommended to
+ * have detectable side-effects in the iterator.
+ * For methods like [map] and [where], the returned iterable will execute the
+ * argument function on every iteration, so those functions should also not
+ * have side effects.
+ */
+abstract class Iterable<E> {
+ // TODO(lrn): When we allow forwarding const constructors through
+ // mixin applications, make this class implement [IterableMixin].
+ const Iterable();
+
+ /**
+ * Creates an `Iterable` which generates its elements dynamically.
+ *
+ * The generated iterable has [count] elements,
+ * and the element at index `n` is computed by calling `generator(n)`.
+ * Values are not cached, so each iteration computes the values again.
+ *
+ * If [generator] is omitted, it defaults to an identity function
+ * on integers `(int x) => x`, so it may only be omitted if the type
+ * parameter allows integer values. That is, if [E] is a super-type
+ * of [int].
+ *
+ * As an `Iterable`, `new Iterable.generate(n, generator))` is equivalent to
+ * `const [0, ..., n - 1].map(generator)`.
+ */
+ factory Iterable.generate(int count, [E generator(int index)]) {
+ if (count <= 0) return EmptyIterable<E>();
+ return _GeneratorIterable<E>(count, generator);
+ }
+
+ /**
+ * Creates an empty iterable.
+ *
+ * The empty iterable has no elements, and iterating it always stops
+ * immediately.
+ */
+ const factory Iterable.empty() = EmptyIterable<E>;
+
+ /**
+ * Adapts [source] to be an `Iterable<T>`.
+ *
+ * Any time the iterable would produce an element that is not a [T],
+ * the element access will throw. If all elements of [source] are actually
+ * instances of [T], or if only elements that are actually instances of [T]
+ * are accessed, then the resulting iterable can be used as an `Iterable<T>`.
+ */
+ static Iterable<T> castFrom<S, T>(Iterable<S> source) =>
+ CastIterable<S, T>(source);
+
+ /**
+ * Returns a new `Iterator` that allows iterating the elements of this
+ * `Iterable`.
+ *
+ * Iterable classes may specify the iteration order of their elements
+ * (for example [List] always iterate in index order),
+ * or they may leave it unspecified (for example a hash-based [Set]
+ * may iterate in any order).
+ *
+ * Each time `iterator` is read, it returns a new iterator,
+ * which can be used to iterate through all the elements again.
+ * The iterators of the same iterable can be stepped through independently,
+ * but should return the same elements in the same order,
+ * as long as the underlying collection isn't changed.
+ *
+ * Modifying the collection may cause new iterators to produce
+ * different elements, and may change the order of existing elements.
+ * A [List] specifies its iteration order precisely,
+ * so modifying the list changes the iteration order predictably.
+ * A hash-based [Set] may change its iteration order completely
+ * when adding a new element to the set.
+ *
+ * Modifying the underlying collection after creating the new iterator
+ * may cause an error the next time [Iterator.moveNext] is called
+ * on that iterator.
+ * Any *modifiable* iterable class should specify which operations will
+ * break iteration.
+ */
+ Iterator<E> get iterator;
+
+ /**
+ * Provides a view of this iterable as an iterable of [R] instances.
+ *
+ * If this iterable only contains instances of [R], all operations
+ * will work correctly. If any operation tries to access an element
+ * that is not an instance of [R], the access will throw instead.
+ *
+ * When the returned iterable creates a new object that depends on
+ * the type [R], e.g., from [toList], it will have exactly the type [R].
+ */
+ Iterable<R> cast<R>() => Iterable.castFrom<E, R>(this);
+ /**
+ * Returns the lazy concatentation of this iterable and [other].
+ *
+ * The returned iterable will provide the same elements as this iterable,
+ * and, after that, the elements of [other], in the same order as in the
+ * original iterables.
+ */
+ Iterable<E> followedBy(Iterable<E> other) {
+ if (this is EfficientLengthIterable<E>) {
+ return FollowedByIterable<E>.firstEfficient(this, other);
+ }
+ return FollowedByIterable<E>(this, other);
+ }
+
+ /**
+ * Returns a new lazy [Iterable] with elements that are created by
+ * calling `f` on each element of this `Iterable` in iteration order.
+ *
+ * This method returns a view of the mapped elements. As long as the
+ * returned [Iterable] is not iterated over, the supplied function [f] will
+ * not be invoked. The transformed elements will not be cached. Iterating
+ * multiple times over the returned [Iterable] will invoke the supplied
+ * function [f] multiple times on the same element.
+ *
+ * Methods on the returned iterable are allowed to omit calling `f`
+ * on any element where the result isn't needed.
+ * For example, [elementAt] may call `f` only once.
+ */
+ Iterable<T> map<T>(T f(E e)) => MappedIterable<E, T>(this, f);
+
+ /**
+ * Returns a new lazy [Iterable] with all elements that satisfy the
+ * predicate [test].
+ *
+ * The matching elements have the same order in the returned iterable
+ * as they have in [iterator].
+ *
+ * This method returns a view of the mapped elements.
+ * As long as the returned [Iterable] is not iterated over,
+ * the supplied function [test] will not be invoked.
+ * Iterating will not cache results, and thus iterating multiple times over
+ * the returned [Iterable] may invoke the supplied
+ * function [test] multiple times on the same element.
+ */
+ Iterable<E> where(bool test(E element)) => WhereIterable<E>(this, test);
+
+ /**
+ * Returns a new lazy [Iterable] with all elements that have type [T].
+ *
+ * The matching elements have the same order in the returned iterable
+ * as they have in [iterator].
+ *
+ * This method returns a view of the mapped elements.
+ * Iterating will not cache results, and thus iterating multiple times over
+ * the returned [Iterable] may yield different results,
+ * if the underlying elements change between iterations.
+ */
+ Iterable<T> whereType<T>() => WhereTypeIterable<T>(this);
+
+ /**
+ * Expands each element of this [Iterable] into zero or more elements.
+ *
+ * The resulting Iterable runs through the elements returned
+ * by [f] for each element of this, in iteration order.
+ *
+ * The returned [Iterable] is lazy, and calls [f] for each element
+ * of this every time it's iterated.
+ *
+ * Example:
+ *
+ * var pairs = [[1, 2], [3, 4]];
+ * var flattened = pairs.expand((pair) => pair).toList();
+ * print(flattened); // => [1, 2, 3, 4];
+ *
+ * var input = [1, 2, 3];
+ * var duplicated = input.expand((i) => [i, i]).toList();
+ * print(duplicated); // => [1, 1, 2, 2, 3, 3]
+ *
+ */
+ Iterable<T> expand<T>(Iterable<T> f(E element)) =>
+ ExpandIterable<E, T>(this, f);
+
+ /**
+ * Returns true if the collection contains an element equal to [element].
+ *
+ * This operation will check each element in order for being equal to
+ * [element], unless it has a more efficient way to find an element
+ * equal to [element].
+ *
+ * The equality used to determine whether [element] is equal to an element of
+ * the iterable defaults to the [Object.==] of the element.
+ *
+ * Some types of iterable may have a different equality used for its elements.
+ * For example, a [Set] may have a custom equality
+ * (see [Set.identity]) that its `contains` uses.
+ * Likewise the `Iterable` returned by a [Map.keys] call
+ * should use the same equality that the `Map` uses for keys.
+ */
+ bool contains(Object element) {
+ for (E e in this) {
+ if (e == element) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Applies the function [f] to each element of this collection in iteration
+ * order.
+ */
+ void forEach(void f(E element)) {
+ for (E element in this) f(element);
+ }
+
+ /**
+ * Reduces a collection to a single value by iteratively combining elements
+ * of the collection using the provided function.
+ *
+ * The iterable must have at least one element.
+ * If it has only one element, that element is returned.
+ *
+ * Otherwise this method starts with the first element from the iterator,
+ * and then combines it with the remaining elements in iteration order,
+ * as if by:
+ *
+ * E value = iterable.first;
+ * iterable.skip(1).forEach((element) {
+ * value = combine(value, element);
+ * });
+ * return value;
+ *
+ * Example of calculating the sum of an iterable:
+ *
+ * iterable.reduce((value, element) => value + element);
+ *
+ */
+ E reduce(E combine(E value, E element)) {
+ Iterator<E> iterator = this.iterator;
+ if (!iterator.moveNext()) {
+ throw IterableElementError.noElement();
+ }
+ E value = iterator.current;
+ while (iterator.moveNext()) {
+ value = combine(value, iterator.current);
+ }
+ return value;
+ }
+
+ /**
+ * Reduces a collection to a single value by iteratively combining each
+ * element of the collection with an existing value
+ *
+ * Uses [initialValue] as the initial value,
+ * then iterates through the elements and updates the value with
+ * each element using the [combine] function, as if by:
+ *
+ * var value = initialValue;
+ * for (E element in this) {
+ * value = combine(value, element);
+ * }
+ * return value;
+ *
+ * Example of calculating the sum of an iterable:
+ *
+ * iterable.fold(0, (prev, element) => prev + element);
+ *
+ */
+ T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+ var value = initialValue;
+ for (E element in this) value = combine(value, element);
+ return value;
+ }
+
+ /**
+ * Checks whether every element of this iterable satisfies [test].
+ *
+ * Checks every element in iteration order, and returns `false` if
+ * any of them make [test] return `false`, otherwise returns `true`.
+ */
+ bool every(bool test(E element)) {
+ for (E element in this) {
+ if (!test(element)) return false;
+ }
+ return true;
+ }
+
+ /**
+ * Converts each element to a [String] and concatenates the strings.
+ *
+ * Iterates through elements of this iterable,
+ * converts each one to a [String] by calling [Object.toString],
+ * and then concatenates the strings, with the
+ * [separator] string interleaved between the elements.
+ */
+ String join([String separator = ""]) {
+ Iterator<E> iterator = this.iterator;
+ if (!iterator.moveNext()) return "";
+ StringBuffer buffer = StringBuffer();
+ if (separator == null || separator == "") {
+ do {
+ buffer.write("${iterator.current}");
+ } while (iterator.moveNext());
+ } else {
+ buffer.write("${iterator.current}");
+ while (iterator.moveNext()) {
+ buffer.write(separator);
+ buffer.write("${iterator.current}");
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Checks whether any element of this iterable satisfies [test].
+ *
+ * Checks every element in iteration order, and returns `true` if
+ * any of them make [test] return `true`, otherwise returns false.
+ */
+ bool any(bool test(E element)) {
+ for (E element in this) {
+ if (test(element)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Creates a [List] containing the elements of this [Iterable].
+ *
+ * The elements are in iteration order.
+ * The list is fixed-length if [growable] is false.
+ */
+ List<E> toList({bool growable = true}) {
+ return List<E>.from(this, growable: growable);
+ }
+
+ /**
+ * Creates a [Set] containing the same elements as this iterable.
+ *
+ * The set may contain fewer elements than the iterable,
+ * if the iterable contains an element more than once,
+ * or it contains one or more elements that are equal.
+ * The order of the elements in the set is not guaranteed to be the same
+ * as for the iterable.
+ */
+ Set<E> toSet() => Set<E>.from(this);
+
+ /**
+ * Returns the number of elements in [this].
+ *
+ * Counting all elements may involve iterating through all elements and can
+ * therefore be slow.
+ * Some iterables have a more efficient way to find the number of elements.
+ */
+ int get length {
+ assert(this is! EfficientLengthIterable);
+ int count = 0;
+ Iterator it = iterator;
+ while (it.moveNext()) {
+ count++;
+ }
+ return count;
+ }
+
+ /**
+ * Returns `true` if there are no elements in this collection.
+ *
+ * May be computed by checking if `iterator.moveNext()` returns `false`.
+ */
+ bool get isEmpty => !iterator.moveNext();
+
+ /**
+ * Returns true if there is at least one element in this collection.
+ *
+ * May be computed by checking if `iterator.moveNext()` returns `true`.
+ */
+ bool get isNotEmpty => !isEmpty;
+
+ /**
+ * Returns a lazy iterable of the [count] first elements of this iterable.
+ *
+ * The returned `Iterable` may contain fewer than `count` elements, if `this`
+ * contains fewer than `count` elements.
+ *
+ * The elements can be computed by stepping through [iterator] until [count]
+ * elements have been seen.
+ *
+ * The `count` must not be negative.
+ */
+ Iterable<E> take(int count) {
+ return TakeIterable<E>(this, count);
+ }
+
+ /**
+ * Returns a lazy iterable of the leading elements satisfying [test].
+ *
+ * The filtering happens lazily. Every new iterator of the returned
+ * iterable starts iterating over the elements of `this`.
+ *
+ * The elements can be computed by stepping through [iterator] until an
+ * element is found where `test(element)` is false. At that point,
+ * the returned iterable stops (its `moveNext()` returns false).
+ */
+ Iterable<E> takeWhile(bool test(E value)) {
+ return TakeWhileIterable<E>(this, test);
+ }
+
+ /**
+ * Returns an [Iterable] that provides all but the first [count] elements.
+ *
+ * When the returned iterable is iterated, it starts iterating over `this`,
+ * first skipping past the initial [count] elements.
+ * If `this` has fewer than `count` elements, then the resulting Iterable is
+ * empty.
+ * After that, the remaining elements are iterated in the same order as
+ * in this iterable.
+ *
+ * Some iterables may be able to find later elements without first iterating
+ * through earlier elements, for example when iterating a [List].
+ * Such iterables are allowed to ignore the initial skipped elements.
+ *
+ * The [count] must not be negative.
+ */
+ Iterable<E> skip(int count) {
+ return SkipIterable<E>(this, count);
+ }
+
+ /**
+ * Returns an `Iterable` that skips leading elements while [test] is satisfied.
+ *
+ * The filtering happens lazily. Every new [Iterator] of the returned
+ * iterable iterates over all elements of `this`.
+ *
+ * The returned iterable provides elements by iterating this iterable,
+ * but skipping over all initial elements where `test(element)` returns
+ * true. If all elements satisfy `test` the resulting iterable is empty,
+ * otherwise it iterates the remaining elements in their original order,
+ * starting with the first element for which `test(element)` returns `false`.
+ */
+ Iterable<E> skipWhile(bool test(E value)) {
+ return SkipWhileIterable<E>(this, test);
+ }
+
+ /**
+ * Returns the first element.
+ *
+ * Throws a [StateError] if `this` is empty.
+ * Otherwise returns the first element in the iteration order,
+ * equivalent to `this.elementAt(0)`.
+ */
+ E get first {
+ Iterator<E> it = iterator;
+ if (!it.moveNext()) {
+ throw IterableElementError.noElement();
+ }
+ return it.current;
+ }
+
+ /**
+ * Returns the last element.
+ *
+ * Throws a [StateError] if `this` is empty.
+ * Otherwise may iterate through the elements and returns the last one
+ * seen.
+ * Some iterables may have more efficient ways to find the last element
+ * (for example a list can directly access the last element,
+ * without iterating through the previous ones).
+ */
+ E get last {
+ Iterator<E> it = iterator;
+ if (!it.moveNext()) {
+ throw IterableElementError.noElement();
+ }
+ E result;
+ do {
+ result = it.current;
+ } while (it.moveNext());
+ return result;
+ }
+
+ /**
+ * Checks that this iterable has only one element, and returns that element.
+ *
+ * Throws a [StateError] if `this` is empty or has more than one element.
+ */
+ E get single {
+ Iterator<E> it = iterator;
+ if (!it.moveNext()) throw IterableElementError.noElement();
+ E result = it.current;
+ if (it.moveNext()) throw IterableElementError.tooMany();
+ return result;
+ }
+
+ /**
+ * Returns the first element that satisfies the given predicate [test].
+ *
+ * Iterates through elements and returns the first to satisfy [test].
+ *
+ * If no element satisfies [test], the result of invoking the [orElse]
+ * function is returned.
+ * If [orElse] is omitted, it defaults to throwing a [StateError].
+ */
+ E firstWhere(bool test(E element), {E orElse()}) {
+ for (E element in this) {
+ if (test(element)) return element;
+ }
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ /**
+ * Returns the last element that satisfies the given predicate [test].
+ *
+ * An iterable that can access its elements directly may check its
+ * elements in any order (for example a list starts by checking the
+ * last element and then moves towards the start of the list).
+ * The default implementation iterates elements in iteration order,
+ * checks `test(element)` for each,
+ * and finally returns that last one that matched.
+ *
+ * If no element satisfies [test], the result of invoking the [orElse]
+ * function is returned.
+ * If [orElse] is omitted, it defaults to throwing a [StateError].
+ */
+ E lastWhere(bool test(E element), {E orElse()}) {
+ E result;
+ bool foundMatching = false;
+ for (E element in this) {
+ if (test(element)) {
+ result = element;
+ foundMatching = true;
+ }
+ }
+ if (foundMatching) return result;
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ /**
+ * Returns the single element that satisfies [test].
+ *
+ * Checks elements to see if `test(element)` returns true.
+ * If exactly one element satisfies [test], that element is returned.
+ * If more than one matching element is found, throws [StateError].
+ * If no matching element is found, returns the result of [orElse].
+ * If [orElse] is omitted, it defaults to throwing a [StateError].
+ */
+ E singleWhere(bool test(E element), {E orElse()}) {
+ E result;
+ bool foundMatching = false;
+ for (E element in this) {
+ if (test(element)) {
+ if (foundMatching) {
+ throw IterableElementError.tooMany();
+ }
+ result = element;
+ foundMatching = true;
+ }
+ }
+ if (foundMatching) return result;
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ /**
+ * Returns the [index]th element.
+ *
+ * The [index] must be non-negative and less than [length].
+ * Index zero represents the first element (so `iterable.elementAt(0)` is
+ * equivalent to `iterable.first`).
+ *
+ * May iterate through the elements in iteration order, ignoring the
+ * first [index] elements and then returning the next.
+ * Some iterables may have more a efficient way to find the element.
+ */
+ E elementAt(int index) {
+ ArgumentError.checkNotNull(index, "index");
+ RangeError.checkNotNegative(index, "index");
+ int elementIndex = 0;
+ for (E element in this) {
+ if (index == elementIndex) return element;
+ elementIndex++;
+ }
+ throw RangeError.index(index, this, "index", null, elementIndex);
+ }
+
+ /**
+ * Returns a string representation of (some of) the elements of `this`.
+ *
+ * Elements are represented by their own `toString` results.
+ *
+ * The default representation always contains the first three elements.
+ * If there are less than a hundred elements in the iterable, it also
+ * contains the last two elements.
+ *
+ * If the resulting string isn't above 80 characters, more elements are
+ * included from the start of the iterable.
+ *
+ * The conversion may omit calling `toString` on some elements if they
+ * are known to not occur in the output, and it may stop iterating after
+ * a hundred elements.
+ */
+ String toString() => IterableBase.iterableToShortString(this, '(', ')');
+}
+
+typedef _Generator<E> = E Function(int index);
+
+class _GeneratorIterable<E> extends ListIterable<E> {
+ /// The length of the generated iterable.
+ final int length;
+
+ /// The function mapping indices to values.
+ final _Generator<E> _generator;
+
+ /// Creates the generated iterable.
+ ///
+ /// If [generator] is `null`, it is checked that `int` is assignable to [E].
+ _GeneratorIterable(this.length, E generator(int index))
+ : // The `as` below is used as check to make sure that `int` is assignable
+ // to [E].
+ _generator = (generator != null) ? generator : _id as _Generator<E>;
+
+ E elementAt(int index) {
+ RangeError.checkValidIndex(index, this);
+ return _generator(index);
+ }
+
+ /// Helper function used as default _generator function.
+ static int _id(int n) => n;
+}
+
+/**
+ * An Iterator that allows moving backwards as well as forwards.
+ */
+abstract class BidirectionalIterator<E> implements Iterator<E> {
+ /**
+ * Move back to the previous element.
+ *
+ * Returns true and updates [current] if successful. Returns false
+ * and sets [current] to null if there is no previous element.
+ */
+ bool movePrevious();
+}
diff --git a/sdk_nnbd/lib/core/iterator.dart b/sdk_nnbd/lib/core/iterator.dart
new file mode 100644
index 0000000..cd0ad32
--- /dev/null
+++ b/sdk_nnbd/lib/core/iterator.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An interface for getting items, one at a time, from an object.
+ *
+ * The for-in construct transparently uses `Iterator` to test for the end
+ * of the iteration, and to get each item (or _element_).
+ *
+ * If the object iterated over is changed during the iteration, the
+ * behavior is unspecified.
+ *
+ * The `Iterator` is initially positioned before the first element.
+ * Before accessing the first element the iterator must thus be advanced using
+ * [moveNext] to point to the first element.
+ * If no element is left, then [moveNext] returns false, [current]
+ * returns `null`, and all further calls to [moveNext] will also return false.
+ *
+ * A typical usage of an Iterator looks as follows:
+ *
+ * var it = obj.iterator;
+ * while (it.moveNext()) {
+ * use(it.current);
+ * }
+ *
+ * **See also:**
+ * [Iteration](http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html#iteration)
+ * in the [library tour](http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html)
+ */
+abstract class Iterator<E> {
+ /**
+ * Moves to the next element.
+ *
+ * Returns true if [current] contains the next element.
+ * Returns false if no elements are left.
+ *
+ * It is safe to invoke [moveNext] even when the iterator is already
+ * positioned after the last element.
+ * In this case [moveNext] returns false again and has no effect.
+ *
+ * A call to `moveNext` may throw if iteration has been broken by
+ * changing the underlying collection.
+ */
+ bool moveNext();
+
+ /**
+ * Returns the current element.
+ *
+ * Returns `null` if the iterator has not yet been moved to the first
+ * element, or if the iterator has been moved past the last element of the
+ * [Iterable].
+ *
+ * The `current` getter should keep its value until the next call to
+ * [moveNext], even if an underlying collection changes.
+ * After a successful call to `moveNext`, the user doesn't need to cache
+ * the current value, but can keep reading it from the iterator.
+ */
+ E get current;
+}
diff --git a/sdk_nnbd/lib/core/list.dart b/sdk_nnbd/lib/core/list.dart
new file mode 100644
index 0000000..27e1653
--- /dev/null
+++ b/sdk_nnbd/lib/core/list.dart
@@ -0,0 +1,731 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An indexable collection of objects with a length.
+ *
+ * Subclasses of this class implement different kinds of lists.
+ * The most common kinds of lists are:
+ *
+ * * Fixed-length list.
+ * An error occurs when attempting to use operations
+ * that can change the length of the list.
+ *
+ * * Growable list. Full implementation of the API defined in this class.
+ *
+ * The default growable list, as returned by `new List()` or `[]`, keeps
+ * an internal buffer, and grows that buffer when necessary. This guarantees
+ * that a sequence of [add] operations will each execute in amortized constant
+ * time. Setting the length directly may take time proportional to the new
+ * length, and may change the internal capacity so that a following add
+ * operation will need to immediately increase the buffer capacity.
+ * Other list implementations may have different performance behavior.
+ *
+ * The following code illustrates that some List implementations support
+ * only a subset of the API.
+ *
+ * List<int> fixedLengthList = new List(5);
+ * fixedLengthList.length = 0; // Error
+ * fixedLengthList.add(499); // Error
+ * fixedLengthList[0] = 87;
+ * List<int> growableList = [1, 2];
+ * growableList.length = 0;
+ * growableList.add(499);
+ * growableList[0] = 87;
+ *
+ * Lists are [Iterable]. Iteration occurs over values in index order. Changing
+ * the values does not affect iteration, but changing the valid
+ * indices—that is, changing the list's length—between iteration
+ * steps causes a [ConcurrentModificationError]. This means that only growable
+ * lists can throw ConcurrentModificationError. If the length changes
+ * temporarily and is restored before continuing the iteration, the iterator
+ * does not detect it.
+ *
+ * It is generally not allowed to modify the list's length (adding or removing
+ * elements) while an operation on the list is being performed,
+ * for example during a call to [forEach] or [sort].
+ * Changing the list's length while it is being iterated, either by iterating it
+ * directly or through iterating an [Iterable] that is backed by the list, will
+ * break the iteration.
+ */
+abstract class List<E> implements EfficientLengthIterable<E> {
+ /**
+ * Creates a list of the given length.
+ *
+ * The created list is fixed-length if [length] is provided.
+ *
+ * List fixedLengthList = new List(3);
+ * fixedLengthList.length; // 3
+ * fixedLengthList.length = 1; // Error
+ *
+ * The list has length 0 and is growable if [length] is omitted.
+ *
+ * List growableList = new List();
+ * growableList.length; // 0;
+ * growableList.length = 3;
+ *
+ * To create a growable list with a given length, just assign the length
+ * right after creation:
+ *
+ * List growableList = new List()..length = 500;
+ *
+ * The [length] must not be negative or null, if it is provided.
+ */
+ external factory List([int length]);
+
+ /**
+ * Creates a list of the given length with [fill] at each position.
+ *
+ * The [length] must be a non-negative integer.
+ *
+ * Example:
+ * ```dart
+ * new List<int>.filled(3, 0, growable: true); // [0, 0, 0]
+ * ```
+ *
+ * The created list is fixed-length if [growable] is false (the default)
+ * and growable if [growable] is true.
+ * If the list is growable, changing its length will not initialize new
+ * entries with [fill].
+ * After being created and filled, the list is no different from any other
+ * growable or fixed-length list created using [List].
+ *
+ * All elements of the returned list share the same [fill] value.
+ * ```
+ * var shared = new List.filled(3, []);
+ * shared[0].add(499);
+ * print(shared); // => [[499], [499], [499]]
+ * ```
+ *
+ * You can use [List.generate] to create a list with a new object at
+ * each position.
+ * ```
+ * var unique = new List.generate(3, (_) => []);
+ * unique[0].add(499);
+ * print(unique); // => [[499], [], []]
+ * ```
+ */
+ external factory List.filled(int length, E fill, {bool growable = false});
+
+ /**
+ * Creates a list containing all [elements].
+ *
+ * The [Iterator] of [elements] provides the order of the elements.
+ *
+ * All the [elements] should be instances of [E].
+ * The `elements` iterable itself may have any element type, so this
+ * constructor can be used to down-cast a `List`, for example as:
+ * ```dart
+ * List<SuperType> superList = ...;
+ * List<SubType> subList =
+ * new List<SubType>.from(superList.whereType<SubType>());
+ * ```
+ *
+ * This constructor creates a growable list when [growable] is true;
+ * otherwise, it returns a fixed-length list.
+ */
+ external factory List.from(Iterable elements, {bool growable = true});
+
+ /**
+ * Creates a list from [elements].
+ *
+ * The [Iterator] of [elements] provides the order of the elements.
+ *
+ * This constructor creates a growable list when [growable] is true;
+ * otherwise, it returns a fixed-length list.
+ */
+ factory List.of(Iterable<E> elements, {bool growable = true}) =>
+ List<E>.from(elements, growable: growable);
+
+ /**
+ * Generates a list of values.
+ *
+ * Creates a list with [length] positions and fills it with values created by
+ * calling [generator] for each index in the range `0` .. `length - 1`
+ * in increasing order.
+ *
+ * new List<int>.generate(3, (int index) => index * index); // [0, 1, 4]
+ *
+ * The created list is fixed-length unless [growable] is true.
+ */
+ factory List.generate(int length, E generator(int index),
+ {bool growable = true}) {
+ List<E> result;
+ if (growable) {
+ result = <E>[]..length = length;
+ } else {
+ result = List<E>(length);
+ }
+ for (int i = 0; i < length; i++) {
+ result[i] = generator(i);
+ }
+ return result;
+ }
+
+ /**
+ * Creates an unmodifiable list containing all [elements].
+ *
+ * The [Iterator] of [elements] provides the order of the elements.
+ *
+ * An unmodifiable list cannot have its length or elements changed.
+ * If the elements are themselves immutable, then the resulting list
+ * is also immutable.
+ */
+ external factory List.unmodifiable(Iterable elements);
+
+ /**
+ * Adapts [source] to be a `List<T>`.
+ *
+ * Any time the list would produce an element that is not a [T],
+ * the element access will throw.
+ *
+ * Any time a [T] value is attempted stored into the adapted list,
+ * the store will throw unless the value is also an instance of [S].
+ *
+ * If all accessed elements of [source] are actually instances of [T],
+ * and if all elements stored into the returned list are actually instance
+ * of [S],
+ * then the returned list can be used as a `List<T>`.
+ */
+ static List<T> castFrom<S, T>(List<S> source) => CastList<S, T>(source);
+
+ /**
+ * Copy a range of one list into another list.
+ *
+ * This is a utility function that can be used to implement methods like
+ * [setRange].
+ *
+ * The range from [start] to [end] must be a valid range of [source],
+ * and there must be room for `end - start` elements from position [at].
+ * If [start] is omitted, it defaults to zero.
+ * If [end] is omitted, it defaults to [source.length].
+ *
+ * If [source] and [target] is the same list, overlapping source and target
+ * ranges are respected so that the target range ends up containing the
+ * initial content of the source range.
+ * Otherwise the order of element copying is not guaranteed.
+ */
+ static void copyRange<T>(List<T> target, int at, List<T> source,
+ [int start, int end]) {
+ start ??= 0;
+ end = RangeError.checkValidRange(start, end, source.length);
+ int length = end - start;
+ if (target.length < at + length) {
+ throw ArgumentError.value(target, "target",
+ "Not big enough to hold $length elements at position $at");
+ }
+ if (!identical(source, target) || start >= at) {
+ for (int i = 0; i < length; i++) {
+ target[at + i] = source[start + i];
+ }
+ } else {
+ for (int i = length; --i >= 0;) {
+ target[at + i] = source[start + i];
+ }
+ }
+ }
+
+ /**
+ * Write the elements of an iterable into a list.
+ *
+ * This is a utility function that can be used to implement methods like
+ * [setAll].
+ *
+ * The elements of [source] are written into [target] from position [at].
+ * The [source] must not contain more elements after writing the last
+ * position of [target].
+ *
+ * If the source is a list, the [copyRange] function is likely to be more
+ * efficient.
+ */
+ static void writeIterable<T>(List<T> target, int at, Iterable<T> source) {
+ RangeError.checkValueInInterval(at, 0, target.length, "at");
+ int index = at;
+ int targetLength = target.length;
+ for (var element in source) {
+ if (index == targetLength) {
+ throw IndexError(targetLength, target);
+ }
+ target[index] = element;
+ index++;
+ }
+ }
+
+ /**
+ * Returns a view of this list as a list of [R] instances.
+ *
+ * If this list contains only instances of [R], all read operations
+ * will work correctly. If any operation tries to access an element
+ * that is not an instance of [R], the access will throw instead.
+ *
+ * Elements added to the list (e.g., by using [add] or [addAll])
+ * must be instance of [R] to be valid arguments to the adding function,
+ * and they must be instances of [E] as well to be accepted by
+ * this list as well.
+ *
+ * Typically implemented as `List.castFrom<E, R>(this)`.
+ */
+ List<R> cast<R>();
+ /**
+ * Returns the object at the given [index] in the list
+ * or throws a [RangeError] if [index] is out of bounds.
+ */
+ E operator [](int index);
+
+ /**
+ * Sets the value at the given [index] in the list to [value]
+ * or throws a [RangeError] if [index] is out of bounds.
+ */
+ void operator []=(int index, E value);
+
+ /**
+ * Updates the first position of the list to contain [value].
+ *
+ * Equivalent to `theList[0] = value;`.
+ *
+ * The list must be non-empty.
+ */
+ void set first(E value);
+
+ /**
+ * Updates the last position of the list to contain [value].
+ *
+ * Equivalent to `theList[theList.length - 1] = value;`.
+ *
+ * The list must be non-empty.
+ */
+ void set last(E value);
+
+ /**
+ * Returns the number of objects in this list.
+ *
+ * The valid indices for a list are `0` through `length - 1`.
+ */
+ int get length;
+
+ /**
+ * Changes the length of this list.
+ *
+ * If [newLength] is greater than
+ * the current length, entries are initialized to [:null:].
+ *
+ * Throws an [UnsupportedError] if the list is fixed-length.
+ */
+ set length(int newLength);
+
+ /**
+ * Adds [value] to the end of this list,
+ * extending the length by one.
+ *
+ * Throws an [UnsupportedError] if the list is fixed-length.
+ */
+ void add(E value);
+
+ /**
+ * Appends all objects of [iterable] to the end of this list.
+ *
+ * Extends the length of the list by the number of objects in [iterable].
+ * Throws an [UnsupportedError] if this list is fixed-length.
+ */
+ void addAll(Iterable<E> iterable);
+
+ /**
+ * Returns an [Iterable] of the objects in this list in reverse order.
+ */
+ Iterable<E> get reversed;
+
+ /**
+ * Sorts this list according to the order specified by the [compare] function.
+ *
+ * The [compare] function must act as a [Comparator].
+ *
+ * List<String> numbers = ['two', 'three', 'four'];
+ * // Sort from shortest to longest.
+ * numbers.sort((a, b) => a.length.compareTo(b.length));
+ * print(numbers); // [two, four, three]
+ *
+ * The default List implementations use [Comparable.compare] if
+ * [compare] is omitted.
+ *
+ * List<int> nums = [13, 2, -11];
+ * nums.sort();
+ * print(nums); // [-11, 2, 13]
+ *
+ * A [Comparator] may compare objects as equal (return zero), even if they
+ * are distinct objects.
+ * The sort function is not guaranteed to be stable, so distinct objects
+ * that compare as equal may occur in any order in the result:
+ *
+ * List<String> numbers = ['one', 'two', 'three', 'four'];
+ * numbers.sort((a, b) => a.length.compareTo(b.length));
+ * print(numbers); // [one, two, four, three] OR [two, one, four, three]
+ */
+ void sort([int compare(E a, E b)]);
+
+ /**
+ * Shuffles the elements of this list randomly.
+ */
+ void shuffle([Random random]);
+
+ /**
+ * Returns the first index of [element] in this list.
+ *
+ * Searches the list from index [start] to the end of the list.
+ * The first time an object [:o:] is encountered so that [:o == element:],
+ * the index of [:o:] is returned.
+ *
+ * List<String> notes = ['do', 're', 'mi', 're'];
+ * notes.indexOf('re'); // 1
+ * notes.indexOf('re', 2); // 3
+ *
+ * Returns -1 if [element] is not found.
+ *
+ * notes.indexOf('fa'); // -1
+ */
+ int indexOf(E element, [int start = 0]);
+
+ /**
+ * Returns the first index in the list that satisfies the provided [test].
+ *
+ * Searches the list from index [start] to the end of the list.
+ * The first time an object `o` is encountered so that `test(o)` is true,
+ * the index of `o` is returned.
+ *
+ * ```
+ * List<String> notes = ['do', 're', 'mi', 're'];
+ * notes.indexWhere((note) => note.startsWith('r')); // 1
+ * notes.indexWhere((note) => note.startsWith('r'), 2); // 3
+ * ```
+ *
+ * Returns -1 if [element] is not found.
+ * ```
+ * notes.indexWhere((note) => note.startsWith('k')); // -1
+ * ```
+ */
+ int indexWhere(bool test(E element), [int start = 0]);
+
+ /**
+ * Returns the last index in the list that satisfies the provided [test].
+ *
+ * Searches the list from index [start] to 0.
+ * The first time an object `o` is encountered so that `test(o)` is true,
+ * the index of `o` is returned.
+ *
+ * ```
+ * List<String> notes = ['do', 're', 'mi', 're'];
+ * notes.lastIndexWhere((note) => note.startsWith('r')); // 3
+ * notes.lastIndexWhere((note) => note.startsWith('r'), 2); // 1
+ * ```
+ *
+ * Returns -1 if [element] is not found.
+ * ```
+ * notes.lastIndexWhere((note) => note.startsWith('k')); // -1
+ * ```
+ */
+ int lastIndexWhere(bool test(E element), [int start]);
+
+ /**
+ * Returns the last index of [element] in this list.
+ *
+ * Searches the list backwards from index [start] to 0.
+ *
+ * The first time an object [:o:] is encountered so that [:o == element:],
+ * the index of [:o:] is returned.
+ *
+ * List<String> notes = ['do', 're', 'mi', 're'];
+ * notes.lastIndexOf('re', 2); // 1
+ *
+ * If [start] is not provided, this method searches from the end of the
+ * list./Returns
+ *
+ * notes.lastIndexOf('re'); // 3
+ *
+ * Returns -1 if [element] is not found.
+ *
+ * notes.lastIndexOf('fa'); // -1
+ */
+ int lastIndexOf(E element, [int start]);
+
+ /**
+ * Removes all objects from this list;
+ * the length of the list becomes zero.
+ *
+ * Throws an [UnsupportedError], and retains all objects, if this
+ * is a fixed-length list.
+ */
+ void clear();
+
+ /**
+ * Inserts the object at position [index] in this list.
+ *
+ * This increases the length of the list by one and shifts all objects
+ * at or after the index towards the end of the list.
+ *
+ * The list must be growable.
+ * The [index] value must be non-negative and no greater than [length].
+ */
+ void insert(int index, E element);
+
+ /**
+ * Inserts all objects of [iterable] at position [index] in this list.
+ *
+ * This increases the length of the list by the length of [iterable] and
+ * shifts all later objects towards the end of the list.
+ *
+ * The list must be growable.
+ * The [index] value must be non-negative and no greater than [length].
+ */
+ void insertAll(int index, Iterable<E> iterable);
+
+ /**
+ * Overwrites objects of `this` with the objects of [iterable], starting
+ * at position [index] in this list.
+ *
+ * List<String> list = ['a', 'b', 'c'];
+ * list.setAll(1, ['bee', 'sea']);
+ * list.join(', '); // 'a, bee, sea'
+ *
+ * This operation does not increase the length of `this`.
+ *
+ * The [index] must be non-negative and no greater than [length].
+ *
+ * The [iterable] must not have more elements than what can fit from [index]
+ * to [length].
+ *
+ * If `iterable` is based on this list, its values may change /during/ the
+ * `setAll` operation.
+ */
+ void setAll(int index, Iterable<E> iterable);
+
+ /**
+ * Removes the first occurrence of [value] from this list.
+ *
+ * Returns true if [value] was in the list, false otherwise.
+ *
+ * List<String> parts = ['head', 'shoulders', 'knees', 'toes'];
+ * parts.remove('head'); // true
+ * parts.join(', '); // 'shoulders, knees, toes'
+ *
+ * The method has no effect if [value] was not in the list.
+ *
+ * // Note: 'head' has already been removed.
+ * parts.remove('head'); // false
+ * parts.join(', '); // 'shoulders, knees, toes'
+ *
+ * An [UnsupportedError] occurs if the list is fixed-length.
+ */
+ bool remove(Object value);
+
+ /**
+ * Removes the object at position [index] from this list.
+ *
+ * This method reduces the length of `this` by one and moves all later objects
+ * down by one position.
+ *
+ * Returns the removed object.
+ *
+ * The [index] must be in the range `0 ≤ index < length`.
+ *
+ * Throws an [UnsupportedError] if this is a fixed-length list. In that case
+ * the list is not modified.
+ */
+ E removeAt(int index);
+
+ /**
+ * Pops and returns the last object in this list.
+ *
+ * The list must not be empty.
+ *
+ * Throws an [UnsupportedError] if this is a fixed-length list.
+ */
+ E removeLast();
+
+ /**
+ * Removes all objects from this list that satisfy [test].
+ *
+ * An object [:o:] satisfies [test] if [:test(o):] is true.
+ *
+ * List<String> numbers = ['one', 'two', 'three', 'four'];
+ * numbers.removeWhere((item) => item.length == 3);
+ * numbers.join(', '); // 'three, four'
+ *
+ * Throws an [UnsupportedError] if this is a fixed-length list.
+ */
+ void removeWhere(bool test(E element));
+
+ /**
+ * Removes all objects from this list that fail to satisfy [test].
+ *
+ * An object [:o:] satisfies [test] if [:test(o):] is true.
+ *
+ * List<String> numbers = ['one', 'two', 'three', 'four'];
+ * numbers.retainWhere((item) => item.length == 3);
+ * numbers.join(', '); // 'one, two'
+ *
+ * Throws an [UnsupportedError] if this is a fixed-length list.
+ */
+ void retainWhere(bool test(E element));
+
+ /**
+ * Returns the concatenation of this list and [other].
+ *
+ * Returns a new list containing the elements of this list followed by
+ * the elements of [other].
+ *
+ * The default behavior is to return a normal growable list.
+ * Some list types may choose to return a list of the same type as themselves
+ * (see [Uint8List.+]);
+ */
+ List<E> operator +(List<E> other);
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is a `List<E>` containing the elements of this list at
+ * positions greater than or equal to [start] and less than [end] in the same
+ * order as they occur in this list.
+ *
+ * ```dart
+ * var colors = ["red", "green", "blue", "orange", "pink"];
+ * print(colors.sublist(1, 3)); // [green, blue]
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(colors.sublist(1)); // [green, blue, orange, pink]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ List<E> sublist(int start, [int end]);
+
+ /**
+ * Returns an [Iterable] that iterates over the objects in the range
+ * [start] inclusive to [end] exclusive.
+ *
+ * The provided range, given by [start] and [end], must be valid at the time
+ * of the call.
+ *
+ * A range from [start] to [end] is valid if `0 <= start <= end <= len`, where
+ * `len` is this list's `length`. The range starts at `start` and has length
+ * `end - start`. An empty range (with `end == start`) is valid.
+ *
+ * The returned [Iterable] behaves like `skip(start).take(end - start)`.
+ * That is, it does *not* throw if this list changes size.
+ *
+ * List<String> colors = ['red', 'green', 'blue', 'orange', 'pink'];
+ * Iterable<String> range = colors.getRange(1, 4);
+ * range.join(', '); // 'green, blue, orange'
+ * colors.length = 3;
+ * range.join(', '); // 'green, blue'
+ */
+ Iterable<E> getRange(int start, int end);
+
+ /**
+ * Copies the objects of [iterable], skipping [skipCount] objects first,
+ * into the range [start], inclusive, to [end], exclusive, of the list.
+ *
+ * List<int> list1 = [1, 2, 3, 4];
+ * List<int> list2 = [5, 6, 7, 8, 9];
+ * // Copies the 4th and 5th items in list2 as the 2nd and 3rd items
+ * // of list1.
+ * list1.setRange(1, 3, list2, 3);
+ * list1.join(', '); // '1, 8, 9, 4'
+ *
+ * The provided range, given by [start] and [end], must be valid.
+ * A range from [start] to [end] is valid if `0 <= start <= end <= len`, where
+ * `len` is this list's `length`. The range starts at `start` and has length
+ * `end - start`. An empty range (with `end == start`) is valid.
+ *
+ * The [iterable] must have enough objects to fill the range from `start`
+ * to `end` after skipping [skipCount] objects.
+ *
+ * If `iterable` is this list, the operation copies the elements
+ * originally in the range from `skipCount` to `skipCount + (end - start)` to
+ * the range `start` to `end`, even if the two ranges overlap.
+ *
+ * If `iterable` depends on this list in some other way, no guarantees are
+ * made.
+ */
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]);
+
+ /**
+ * Removes the objects in the range [start] inclusive to [end] exclusive.
+ *
+ * The provided range, given by [start] and [end], must be valid.
+ * A range from [start] to [end] is valid if `0 <= start <= end <= len`, where
+ * `len` is this list's `length`. The range starts at `start` and has length
+ * `end - start`. An empty range (with `end == start`) is valid.
+ *
+ * Throws an [UnsupportedError] if this is a fixed-length list. In that case
+ * the list is not modified.
+ */
+ void removeRange(int start, int end);
+
+ /**
+ * Sets the objects in the range [start] inclusive to [end] exclusive
+ * to the given [fillValue].
+ *
+ * The provided range, given by [start] and [end], must be valid.
+ * A range from [start] to [end] is valid if `0 <= start <= end <= len`, where
+ * `len` is this list's `length`. The range starts at `start` and has length
+ * `end - start`. An empty range (with `end == start`) is valid.
+ *
+ * Example:
+ * ```dart
+ * List<int> list = new List(3);
+ * list.fillRange(0, 2, 1);
+ * print(list); // [1, 1, null]
+ * ```
+ *
+ */
+ void fillRange(int start, int end, [E fillValue]);
+
+ /**
+ * Removes the objects in the range [start] inclusive to [end] exclusive
+ * and inserts the contents of [replacement] in its place.
+ *
+ * List<int> list = [1, 2, 3, 4, 5];
+ * list.replaceRange(1, 4, [6, 7]);
+ * list.join(', '); // '1, 6, 7, 5'
+ *
+ * The provided range, given by [start] and [end], must be valid.
+ * A range from [start] to [end] is valid if `0 <= start <= end <= len`, where
+ * `len` is this list's `length`. The range starts at `start` and has length
+ * `end - start`. An empty range (with `end == start`) is valid.
+ *
+ * This method does not work on fixed-length lists, even when [replacement]
+ * has the same number of elements as the replaced range. In that case use
+ * [setRange] instead.
+ */
+ void replaceRange(int start, int end, Iterable<E> replacement);
+
+ /**
+ * Returns an unmodifiable [Map] view of `this`.
+ *
+ * The map uses the indices of this list as keys and the corresponding objects
+ * as values. The `Map.keys` [Iterable] iterates the indices of this list
+ * in numerical order.
+ *
+ * List<String> words = ['fee', 'fi', 'fo', 'fum'];
+ * Map<int, String> map = words.asMap();
+ * map[0] + map[1]; // 'feefi';
+ * map.keys.toList(); // [0, 1, 2, 3]
+ */
+ Map<int, E> asMap();
+
+ /**
+ * Whether this list is equal to [other].
+ *
+ * Lists are, by default, only equal to themselves.
+ * Even if [other] is also a list, the equality comparison
+ * does not compare the elements of the two lists.
+ */
+ bool operator ==(Object other);
+}
diff --git a/sdk_nnbd/lib/core/map.dart b/sdk_nnbd/lib/core/map.dart
new file mode 100644
index 0000000..f914fe1
--- /dev/null
+++ b/sdk_nnbd/lib/core/map.dart
@@ -0,0 +1,404 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A collection of key/value pairs, from which you retrieve a value
+ * using its associated key.
+ *
+ * There is a finite number of keys in the map,
+ * and each key has exactly one value associated with it.
+ *
+ * Maps, and their keys and values, can be iterated.
+ * The order of iteration is defined by the individual type of map.
+ * Examples:
+ *
+ * * The plain [HashMap] is unordered (no order is guaranteed),
+ * * the [LinkedHashMap] iterates in key insertion order,
+ * * and a sorted map like [SplayTreeMap] iterates the keys in sorted order.
+ *
+ * It is generally not allowed to modify the map (add or remove keys) while
+ * an operation is being performed on the map, for example in functions called
+ * during a [forEach] or [putIfAbsent] call.
+ * Modifying the map while iterating the keys or values
+ * may also break the iteration.
+ *
+ * It is generally not allowed to modify the equality of keys (and thus not
+ * their hashcode) while they are in the map. Some specialized subtypes may be
+ * more permissive, in which case they should document this behavior.
+ */
+abstract class Map<K, V> {
+ /**
+ * Creates a Map instance with the default implementation, [LinkedHashMap].
+ *
+ * This constructor is equivalent to the non-const map literal `<K,V>{}`.
+ *
+ * A `LinkedHashMap` requires the keys to implement compatible
+ * `operator==` and `hashCode`, and it allows null as a key.
+ * It iterates in key insertion order.
+ */
+ external factory Map();
+
+ /**
+ * Creates a [LinkedHashMap] instance that contains all key/value pairs of
+ * [other].
+ *
+ * The keys must all be instances of [K] and the values of [V].
+ * The [other] map itself can have any type.
+ *
+ * A `LinkedHashMap` requires the keys to implement compatible
+ * `operator==` and `hashCode`, and it allows `null` as a key.
+ * It iterates in key insertion order.
+ */
+ factory Map.from(Map other) = LinkedHashMap<K, V>.from;
+
+ /**
+ * Creates a [LinkedHashMap] with the same keys and values as [other].
+ *
+ * A `LinkedHashMap` requires the keys to implement compatible
+ * `operator==` and `hashCode`, and it allows `null` as a key.
+ * It iterates in key insertion order.
+ */
+ factory Map.of(Map<K, V> other) = LinkedHashMap<K, V>.of;
+
+ /**
+ * Creates an unmodifiable hash based map containing the entries of [other].
+ *
+ * The keys must all be instances of [K] and the values of [V].
+ * The [other] map itself can have any type.
+ *
+ * The map requires the keys to implement compatible
+ * `operator==` and `hashCode`, and it allows `null` as a key.
+ * The created map iterates keys in a fixed order,
+ * preserving the order provided by [other].
+ *
+ * The resulting map behaves like the result of [Map.from],
+ * except that the map returned by this constructor is not modifiable.
+ */
+ external factory Map.unmodifiable(Map other);
+
+ /**
+ * Creates an identity map with the default implementation, [LinkedHashMap].
+ *
+ * An identity map uses [identical] for equality and [identityHashCode]
+ * for hash codes of keys instead of the intrinsic [Object.operator==] and
+ * [Object.hashCode] of the keys.
+ *
+ * The returned map allows `null` as a key.
+ * It iterates in key insertion order.
+ */
+ factory Map.identity() = LinkedHashMap<K, V>.identity;
+
+ /**
+ * Creates a Map instance in which the keys and values are computed from the
+ * [iterable].
+ *
+ * The created map is a [LinkedHashMap].
+ * A `LinkedHashMap` requires the keys to implement compatible
+ * `operator==` and `hashCode`, and it allows null as a key.
+ * It iterates in key insertion order.
+ *
+ * For each element of the [iterable] this constructor computes a key/value
+ * pair, by applying [key] and [value] respectively.
+ *
+ * The example below creates a new Map from a List. The keys of `map` are
+ * `list` values converted to strings, and the values of the `map` are the
+ * squares of the `list` values:
+ *
+ * List<int> list = [1, 2, 3];
+ * Map<String, int> map = new Map.fromIterable(list,
+ * key: (item) => item.toString(),
+ * value: (item) => item * item);
+ *
+ * map['1'] + map['2']; // 1 + 4
+ * map['3'] - map['2']; // 9 - 4
+ *
+ * If no values are specified for [key] and [value] the default is the
+ * identity function.
+ *
+ * In the following example, the keys and corresponding values of `map`
+ * are `list` values:
+ *
+ * map = new Map.fromIterable(list);
+ * map[1] + map[2]; // 1 + 2
+ * map[3] - map[2]; // 3 - 2
+ *
+ * The keys computed by the source [iterable] do not need to be unique. The
+ * last occurrence of a key will simply overwrite any previous value.
+ */
+ factory Map.fromIterable(Iterable iterable,
+ {K key(element), V value(element)}) = LinkedHashMap<K, V>.fromIterable;
+
+ /**
+ * Creates a Map instance associating the given [keys] to [values].
+ *
+ * The created map is a [LinkedHashMap].
+ * A `LinkedHashMap` requires the keys to implement compatible
+ * `operator==` and `hashCode`, and it allows null as a key.
+ * It iterates in key insertion order.
+ *
+ * This constructor iterates over [keys] and [values] and maps each element of
+ * [keys] to the corresponding element of [values].
+ *
+ * List<String> letters = ['b', 'c'];
+ * List<String> words = ['bad', 'cat'];
+ * Map<String, String> map = new Map.fromIterables(letters, words);
+ * map['b'] + map['c']; // badcat
+ *
+ * If [keys] contains the same object multiple times, the last occurrence
+ * overwrites the previous value.
+ *
+ * The two [Iterable]s must have the same length.
+ */
+ factory Map.fromIterables(Iterable<K> keys, Iterable<V> values) =
+ LinkedHashMap<K, V>.fromIterables;
+
+ /**
+ * Adapts [source] to be a `Map<K2, V2>`.
+ *
+ * Any time the set would produce a key or value that is not a [K2] or [V2],
+ * the access will throw.
+ *
+ * Any time [K2] key or [V2] value is attempted added into the adapted map,
+ * the store will throw unless the key is also an instance of [K] and
+ * the value is also an instance of [V].
+ *
+ * If all accessed entries of [source] are have [K2] keys and [V2] values
+ * and if all entries added to the returned map have [K] keys and [V]] values,
+ * then the returned map can be used as a `Map<K2, V2>`.
+ */
+ static Map<K2, V2> castFrom<K, V, K2, V2>(Map<K, V> source) =>
+ CastMap<K, V, K2, V2>(source);
+
+ /**
+ * Creates a new map and adds all entries.
+ *
+ * Returns a new `Map<K, V>` where all entries of [entries]
+ * have been added in iteration order.
+ *
+ * If multiple [entries] have the same key,
+ * later occurrences overwrite the earlier ones.
+ */
+ factory Map.fromEntries(Iterable<MapEntry<K, V>> entries) =>
+ <K, V>{}..addEntries(entries);
+
+ /**
+ * Provides a view of this map as having [RK] keys and [RV] instances,
+ * if necessary.
+ *
+ * If this map is already a `Map<RK, RV>`, it is returned unchanged.
+ *
+ * If this set contains only keys of type [RK] and values of type [RV],
+ * all read operations will work correctly.
+ * If any operation exposes a non-[RK] key or non-[RV] value,
+ * the operation will throw instead.
+ *
+ * Entries added to the map must be valid for both a `Map<K, V>` and a
+ * `Map<RK, RV>`.
+ */
+ Map<RK, RV> cast<RK, RV>();
+ /**
+ * Returns true if this map contains the given [value].
+ *
+ * Returns true if any of the values in the map are equal to `value`
+ * according to the `==` operator.
+ */
+ bool containsValue(Object value);
+
+ /**
+ * Returns true if this map contains the given [key].
+ *
+ * Returns true if any of the keys in the map are equal to `key`
+ * according to the equality used by the map.
+ */
+ bool containsKey(Object key);
+
+ /**
+ * Returns the value for the given [key] or null if [key] is not in the map.
+ *
+ * Some maps allow keys to have `null` as a value.
+ * For those maps, a lookup using this operator cannot distinguish between a
+ * key not being in the map and the key having a `null` value.
+ * Methods like [containsKey] or [putIfAbsent] can be used if the distinction
+ * is important.
+ */
+ V operator [](Object key);
+
+ /**
+ * Associates the [key] with the given [value].
+ *
+ * If the key was already in the map, its associated value is changed.
+ * Otherwise the key/value pair is added to the map.
+ */
+ void operator []=(K key, V value);
+
+ /**
+ * The map entries of [this].
+ */
+ Iterable<MapEntry<K, V>> get entries;
+
+ /**
+ * Returns a new map where all entries of this map are transformed by
+ * the given [f] function.
+ */
+ Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> f(K key, V value));
+
+ /**
+ * Adds all key/value pairs of [newEntries] to this map.
+ *
+ * If a key of [newEntries] is already in this map,
+ * the corresponding value is overwritten.
+ *
+ * The operation is equivalent to doing `this[entry.key] = entry.value`
+ * for each [MapEntry] of the iterable.
+ */
+ void addEntries(Iterable<MapEntry<K, V>> newEntries);
+
+ /**
+ * Updates the value for the provided [key].
+ *
+ * Returns the new value of the key.
+ *
+ * If the key is present, invokes [update] with the current value and stores
+ * the new value in the map.
+ *
+ * If the key is not present and [ifAbsent] is provided, calls [ifAbsent]
+ * and adds the key with the returned value to the map.
+ *
+ * It's an error if the key is not present and [ifAbsent] is not provided.
+ */
+ V update(K key, V update(V value), {V ifAbsent()});
+
+ /**
+ * Updates all values.
+ *
+ * Iterates over all entries in the map and updates them with the result
+ * of invoking [update].
+ */
+ void updateAll(V update(K key, V value));
+
+ /**
+ * Removes all entries of this map that satisfy the given [predicate].
+ */
+ void removeWhere(bool predicate(K key, V value));
+
+ /**
+ * Look up the value of [key], or add a new value if it isn't there.
+ *
+ * Returns the value associated to [key], if there is one.
+ * Otherwise calls [ifAbsent] to get a new value, associates [key] to
+ * that value, and then returns the new value.
+ *
+ * Map<String, int> scores = {'Bob': 36};
+ * for (var key in ['Bob', 'Rohan', 'Sophena']) {
+ * scores.putIfAbsent(key, () => key.length);
+ * }
+ * scores['Bob']; // 36
+ * scores['Rohan']; // 5
+ * scores['Sophena']; // 7
+ *
+ * Calling [ifAbsent] must not add or remove keys from the map.
+ */
+ V putIfAbsent(K key, V ifAbsent());
+
+ /**
+ * Adds all key/value pairs of [other] to this map.
+ *
+ * If a key of [other] is already in this map, its value is overwritten.
+ *
+ * The operation is equivalent to doing `this[key] = value` for each key
+ * and associated value in other. It iterates over [other], which must
+ * therefore not change during the iteration.
+ */
+ void addAll(Map<K, V> other);
+
+ /**
+ * Removes [key] and its associated value, if present, from the map.
+ *
+ * Returns the value associated with `key` before it was removed.
+ * Returns `null` if `key` was not in the map.
+ *
+ * Note that values can be `null` and a returned `null` value doesn't
+ * always mean that the key was absent.
+ */
+ V remove(Object key);
+
+ /**
+ * Removes all pairs from the map.
+ *
+ * After this, the map is empty.
+ */
+ void clear();
+
+ /**
+ * Applies [f] to each key/value pair of the map.
+ *
+ * Calling `f` must not add or remove keys from the map.
+ */
+ void forEach(void f(K key, V value));
+
+ /**
+ * The keys of [this].
+ *
+ * The returned iterable has efficient `length` and `contains` operations,
+ * based on [length] and [containsKey] of the map.
+ *
+ * The order of iteration is defined by the individual `Map` implementation,
+ * but must be consistent between changes to the map.
+ *
+ * Modifying the map while iterating the keys
+ * may break the iteration.
+ */
+ Iterable<K> get keys;
+
+ /**
+ * The values of [this].
+ *
+ * The values are iterated in the order of their corresponding keys.
+ * This means that iterating [keys] and [values] in parallel will
+ * provide matching pairs of keys and values.
+ *
+ * The returned iterable has an efficient `length` method based on the
+ * [length] of the map. Its [Iterable.contains] method is based on
+ * `==` comparison.
+ *
+ * Modifying the map while iterating the
+ * values may break the iteration.
+ */
+ Iterable<V> get values;
+
+ /**
+ * The number of key/value pairs in the map.
+ */
+ int get length;
+
+ /**
+ * Returns true if there is no key/value pair in the map.
+ */
+ bool get isEmpty;
+
+ /**
+ * Returns true if there is at least one key/value pair in the map.
+ */
+ bool get isNotEmpty;
+}
+
+/**
+ * A key/value pair representing an entry in a [Map].
+ */
+class MapEntry<K, V> {
+ /** The key of the entry. */
+ final K key;
+
+ /** The value associated to [key] in the map. */
+ final V value;
+
+ /** Creates an entry with [key] and [value]. */
+ const factory MapEntry(K key, V value) = MapEntry<K, V>._;
+
+ const MapEntry._(this.key, this.value);
+
+ String toString() => "MapEntry($key: $value)";
+}
diff --git a/sdk_nnbd/lib/core/null.dart b/sdk_nnbd/lib/core/null.dart
new file mode 100644
index 0000000..af7d86d
--- /dev/null
+++ b/sdk_nnbd/lib/core/null.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * The reserved word [:null:] denotes an object that is the sole instance of
+ * this class.
+ *
+ * It is a compile-time error for a class to attempt to extend or implement
+ * Null.
+ */
+@pragma("vm:entry-point")
+class Null {
+ factory Null._uninstantiable() {
+ throw UnsupportedError('class Null cannot be instantiated');
+ }
+
+ external int get hashCode;
+
+ /** Returns the string `"null"`. */
+ String toString() => "null";
+}
diff --git a/sdk_nnbd/lib/core/num.dart b/sdk_nnbd/lib/core/num.dart
new file mode 100644
index 0000000..e04112c
--- /dev/null
+++ b/sdk_nnbd/lib/core/num.dart
@@ -0,0 +1,493 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An integer or floating-point number.
+ *
+ * It is a compile-time error for any type other than [int] or [double]
+ * to attempt to extend or implement num.
+ */
+abstract class num implements Comparable<num> {
+ /**
+ * Test whether this value is numerically equal to `other`.
+ *
+ * If both operands are doubles, they are equal if they have the same
+ * representation, except that:
+ *
+ * * zero and minus zero (0.0 and -0.0) are considered equal. They
+ * both have the numerical value zero.
+ * * NaN is not equal to anything, including NaN. If either operand is
+ * NaN, the result is always false.
+ *
+ * If one operand is a double and the other is an int, they are equal if
+ * the double has an integer value (finite with no fractional part) and
+ * `identical(doubleValue.toInt(), intValue)` is true.
+ *
+ * If both operands are integers, they are equal if they have the same value.
+ *
+ * Returns false if `other` is not a [num].
+ *
+ * Notice that the behavior for NaN is non-reflexive. This means that
+ * equality of double values is not a proper equality relation, as is
+ * otherwise required of `operator==`. Using NaN in, e.g., a [HashSet]
+ * will fail to work. The behavior is the standard IEEE-754 equality of
+ * doubles.
+ *
+ * If you can avoid NaN values, the remaining doubles do have a proper
+ * equality relation, and can be used safely.
+ *
+ * Use [compareTo] for a comparison that distinguishes zero and minus zero,
+ * and that considers NaN values as equal.
+ */
+ bool operator ==(Object other);
+
+ /**
+ * Returns a hash code for a numerical value.
+ *
+ * The hash code is compatible with equality. It returns the same value
+ * for an [int] and a [double] with the same numerical value, and therefore
+ * the same value for the doubles zero and minus zero.
+ *
+ * No guarantees are made about the hash code of NaN values.
+ */
+ int get hashCode;
+
+ /**
+ * Compares this to `other`.
+ *
+ * Returns a negative number if `this` is less than `other`, zero if they are
+ * equal, and a positive number if `this` is greater than `other`.
+ *
+ * The ordering represented by this method is a total ordering of [num]
+ * values. All distinct doubles are non-equal, as are all distinct integers,
+ * but integers are equal to doubles if they have the same numerical
+ * value.
+ *
+ * For doubles, the `compareTo` operation is different from the partial
+ * ordering given by [operator==], [operator<] and [operator>]. For example,
+ * IEEE doubles impose that `0.0 == -0.0` and all comparison operations on
+ * NaN return false.
+ *
+ * This function imposes a complete ordering for doubles. When using
+ * `compareTo` the following properties hold:
+ *
+ * - All NaN values are considered equal, and greater than any numeric value.
+ * - -0.0 is less than 0.0 (and the integer 0), but greater than any non-zero
+ * negative value.
+ * - Negative infinity is less than all other values and positive infinity is
+ * greater than all non-NaN values.
+ * - All other values are compared using their numeric value.
+ *
+ * Examples:
+ * ```
+ * print(1.compareTo(2)); // => -1
+ * print(2.compareTo(1)); // => 1
+ * print(1.compareTo(1)); // => 0
+ *
+ * // The following comparisons yield different results than the
+ * // corresponding comparison operators.
+ * print((-0.0).compareTo(0.0)); // => -1
+ * print(double.nan.compareTo(double.nan)); // => 0
+ * print(double.infinity.compareTo(double.nan)); // => -1
+ *
+ * // -0.0, and NaN comparison operators have rules imposed by the IEEE
+ * // standard.
+ * print(-0.0 == 0.0); // => true
+ * print(double.nan == double.nan); // => false
+ * print(double.infinity < double.nan); // => false
+ * print(double.nan < double.infinity); // => false
+ * print(double.nan == double.infinity); // => false
+ * ```
+ */
+ int compareTo(num other);
+
+ /** Addition operator. */
+ num operator +(num other);
+
+ /** Subtraction operator. */
+ num operator -(num other);
+
+ /** Multiplication operator. */
+ num operator *(num other);
+
+ /**
+ * Euclidean modulo operator.
+ *
+ * Returns the remainder of the Euclidean division. The Euclidean division of
+ * two integers `a` and `b` yields two integers `q` and `r` such that
+ * `a == b * q + r` and `0 <= r < b.abs()`.
+ *
+ * The Euclidean division is only defined for integers, but can be easily
+ * extended to work with doubles. In that case `r` may have a non-integer
+ * value, but it still verifies `0 <= r < |b|`.
+ *
+ * The sign of the returned value `r` is always positive.
+ *
+ * See [remainder] for the remainder of the truncating division.
+ */
+ num operator %(num other);
+
+ /** Division operator. */
+ double operator /(num other);
+
+ /**
+ * Truncating division operator.
+ *
+ * If either operand is a [double] then the result of the truncating division
+ * `a ~/ b` is equivalent to `(a / b).truncate().toInt()`.
+ *
+ * If both operands are [int]s then `a ~/ b` performs the truncating
+ * integer division.
+ */
+ int operator ~/(num other);
+
+ /** Negate operator. */
+ num operator -();
+
+ /**
+ * Returns the remainder of the truncating division of `this` by [other].
+ *
+ * The result `r` of this operation satisfies:
+ * `this == (this ~/ other) * other + r`.
+ * As a consequence the remainder `r` has the same sign as the divider `this`.
+ */
+ num remainder(num other);
+
+ /** Relational less than operator. */
+ bool operator <(num other);
+
+ /** Relational less than or equal operator. */
+ bool operator <=(num other);
+
+ /** Relational greater than operator. */
+ bool operator >(num other);
+
+ /** Relational greater than or equal operator. */
+ bool operator >=(num other);
+
+ /** True if the number is the double Not-a-Number value; otherwise, false. */
+ bool get isNaN;
+
+ /**
+ * True if the number is negative; otherwise, false.
+ *
+ * Negative numbers are those less than zero, and the double `-0.0`.
+ */
+ bool get isNegative;
+
+ /**
+ * True if the number is positive infinity or negative infinity; otherwise,
+ * false.
+ */
+ bool get isInfinite;
+
+ /**
+ * True if the number is finite; otherwise, false.
+ *
+ * The only non-finite numbers are NaN, positive infinity, and
+ * negative infinity.
+ */
+ bool get isFinite;
+
+ /** Returns the absolute value of this [num]. */
+ num abs();
+
+ /**
+ * Returns minus one, zero or plus one depending on the sign and
+ * numerical value of the number.
+ *
+ * Returns minus one if the number is less than zero,
+ * plus one if the number is greater than zero,
+ * and zero if the number is equal to zero.
+ *
+ * Returns NaN if the number is the double NaN value.
+ *
+ * Returns a number of the same type as this number.
+ * For doubles, `-0.0.sign == -0.0`.
+
+ * The result satisfies:
+ *
+ * n == n.sign * n.abs()
+ *
+ * for all numbers `n` (except NaN, because NaN isn't `==` to itself).
+ */
+ num get sign;
+
+ /**
+ * Returns the integer closest to `this`.
+ *
+ * Rounds away from zero when there is no closest integer:
+ * `(3.5).round() == 4` and `(-3.5).round() == -4`.
+ *
+ * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+ */
+ int round();
+
+ /**
+ * Returns the greatest integer no greater than `this`.
+ *
+ * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+ */
+ int floor();
+
+ /**
+ * Returns the least integer no smaller than `this`.
+ *
+ * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+ */
+ int ceil();
+
+ /**
+ * Returns the integer obtained by discarding any fractional
+ * digits from `this`.
+ *
+ * If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError].
+ */
+ int truncate();
+
+ /**
+ * Returns the double integer value closest to `this`.
+ *
+ * Rounds away from zero when there is no closest integer:
+ * `(3.5).roundToDouble() == 4` and `(-3.5).roundToDouble() == -4`.
+ *
+ * If this is already an integer valued double, including `-0.0`, or it is a
+ * non-finite double value, the value is returned unmodified.
+ *
+ * For the purpose of rounding, `-0.0` is considered to be below `0.0`,
+ * and `-0.0` is therefore considered closer to negative numbers than `0.0`.
+ * This means that for a value, `d` in the range `-0.5 < d < 0.0`,
+ * the result is `-0.0`.
+ *
+ * The result is always a double.
+ * If this is a numerically large integer, the result may be an infinite
+ * double.
+ */
+ double roundToDouble();
+
+ /**
+ * Returns the greatest double integer value no greater than `this`.
+ *
+ * If this is already an integer valued double, including `-0.0`, or it is a
+ * non-finite double value, the value is returned unmodified.
+ *
+ * For the purpose of rounding, `-0.0` is considered to be below `0.0`.
+ * A number `d` in the range `0.0 < d < 1.0` will return `0.0`.
+ *
+ * The result is always a double.
+ * If this is a numerically large integer, the result may be an infinite
+ * double.
+ */
+ double floorToDouble();
+
+ /**
+ * Returns the least double integer value no smaller than `this`.
+ *
+ * If this is already an integer valued double, including `-0.0`, or it is a
+ * non-finite double value, the value is returned unmodified.
+ *
+ * For the purpose of rounding, `-0.0` is considered to be below `0.0`.
+ * A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`.
+ *
+ * The result is always a double.
+ * If this is a numerically large integer, the result may be an infinite
+ * double.
+ */
+ double ceilToDouble();
+
+ /**
+ * Returns the double integer value obtained by discarding any fractional
+ * digits from the double value of `this`.
+ *
+ * If this is already an integer valued double, including `-0.0`, or it is a
+ * non-finite double value, the value is returned unmodified.
+ *
+ * For the purpose of rounding, `-0.0` is considered to be below `0.0`.
+ * A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`, and
+ * in the range `0.0 < d < 1.0` it will return 0.0.
+ *
+ * The result is always a double.
+ * If this is a numerically large integer, the result may be an infinite
+ * double.
+ */
+ double truncateToDouble();
+
+ /**
+ * Returns this [num] clamped to be in the range [lowerLimit]-[upperLimit].
+ *
+ * The comparison is done using [compareTo] and therefore takes `-0.0` into
+ * account. This also implies that [double.nan] is treated as the maximal
+ * double value.
+ *
+ * The arguments [lowerLimit] and [upperLimit] must form a valid range where
+ * `lowerLimit.compareTo(upperLimit) <= 0`.
+ */
+ num clamp(num lowerLimit, num upperLimit);
+
+ /** Truncates this [num] to an integer and returns the result as an [int]. */
+ int toInt();
+
+ /**
+ * Return this [num] as a [double].
+ *
+ * If the number is not representable as a [double], an
+ * approximation is returned. For numerically large integers, the
+ * approximation may be infinite.
+ */
+ double toDouble();
+
+ /**
+ * Returns a decimal-point string-representation of `this`.
+ *
+ * Converts `this` to a [double] before computing the string representation.
+ *
+ * If the absolute value of `this` is greater or equal to `10^21` then this
+ * methods returns an exponential representation computed by
+ * `this.toStringAsExponential()`. Otherwise the result
+ * is the closest string representation with exactly [fractionDigits] digits
+ * after the decimal point. If [fractionDigits] equals 0 then the decimal
+ * point is omitted.
+ *
+ * The parameter [fractionDigits] must be an integer satisfying:
+ * `0 <= fractionDigits <= 20`.
+ *
+ * Examples:
+ *
+ * 1.toStringAsFixed(3); // 1.000
+ * (4321.12345678).toStringAsFixed(3); // 4321.123
+ * (4321.12345678).toStringAsFixed(5); // 4321.12346
+ * 123456789012345678901.toStringAsFixed(3); // 123456789012345683968.000
+ * 1000000000000000000000.toStringAsFixed(3); // 1e+21
+ * 5.25.toStringAsFixed(0); // 5
+ */
+ String toStringAsFixed(int fractionDigits);
+
+ /**
+ * Returns an exponential string-representation of `this`.
+ *
+ * Converts `this` to a [double] before computing the string representation.
+ *
+ * If [fractionDigits] is given then it must be an integer satisfying:
+ * `0 <= fractionDigits <= 20`. In this case the string contains exactly
+ * [fractionDigits] after the decimal point. Otherwise, without the parameter,
+ * the returned string uses the shortest number of digits that accurately
+ * represent [this].
+ *
+ * If [fractionDigits] equals 0 then the decimal point is omitted.
+ * Examples:
+ *
+ * 1.toStringAsExponential(); // 1e+0
+ * 1.toStringAsExponential(3); // 1.000e+0
+ * 123456.toStringAsExponential(); // 1.23456e+5
+ * 123456.toStringAsExponential(3); // 1.235e+5
+ * 123.toStringAsExponential(0); // 1e+2
+ */
+ String toStringAsExponential([int fractionDigits]);
+
+ /**
+ * Converts `this` to a double and returns a string representation with
+ * exactly [precision] significant digits.
+ *
+ * The parameter [precision] must be an integer satisfying:
+ * `1 <= precision <= 21`.
+ *
+ * Examples:
+ *
+ * 1.toStringAsPrecision(2); // 1.0
+ * 1e15.toStringAsPrecision(3); // 1.00e+15
+ * 1234567.toStringAsPrecision(3); // 1.23e+6
+ * 1234567.toStringAsPrecision(9); // 1234567.00
+ * 12345678901234567890.toStringAsPrecision(20); // 12345678901234567168
+ * 12345678901234567890.toStringAsPrecision(14); // 1.2345678901235e+19
+ * 0.00000012345.toStringAsPrecision(15); // 1.23450000000000e-7
+ * 0.0000012345.toStringAsPrecision(15); // 0.00000123450000000000
+ */
+ String toStringAsPrecision(int precision);
+
+ /**
+ * Returns the shortest string that correctly represent the input number.
+ *
+ * All [double]s in the range `10^-6` (inclusive) to `10^21` (exclusive)
+ * are converted to their decimal representation with at least one digit
+ * after the decimal point. For all other doubles,
+ * except for special values like `NaN` or `Infinity`, this method returns an
+ * exponential representation (see [toStringAsExponential]).
+ *
+ * Returns `"NaN"` for [double.nan], `"Infinity"` for [double.infinity], and
+ * `"-Infinity"` for [double.negativeInfinity].
+ *
+ * An [int] is converted to a decimal representation with no decimal point.
+ *
+ * Examples:
+ *
+ * (0.000001).toString(); // "0.000001"
+ * (0.0000001).toString(); // "1e-7"
+ * (111111111111111111111.0).toString(); // "111111111111111110000.0"
+ * (100000000000000000000.0).toString(); // "100000000000000000000.0"
+ * (1000000000000000000000.0).toString(); // "1e+21"
+ * (1111111111111111111111.0).toString(); // "1.1111111111111111e+21"
+ * 1.toString(); // "1"
+ * 111111111111111111111.toString(); // "111111111111111110000"
+ * 100000000000000000000.toString(); // "100000000000000000000"
+ * 1000000000000000000000.toString(); // "1000000000000000000000"
+ * 1111111111111111111111.toString(); // "1111111111111111111111"
+ * 1.234e5.toString(); // 123400
+ * 1234.5e6.toString(); // 1234500000
+ * 12.345e67.toString(); // 1.2345e+68
+ *
+ * Note: the conversion may round the output if the returned string
+ * is accurate enough to uniquely identify the input-number.
+ * For example the most precise representation of the [double] `9e59` equals
+ * `"899999999999999918767229449717619953810131273674690656206848"`, but
+ * this method returns the shorter (but still uniquely identifying) `"9e59"`.
+ *
+ */
+ String toString();
+
+ /**
+ * Parses a string containing a number literal into a number.
+ *
+ * The method first tries to read the [input] as integer (similar to
+ * [int.parse] without a radix).
+ * If that fails, it tries to parse the [input] as a double (similar to
+ * [double.parse]).
+ * If that fails, too, it invokes [onError] with [input], and the result
+ * of that invocation becomes the result of calling `parse`.
+ *
+ * If no [onError] is supplied, it defaults to a function that throws a
+ * [FormatException].
+ *
+ * For any number `n`, this function satisfies
+ * `identical(n, num.parse(n.toString()))` (except when `n` is a NaN `double`
+ * with a payload).
+ *
+ * The [onError] parameter is deprecated and will be removed.
+ * Instead of `num.parse(string, (string) { ... })`,
+ * you should use `num.tryParse(string) ?? (...)`.
+ */
+ static num parse(String input, [@deprecated num onError(String input)]) {
+ num result = tryParse(input);
+ if (result != null) return result;
+ if (onError == null) throw FormatException(input);
+ return onError(input);
+ }
+
+ /**
+ * Parses a string containing a number literal into a number.
+ *
+ * Like [parse] except that this function returns `null` for invalid inputs
+ * instead of throwing.
+ */
+ static num tryParse(String input) {
+ String source = input.trim();
+ // TODO(lrn): Optimize to detect format and result type in one check.
+ return int.tryParse(source) ?? double.tryParse(source);
+ }
+
+ /** Helper functions for [parse]. */
+ static int _returnIntNull(String _) => null;
+ static double _returnDoubleNull(String _) => null;
+}
diff --git a/sdk_nnbd/lib/core/object.dart b/sdk_nnbd/lib/core/object.dart
new file mode 100644
index 0000000..505efdf
--- /dev/null
+++ b/sdk_nnbd/lib/core/object.dart
@@ -0,0 +1,115 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * The base class for all Dart objects.
+ *
+ * Because Object is the root of the Dart class hierarchy,
+ * every other Dart class is a subclass of Object.
+ *
+ * When you define a class, you should override [toString]
+ * to return a string describing an instance of that class.
+ * You might also need to define [hashCode] and [operator ==], as described in the
+ * [Implementing map
+ * keys](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#implementing-map-keys)
+ * section of the [library
+ * tour](http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html).
+ */
+@pragma("vm:entry-point")
+class Object {
+ /**
+ * Creates a new [Object] instance.
+ *
+ * [Object] instances have no meaningful state, and are only useful
+ * through their identity. An [Object] instance is equal to itself
+ * only.
+ */
+ const Object();
+
+ /**
+ * The equality operator.
+ *
+ * The default behavior for all [Object]s is to return true if and
+ * only if `this` and [other] are the same object.
+ *
+ * Override this method to specify a different equality relation on
+ * a class. The overriding method must still be an equivalence relation.
+ * That is, it must be:
+ *
+ * * Total: It must return a boolean for all arguments. It should never throw
+ * or return `null`.
+ *
+ * * Reflexive: For all objects `o`, `o == o` must be true.
+ *
+ * * Symmetric: For all objects `o1` and `o2`, `o1 == o2` and `o2 == o1` must
+ * either both be true, or both be false.
+ *
+ * * Transitive: For all objects `o1`, `o2`, and `o3`, if `o1 == o2` and
+ * `o2 == o3` are true, then `o1 == o3` must be true.
+ *
+ * The method should also be consistent over time,
+ * so whether two objects are equal should only change
+ * if at least one of the objects was modified.
+ *
+ * If a subclass overrides the equality operator it should override
+ * the [hashCode] method as well to maintain consistency.
+ */
+ external bool operator ==(other);
+
+ /**
+ * The hash code for this object.
+ *
+ * A hash code is a single integer which represents the state of the object
+ * that affects [operator ==] comparisons.
+ *
+ * All objects have hash codes.
+ * The default hash code represents only the identity of the object,
+ * the same way as the default [operator ==] implementation only considers objects
+ * equal if they are identical (see [identityHashCode]).
+ *
+ * If [operator ==] is overridden to use the object state instead,
+ * the hash code must also be changed to represent that state.
+ *
+ * Hash codes must be the same for objects that are equal to each other
+ * according to [operator ==].
+ * The hash code of an object should only change if the object changes
+ * in a way that affects equality.
+ * There are no further requirements for the hash codes.
+ * They need not be consistent between executions of the same program
+ * and there are no distribution guarantees.
+ *
+ * Objects that are not equal are allowed to have the same hash code,
+ * it is even technically allowed that all instances have the same hash code,
+ * but if clashes happen too often, it may reduce the efficiency of hash-based
+ * data structures like [HashSet] or [HashMap].
+ *
+ * If a subclass overrides [hashCode], it should override the
+ * [operator ==] operator as well to maintain consistency.
+ */
+ external int get hashCode;
+
+ /**
+ * Returns a string representation of this object.
+ */
+ external String toString();
+
+ /**
+ * Invoked when a non-existent method or property is accessed.
+ *
+ * Classes can override [noSuchMethod] to provide custom behavior.
+ *
+ * If a value is returned, it becomes the result of the original invocation.
+ *
+ * The default behavior is to throw a [NoSuchMethodError].
+ */
+ @pragma("vm:entry-point")
+ external dynamic noSuchMethod(Invocation invocation);
+
+ /**
+ * A representation of the runtime type of the object.
+ */
+ external Type get runtimeType;
+}
diff --git a/sdk_nnbd/lib/core/pattern.dart b/sdk_nnbd/lib/core/pattern.dart
new file mode 100644
index 0000000..6749340
--- /dev/null
+++ b/sdk_nnbd/lib/core/pattern.dart
@@ -0,0 +1,131 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An interface for basic searches within strings.
+ */
+abstract class Pattern {
+ // NOTE: When using "start" index from the language library, call
+ // without an argument if start is zero. This allows backwards compatibility
+ // with implementations of the older interface that didn't have the start
+ // index argument.
+ /**
+ * Match this pattern against the string repeatedly.
+ *
+ * If [start] is provided, matching will start at that index.
+ *
+ * The returned iterable lazily computes all the non-overlapping matches
+ * of the pattern on the string, ordered by start index.
+ * If a user only requests the first
+ * match, this function should not compute all possible matches.
+ *
+ * The matches are found by repeatedly finding the first match
+ * of the pattern on the string, starting from the end of the previous
+ * match, and initially starting from index zero.
+ *
+ * If the pattern matches the empty string at some point, the next
+ * match is found by starting at the previous match's end plus one.
+ */
+ Iterable<Match> allMatches(String string, [int start = 0]);
+
+ /**
+ * Match this pattern against the start of `string`.
+ *
+ * If [start] is provided, it must be an integer in the range `0` ..
+ * `string.length`. In that case, this patten is tested against the
+ * string at the [start] position. That is, a [Match] is returned if the
+ * pattern can match a part of the string starting from position [start].
+ * Returns `null` if the pattern doesn't match.
+ */
+ Match matchAsPrefix(String string, [int start = 0]);
+}
+
+/**
+ * A result from searching within a string.
+ *
+ * A Match or an [Iterable] of Match objects is returned from [Pattern]
+ * matching methods.
+ *
+ * The following example finds all matches of a [RegExp] in a [String]
+ * and iterates through the returned iterable of Match objects.
+ *
+ * RegExp exp = new RegExp(r"(\w+)");
+ * String str = "Parse my string";
+ * Iterable<Match> matches = exp.allMatches(str);
+ * for (Match m in matches) {
+ * String match = m.group(0);
+ * print(match);
+ * }
+ *
+ * The output of the example is:
+ *
+ * Parse
+ * my
+ * string
+ *
+ * Some patterns, regular expressions in particular, may record substrings
+ * that were part of the matching. These are called _groups_ in the Match
+ * object. Some patterns may never have any groups, and their matches always
+ * have zero [groupCount].
+ */
+abstract class Match {
+ /**
+ * Returns the index in the string where the match starts.
+ */
+ int get start;
+
+ /**
+ * Returns the index in the string after the last character of the
+ * match.
+ */
+ int get end;
+
+ /**
+ * Returns the string matched by the given [group].
+ *
+ * If [group] is 0, returns the match of the pattern.
+ *
+ * The result may be `null` if the pattern didn't assign a value to it
+ * as part of this match.
+ */
+ String group(int group);
+
+ /**
+ * Returns the string matched by the given [group].
+ *
+ * If [group] is 0, returns the match of the pattern.
+ *
+ * Short alias for [Match.group].
+ */
+ String operator [](int group);
+
+ /**
+ * Returns a list of the groups with the given indices.
+ *
+ * The list contains the strings returned by [group] for each index in
+ * [groupIndices].
+ */
+ List<String> groups(List<int> groupIndices);
+
+ /**
+ * Returns the number of captured groups in the match.
+ *
+ * Some patterns may capture parts of the input that was used to
+ * compute the full match. This is the number of captured groups,
+ * which is also the maximal allowed argument to the [group] method.
+ */
+ int get groupCount;
+
+ /**
+ * The string on which this match was computed.
+ */
+ String get input;
+
+ /**
+ * The pattern used to search in [input].
+ */
+ Pattern get pattern;
+}
diff --git a/sdk_nnbd/lib/core/print.dart b/sdk_nnbd/lib/core/print.dart
new file mode 100644
index 0000000..42c7d1c
--- /dev/null
+++ b/sdk_nnbd/lib/core/print.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/// Prints a string representation of the object to the console.
+void print(Object object) {
+ String line = "$object";
+ if (printToZone == null) {
+ printToConsole(line);
+ } else {
+ printToZone(line);
+ }
+}
diff --git a/sdk_nnbd/lib/core/regexp.dart b/sdk_nnbd/lib/core/regexp.dart
new file mode 100644
index 0000000..b3046cc
--- /dev/null
+++ b/sdk_nnbd/lib/core/regexp.dart
@@ -0,0 +1,189 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A regular expression pattern.
+ *
+ * Regular expressions are [Pattern]s, and can as such be used to match strings
+ * or parts of strings.
+ *
+ * Dart regular expressions have the same syntax and semantics as
+ * JavaScript regular expressions. See
+ * <https://ecma-international.org/ecma-262/9.0/#sec-regexp-regular-expression-objects>
+ * for the specification of JavaScript regular expressions.
+ *
+ * [firstMatch] is the main implementation method that applies a regular
+ * expression to a string and returns the first [RegExpMatch]. All
+ * other methods in [RegExp] can build on it.
+ *
+ * Use [allMatches] to look for all matches of a regular expression in
+ * a string.
+ *
+ * The following example finds all matches of a regular expression in
+ * a string.
+ * ```dart
+ * RegExp exp = new RegExp(r"(\w+)");
+ * String str = "Parse my string";
+ * Iterable<RegExpMatch> matches = exp.allMatches(str);
+ * ```
+ *
+ * Note the use of a _raw string_ (a string prefixed with `r`)
+ * in the example above. Use a raw string to treat each character in a string
+ * as a literal character.
+ */
+abstract class RegExp implements Pattern {
+ /**
+ * Constructs a regular expression.
+ *
+ * Throws a [FormatException] if [source] is not valid regular
+ * expression syntax.
+ *
+ * If `multiLine` is enabled, then `^` and `$` will match the beginning and
+ * end of a _line_, in addition to matching beginning and end of input,
+ * respectively.
+ *
+ * If `caseSensitive` is disabled, then case is ignored.
+ *
+ * If `unicode` is enabled, then the pattern is treated as a Unicode
+ * pattern as described by the ECMAScript standard.
+ *
+ * If `dotAll` is enabled, then the `.` pattern will match _all_ characters,
+ * including line terminators.
+ *
+ * Example:
+ *
+ * ```dart
+ * var wordPattern = RegExp(r"(\w+)");
+ * var bracketedNumberValue = RegExp("$key: \\[\\d+\\]");
+ * ```
+ *
+ * Notice the use of a _raw string_ in the first example, and a regular
+ * string in the second. Because of the many character classes used in
+ * regular expressions, it is common to use a raw string here, unless string
+ * interpolation is required.
+ */
+ external factory RegExp(String source,
+ {bool multiLine = false,
+ bool caseSensitive = true,
+ @Since("2.4") bool unicode = false,
+ @Since("2.4") bool dotAll = false});
+
+ /**
+ * Returns a regular expression that matches [text].
+ *
+ * If [text] contains characters that are meaningful in regular expressions,
+ * the resulting regular expression will match those characters literally.
+ * If [text] contains no characters that have special meaning in a regular
+ * expression, it is returned unmodified.
+ *
+ * The characters that have special meaning in regular expressions are:
+ * `(`, `)`, `[`, `]`, `{`, `}`, `*`, `+`, `?`, `.`, `^`, `$`, `|` and `\`.
+ */
+ external static String escape(String text);
+
+ /**
+ * Searches for the first match of the regular expression
+ * in the string [input]. Returns `null` if there is no match.
+ */
+ RegExpMatch firstMatch(String input);
+
+ /**
+ * Returns an iterable of the matches of the regular expression on [input].
+ *
+ * If [start] is provided, only start looking for matches at `start`.
+ */
+ Iterable<RegExpMatch> allMatches(String input, [int start = 0]);
+
+ /**
+ * Returns whether the regular expression has a match in the string [input].
+ */
+ bool hasMatch(String input);
+
+ /**
+ * Returns the first substring match of this regular expression in [input].
+ */
+ String stringMatch(String input);
+
+ /**
+ * The source regular expression string used to create this `RegExp`.
+ */
+ String get pattern;
+
+ /**
+ * Whether this regular expression matches multiple lines.
+ *
+ * If the regexp does match multiple lines, the "^" and "$" characters
+ * match the beginning and end of lines. If not, the character match the
+ * beginning and end of the input.
+ */
+ bool get isMultiLine;
+
+ /**
+ * Whether this regular expression is case sensitive.
+ *
+ * If the regular expression is not case sensitive, it will match an input
+ * letter with a pattern letter even if the two letters are different case
+ * versions of the same letter.
+ */
+ bool get isCaseSensitive;
+
+ /**
+ * Whether this regular expression is in Unicode mode.
+ *
+ * In Unicode mode, UTF-16 surrogate pairs in the original string will be
+ * treated as a single code point and will not match separately. Otherwise,
+ * the target string will be treated purely as a sequence of individual code
+ * units and surrogates will not be treated specially.
+ *
+ * In Unicode mode, the syntax of the RegExp pattern is more restricted, but
+ * some pattern features, like Unicode property escapes, are only available in
+ * this mode.
+ */
+ @Since("2.4")
+ bool get isUnicode;
+
+ /**
+ * Whether "." in this regular expression matches line terminators.
+ *
+ * When false, the "." character matches a single character, unless that
+ * character is a line terminator. When true, then the "." character will
+ * match any single character including line terminators.
+ *
+ * This feature is distinct from [isMultiline], as they affect the behavior
+ * of different pattern characters, and so they can be used together or
+ * separately.
+ */
+ @Since("2.4")
+ bool get isDotAll;
+}
+
+/**
+ * A regular expression match.
+ *
+ * Regular expression matches are [Match]es, but also include the ability
+ * to retrieve the names for any named capture groups and to retrieve
+ * matches for named capture groups by name instead of their index.
+ */
+@Since("2.3")
+abstract class RegExpMatch implements Match {
+ /**
+ * The string matched by the group named [name].
+ *
+ * Returns the string matched by the capture group named [name], or
+ * `null` if no string was matched by that capture group as part of
+ * this match.
+ *
+ * The [name] must be the name of a named capture group in the regular
+ * expression creating this match (that is, the name must be in
+ * [groupNames]).
+ */
+ String namedGroup(String name);
+
+ /**
+ * The names of the captured groups in the match.
+ */
+ Iterable<String> get groupNames;
+}
diff --git a/sdk_nnbd/lib/core/set.dart b/sdk_nnbd/lib/core/set.dart
new file mode 100644
index 0000000..e57d974
--- /dev/null
+++ b/sdk_nnbd/lib/core/set.dart
@@ -0,0 +1,264 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A collection of objects in which each object can occur only once.
+ *
+ * That is, for each object of the element type, the object is either considered
+ * to be in the set, or to _not_ be in the set.
+ *
+ * Set implementations may consider some elements indistinguishable. These
+ * elements are treated as being the same for any operation on the set.
+ *
+ * The default [Set] implementation, [LinkedHashSet], considers objects
+ * indistinguishable if they are equal with regard to
+ * operator [Object.==].
+ *
+ * Iterating over elements of a set may be either unordered
+ * or ordered in some way. Examples:
+ *
+ * * A [HashSet] is unordered, which means that its iteration order is
+ * unspecified,
+ * * [LinkedHashSet] iterates in the insertion order of its elements, and
+ * * a sorted set like [SplayTreeSet] iterates the elements in sorted order.
+ *
+ * It is generally not allowed to modify the set (add or remove elements) while
+ * an operation on the set is being performed, for example during a call to
+ * [forEach] or [containsAll]. Nor is it allowed to modify the set while
+ * iterating either the set itself or any [Iterable] that is backed by the set,
+ * such as the ones returned by methods like [where] and [map].
+ *
+ * It is generally not allowed to modify the equality of elements (and thus not
+ * their hashcode) while they are in the set. Some specialized subtypes may be
+ * more permissive, in which case they should document this behavior.
+ */
+abstract class Set<E> extends EfficientLengthIterable<E> {
+ /**
+ * Creates an empty [Set].
+ *
+ * The created [Set] is a plain [LinkedHashSet].
+ * As such, it considers elements that are equal (using [operator ==]) to be
+ * indistinguishable, and requires them to have a compatible
+ * [Object.hashCode] implementation.
+ *
+ * The set is equivalent to one created by `new LinkedHashSet<E>()`.
+ */
+ factory Set() = LinkedHashSet<E>;
+
+ /**
+ * Creates an empty identity [Set].
+ *
+ * The created [Set] is a [LinkedHashSet] that uses identity as equality
+ * relation.
+ *
+ * The set is equivalent to one created by `new LinkedHashSet<E>.identity()`.
+ */
+ factory Set.identity() = LinkedHashSet<E>.identity;
+
+ /**
+ * Creates a [Set] that contains all [elements].
+ *
+ * All the [elements] should be instances of [E].
+ * The `elements` iterable itself can have any type,
+ * so this constructor can be used to down-cast a `Set`, for example as:
+ *
+ * Set<SuperType> superSet = ...;
+ * Set<SubType> subSet =
+ * new Set<SubType>.from(superSet.where((e) => e is SubType));
+ *
+ * The created [Set] is a [LinkedHashSet]. As such, it considers elements that
+ * are equal (using [operator ==]) to be indistinguishable, and requires them to
+ * have a compatible [Object.hashCode] implementation.
+ *
+ * The set is equivalent to one created by
+ * `new LinkedHashSet<E>.from(elements)`.
+ */
+ factory Set.from(Iterable elements) = LinkedHashSet<E>.from;
+
+ /**
+ * Creates a [Set] from [elements].
+ *
+ * The created [Set] is a [LinkedHashSet]. As such, it considers elements that
+ * are equal (using [operator ==]) to be indistinguishable, and requires them to
+ * have a compatible [Object.hashCode] implementation.
+ *
+ * The set is equivalent to one created by
+ * `new LinkedHashSet<E>.of(elements)`.
+ */
+ factory Set.of(Iterable<E> elements) = LinkedHashSet<E>.of;
+
+ /**
+ * Adapts [source] to be a `Set<T>`.
+ *
+ * If [newSet] is provided, it is used to create the new sets returned
+ * by [toSet], [union], and is also used for [intersection] and [difference].
+ * If [newSet] is omitted, it defaults to creating a new set using the
+ * default [Set] constructor, and [intersection] and [difference]
+ * returns an adapted version of calling the same method on the source.
+ *
+ * Any time the set would produce an element that is not a [T],
+ * the element access will throw.
+ *
+ * Any time a [T] value is attempted added into the adapted set,
+ * the store will throw unless the value is also an instance of [S].
+ *
+ * If all accessed elements of [source] are actually instances of [T],
+ * and if all elements added to the returned set are actually instance
+ * of [S],
+ * then the returned set can be used as a `Set<T>`.
+ */
+ static Set<T> castFrom<S, T>(Set<S> source, {Set<R> Function<R>() newSet}) =>
+ CastSet<S, T>(source, newSet);
+
+ /**
+ * Provides a view of this set as a set of [R] instances.
+ *
+ * If this set contains only instances of [R], all read operations
+ * will work correctly. If any operation tries to access an element
+ * that is not an instance of [R], the access will throw instead.
+ *
+ * Elements added to the set (e.g., by using [add] or [addAll])
+ * must be instance of [R] to be valid arguments to the adding function,
+ * and they must be instances of [E] as well to be accepted by
+ * this set as well.
+ */
+ Set<R> cast<R>();
+ /**
+ * Provides an iterator that iterates over the elements of this set.
+ *
+ * The order of iteration is defined by the individual `Set` implementation,
+ * but must be consistent between changes to the set.
+ */
+ Iterator<E> get iterator;
+
+ /**
+ * Returns true if [value] is in the set.
+ */
+ bool contains(Object value);
+
+ /**
+ * Adds [value] to the set.
+ *
+ * Returns `true` if [value] (or an equal value) was not yet in the set.
+ * Otherwise returns `false` and the set is not changed.
+ *
+ * Example:
+ *
+ * var set = new Set();
+ * var time1 = new DateTime.fromMillisecondsSinceEpoch(0);
+ * var time2 = new DateTime.fromMillisecondsSinceEpoch(0);
+ * // time1 and time2 are equal, but not identical.
+ * Expect.isTrue(time1 == time2);
+ * Expect.isFalse(identical(time1, time2));
+ * set.add(time1); // => true.
+ * // A value equal to time2 exists already in the set, and the call to
+ * // add doesn't change the set.
+ * set.add(time2); // => false.
+ * Expect.isTrue(set.length == 1);
+ * Expect.isTrue(identical(time1, set.first));
+ */
+ bool add(E value);
+
+ /**
+ * Adds all [elements] to this Set.
+ *
+ * Equivalent to adding each element in [elements] using [add],
+ * but some collections may be able to optimize it.
+ */
+ void addAll(Iterable<E> elements);
+
+ /**
+ * Removes [value] from the set. Returns true if [value] was
+ * in the set. Returns false otherwise. The method has no effect
+ * if [value] value was not in the set.
+ */
+ bool remove(Object value);
+
+ /**
+ * If an object equal to [object] is in the set, return it.
+ *
+ * Checks whether [object] is in the set, like [contains], and if so,
+ * returns the object in the set, otherwise returns `null`.
+ *
+ * If the equality relation used by the set is not identity,
+ * then the returned object may not be *identical* to [object].
+ * Some set implementations may not be able to implement this method.
+ * If the [contains] method is computed,
+ * rather than being based on an actual object instance,
+ * then there may not be a specific object instance representing the
+ * set element.
+ */
+ E lookup(Object object);
+
+ /**
+ * Removes each element of [elements] from this set.
+ */
+ void removeAll(Iterable<Object> elements);
+
+ /**
+ * Removes all elements of this set that are not elements in [elements].
+ *
+ * Checks for each element of [elements] whether there is an element in this
+ * set that is equal to it (according to `this.contains`), and if so, the
+ * equal element in this set is retained, and elements that are not equal
+ * to any element in `elements` are removed.
+ */
+ void retainAll(Iterable<Object> elements);
+
+ /**
+ * Removes all elements of this set that satisfy [test].
+ */
+ void removeWhere(bool test(E element));
+
+ /**
+ * Removes all elements of this set that fail to satisfy [test].
+ */
+ void retainWhere(bool test(E element));
+
+ /**
+ * Returns whether this Set contains all the elements of [other].
+ */
+ bool containsAll(Iterable<Object> other);
+
+ /**
+ * Returns a new set which is the intersection between this set and [other].
+ *
+ * That is, the returned set contains all the elements of this [Set] that
+ * are also elements of [other] according to `other.contains`.
+ */
+ Set<E> intersection(Set<Object> other);
+
+ /**
+ * Returns a new set which contains all the elements of this set and [other].
+ *
+ * That is, the returned set contains all the elements of this [Set] and
+ * all the elements of [other].
+ */
+ Set<E> union(Set<E> other);
+
+ /**
+ * Returns a new set with the elements of this that are not in [other].
+ *
+ * That is, the returned set contains all the elements of this [Set] that
+ * are not elements of [other] according to `other.contains`.
+ */
+ Set<E> difference(Set<Object> other);
+
+ /**
+ * Removes all elements in the set.
+ */
+ void clear();
+
+ /* Creates a [Set] with the same elements and behavior as this `Set`.
+ *
+ * The returned set behaves the same as this set
+ * with regard to adding and removing elements.
+ * It initially contains the same elements.
+ * If this set specifies an ordering of the elements,
+ * the returned set will have the same order.
+ */
+ Set<E> toSet();
+}
diff --git a/sdk_nnbd/lib/core/sink.dart b/sdk_nnbd/lib/core/sink.dart
new file mode 100644
index 0000000..c79214b
--- /dev/null
+++ b/sdk_nnbd/lib/core/sink.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A generic destination for data.
+ *
+ * Multiple data values can be put into a sink, and when no more data is
+ * available, the sink should be closed.
+ *
+ * This is a generic interface that other data receivers can implement.
+ */
+abstract class Sink<T> {
+ /**
+ * Adds [data] to the sink.
+ *
+ * Must not be called after a call to [close].
+ */
+ void add(T data);
+
+ /**
+ * Closes the sink.
+ *
+ * The [add] method must not be called after this method.
+ *
+ * Calling this method more than once is allowed, but does nothing.
+ */
+ void close();
+}
diff --git a/sdk_nnbd/lib/core/stacktrace.dart b/sdk_nnbd/lib/core/stacktrace.dart
new file mode 100644
index 0000000..2eb1493
--- /dev/null
+++ b/sdk_nnbd/lib/core/stacktrace.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * An interface implemented by all stack trace objects.
+ *
+ * A [StackTrace] is intended to convey information to the user about the call
+ * sequence that triggered an exception.
+ *
+ * These objects are created by the runtime, it is not possible to create
+ * them programmatically.
+ */
+abstract class StackTrace {
+ StackTrace(); // In case existing classes extend StackTrace.
+
+ /**
+ * Create a `StackTrace` object from [stackTraceString].
+ *
+ * The created stack trace will have a `toString` method returning
+ * `stackTraceString`.
+ *
+ * The `stackTraceString` can be a string returned by some other
+ * stack trace, or it can be any string at all.
+ * If the string doesn't look like a stack trace, code that interprets
+ * stack traces is likely to fail, so fake stack traces should be used
+ * with care.
+ */
+ factory StackTrace.fromString(String stackTraceString) = _StringStackTrace;
+
+ /**
+ * Returns a representation of the current stack trace.
+ *
+ * This is similar to what can be achieved by doing:
+ *
+ * try { throw 0; } catch (_, stack) { return stack; }
+ *
+ * The getter achieves this without throwing, except on platforms that
+ * have no other way to get a stack trace.
+ */
+ external static StackTrace get current;
+
+ /**
+ * Returns a [String] representation of the stack trace.
+ *
+ * The string represents the full stack trace starting from
+ * the point where a throw occurred to the top of the current call sequence.
+ *
+ * The exact format of the string representation is not final.
+ */
+ String toString();
+}
+
+class _StringStackTrace implements StackTrace {
+ final String _stackTrace;
+ _StringStackTrace(this._stackTrace);
+ String toString() => _stackTrace;
+}
diff --git a/sdk_nnbd/lib/core/stopwatch.dart b/sdk_nnbd/lib/core/stopwatch.dart
new file mode 100644
index 0000000..45d71ca
--- /dev/null
+++ b/sdk_nnbd/lib/core/stopwatch.dart
@@ -0,0 +1,123 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A simple stopwatch interface to measure elapsed time.
+ */
+class Stopwatch {
+ /**
+ * Cached frequency of the system in Hz (ticks per second).
+ *
+ * Must be initialized in [_initTicker];
+ */
+ static int _frequency;
+
+ // The _start and _stop fields capture the time when [start] and [stop]
+ // are called respectively.
+ // If _stop is null, the stopwatch is running.
+ int _start = 0;
+ int _stop = 0;
+
+ /**
+ * Creates a [Stopwatch] in stopped state with a zero elapsed count.
+ *
+ * The following example shows how to start a [Stopwatch]
+ * immediately after allocation.
+ * ```
+ * var stopwatch = new Stopwatch()..start();
+ * ```
+ */
+ Stopwatch() {
+ if (_frequency == null) _initTicker();
+ }
+
+ /**
+ * Frequency of the elapsed counter in Hz.
+ */
+ int get frequency => _frequency;
+
+ /**
+ * Starts the [Stopwatch].
+ *
+ * The [elapsed] count is increasing monotonically. If the [Stopwatch] has
+ * been stopped, then calling start again restarts it without resetting the
+ * [elapsed] count.
+ *
+ * If the [Stopwatch] is currently running, then calling start does nothing.
+ */
+ void start() {
+ if (_stop != null) {
+ // (Re)start this stopwatch.
+ // Don't count the time while the stopwatch has been stopped.
+ _start += _now() - _stop;
+ _stop = null;
+ }
+ }
+
+ /**
+ * Stops the [Stopwatch].
+ *
+ * The [elapsedTicks] count stops increasing after this call. If the
+ * [Stopwatch] is currently not running, then calling this method has no
+ * effect.
+ */
+ void stop() {
+ _stop ??= _now();
+ }
+
+ /**
+ * Resets the [elapsed] count to zero.
+ *
+ * This method does not stop or start the [Stopwatch].
+ */
+ void reset() {
+ _start = _stop ?? _now();
+ }
+
+ /**
+ * The elapsed number of clock ticks since calling [start] while the
+ * [Stopwatch] is running.
+ *
+ * This is the elapsed number of clock ticks between calling [start] and
+ * calling [stop].
+ *
+ * Is 0 if the [Stopwatch] has never been started.
+ *
+ * The elapsed number of clock ticks increases by [frequency] every second.
+ */
+ int get elapsedTicks {
+ return (_stop ?? _now()) - _start;
+ }
+
+ /**
+ * The [elapsedTicks] counter converted to a [Duration].
+ */
+ Duration get elapsed {
+ return Duration(microseconds: elapsedMicroseconds);
+ }
+
+ /**
+ * The [elapsedTicks] counter converted to microseconds.
+ */
+ external int get elapsedMicroseconds;
+
+ /**
+ * The [elapsedTicks] counter converted to milliseconds.
+ */
+ external int get elapsedMilliseconds;
+
+ /**
+ * Whether the [Stopwatch] is currently running.
+ */
+ bool get isRunning => _stop == null;
+
+ /**
+ * Initializes the time-measuring system. *Must* initialize the [_frequency]
+ * variable.
+ */
+ external static void _initTicker();
+ external static int _now();
+}
diff --git a/sdk_nnbd/lib/core/string.dart b/sdk_nnbd/lib/core/string.dart
new file mode 100644
index 0000000..c611bd5
--- /dev/null
+++ b/sdk_nnbd/lib/core/string.dart
@@ -0,0 +1,829 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A sequence of UTF-16 code units.
+ *
+ * Strings are mainly used to represent text. A character may be represented by
+ * multiple code points, each code point consisting of one or two code
+ * units. For example the Papua New Guinea flag character requires four code
+ * units to represent two code points, but should be treated like a single
+ * character: "🇵🇬". Platforms that do not support the flag character may show
+ * the letters "PG" instead. If the code points are swapped, it instead becomes
+ * the Guadeloupe flag "🇬🇵" ("GP").
+ *
+ * A string can be either single or multiline. Single line strings are
+ * written using matching single or double quotes, and multiline strings are
+ * written using triple quotes. The following are all valid Dart strings:
+ *
+ * 'Single quotes';
+ * "Double quotes";
+ * 'Double quotes in "single" quotes';
+ * "Single quotes in 'double' quotes";
+ *
+ * '''A
+ * multiline
+ * string''';
+ *
+ * """
+ * Another
+ * multiline
+ * string""";
+ *
+ * Strings are immutable. Although you cannot change a string, you can perform
+ * an operation on a string and assign the result to a new string:
+ *
+ * var string = 'Dart is fun';
+ * var newString = string.substring(0, 5);
+ *
+ * You can use the plus (`+`) operator to concatenate strings:
+ *
+ * 'Dart ' + 'is ' + 'fun!'; // 'Dart is fun!'
+ *
+ * You can also use adjacent string literals for concatenation:
+ *
+ * 'Dart ' 'is ' 'fun!'; // 'Dart is fun!'
+ *
+ * You can use `${}` to interpolate the value of Dart expressions
+ * within strings. The curly braces can be omitted when evaluating identifiers:
+ *
+ * string = 'dartlang';
+ * '$string has ${string.length} letters'; // 'dartlang has 8 letters'
+ *
+ * A string is represented by a sequence of Unicode UTF-16 code units
+ * accessible through the [codeUnitAt] or the [codeUnits] members:
+ *
+ * string = 'Dart';
+ * string.codeUnitAt(0); // 68
+ * string.codeUnits; // [68, 97, 114, 116]
+ *
+ * The string representation of code units is accessible through the index
+ * operator:
+ *
+ * string[0]; // 'D'
+ *
+ * The characters of a string are encoded in UTF-16. Decoding UTF-16, which
+ * combines surrogate pairs, yields Unicode code points. Following a similar
+ * terminology to Go, we use the name 'rune' for an integer representing a
+ * Unicode code point. Use the [runes] property to get the runes of a string:
+ *
+ * string.runes.toList(); // [68, 97, 114, 116]
+ *
+ * For a character outside the Basic Multilingual Plane (plane 0) that is
+ * composed of a surrogate pair, [runes] combines the pair and returns a
+ * single integer. For example, the Unicode character for a
+ * musical G-clef ('𝄞') with rune value 0x1D11E consists of a UTF-16 surrogate
+ * pair: `0xD834` and `0xDD1E`. Using [codeUnits] returns the surrogate pair,
+ * and using `runes` returns their combined value:
+ *
+ * var clef = '\u{1D11E}';
+ * clef.codeUnits; // [0xD834, 0xDD1E]
+ * clef.runes.toList(); // [0x1D11E]
+ *
+ * The String class can not be extended or implemented. Attempting to do so
+ * yields a compile-time error.
+ *
+ * ## Other resources
+ *
+ * See [StringBuffer] to efficiently build a string incrementally. See
+ * [RegExp] to work with regular expressions.
+ *
+ * Also see:
+ *
+ * * [Dart Cookbook](https://www.dartlang.org/docs/cookbook/#strings)
+ * for String examples and recipes.
+ * * [Dart Up and Running](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#strings-and-regular-expressions)
+ */
+abstract class String implements Comparable<String>, Pattern {
+ /**
+ * Allocates a new String for the specified [charCodes].
+ *
+ * The [charCodes] can be UTF-16 code units or runes. If a char-code value is
+ * 16-bit, it is copied verbatim:
+ *
+ * new String.fromCharCodes([68]); // 'D'
+ *
+ * If a char-code value is greater than 16-bits, it is decomposed into a
+ * surrogate pair:
+ *
+ * var clef = new String.fromCharCodes([0x1D11E]);
+ * clef.codeUnitAt(0); // 0xD834
+ * clef.codeUnitAt(1); // 0xDD1E
+ *
+ * If [start] and [end] is provided, only the values of [charCodes]
+ * at positions from `start` to, but not including, `end`, are used.
+ * The `start` and `end` values must satisfy
+ * `0 <= start <= end <= charCodes.length`.
+ */
+ external factory String.fromCharCodes(Iterable<int> charCodes,
+ [int start = 0, int end]);
+
+ /**
+ * Allocates a new String for the specified [charCode].
+ *
+ * If the [charCode] can be represented by a single UTF-16 code unit, the new
+ * string contains a single code unit. Otherwise, the [length] is 2 and
+ * the code units form a surrogate pair. See documentation for
+ * [fromCharCodes].
+ *
+ * Creating a String with half of a surrogate pair is allowed.
+ */
+ external factory String.fromCharCode(int charCode);
+
+ /**
+ * Returns the string value of the environment declaration [name].
+ *
+ * Environment declarations are provided by the surrounding system compiling
+ * or running the Dart program. Declarations map a string key to a string
+ * value.
+ *
+ * If [name] is not declared in the environment, the result is instead
+ * [defaultValue].
+ *
+ * Example of getting a value:
+ *
+ * const String.fromEnvironment("defaultFloo", defaultValue: "no floo")
+ *
+ * Example of checking whether a declaration is there at all:
+ *
+ * var isDeclared = const String.fromEnvironment("maybeDeclared") != null;
+ */
+ // The .fromEnvironment() constructors are special in that we do not want
+ // users to call them using "new". We prohibit that by giving them bodies
+ // that throw, even though const constructors are not allowed to have bodies.
+ // Disable those static errors.
+ //ignore: const_constructor_with_body
+ //ignore: const_factory
+ external const factory String.fromEnvironment(String name,
+ {String defaultValue});
+
+ /**
+ * Gets the character (as a single-code-unit [String]) at the given [index].
+ *
+ * The returned string represents exactly one UTF-16 code unit, which may be
+ * half of a surrogate pair. A single member of a surrogate pair is an
+ * invalid UTF-16 string:
+ *
+ * var clef = '\u{1D11E}';
+ * // These represent invalid UTF-16 strings.
+ * clef[0].codeUnits; // [0xD834]
+ * clef[1].codeUnits; // [0xDD1E]
+ *
+ * This method is equivalent to
+ * `new String.fromCharCode(this.codeUnitAt(index))`.
+ */
+ String operator [](int index);
+
+ /**
+ * Returns the 16-bit UTF-16 code unit at the given [index].
+ */
+ int codeUnitAt(int index);
+
+ /**
+ * The length of the string.
+ *
+ * Returns the number of UTF-16 code units in this string. The number
+ * of [runes] might be fewer, if the string contains characters outside
+ * the Basic Multilingual Plane (plane 0):
+ *
+ * 'Dart'.length; // 4
+ * 'Dart'.runes.length; // 4
+ *
+ * var clef = '\u{1D11E}';
+ * clef.length; // 2
+ * clef.runes.length; // 1
+ */
+ int get length;
+
+ /**
+ * Returns a hash code derived from the code units of the string.
+ *
+ * This is compatible with [operator ==]. Strings with the same sequence
+ * of code units have the same hash code.
+ */
+ int get hashCode;
+
+ /**
+ * Returns true if other is a `String` with the same sequence of code units.
+ *
+ * This method compares each individual code unit of the strings.
+ * It does not check for Unicode equivalence.
+ * For example, both the following strings represent the string 'Amélie',
+ * but due to their different encoding, are not equal:
+ *
+ * 'Am\xe9lie' == 'Ame\u{301}lie'; // false
+ *
+ * The first string encodes 'é' as a single unicode code unit (also
+ * a single rune), whereas the second string encodes it as 'e' with the
+ * combining accent character '◌́'.
+ */
+ bool operator ==(Object other);
+
+ /**
+ * Compares this string to [other].
+ *
+ * Returns a negative value if `this` is ordered before `other`,
+ * a positive value if `this` is ordered after `other`,
+ * or zero if `this` and `other` are equivalent.
+ *
+ * The ordering is the same as the ordering of the code points at the first
+ * position where the two strings differ.
+ * If one string is a prefix of the other,
+ * then the shorter string is ordered before the longer string.
+ * If the strings have exactly the same content, they are equivalent with
+ * regard to the ordering.
+ * Ordering does not check for Unicode equivalence.
+ * The comparison is case sensitive.
+ */
+ int compareTo(String other);
+
+ /**
+ * Returns true if this string ends with [other]. For example:
+ *
+ * 'Dart'.endsWith('t'); // true
+ */
+ bool endsWith(String other);
+
+ /**
+ * Returns true if this string starts with a match of [pattern].
+ *
+ * var string = 'Dart';
+ * string.startsWith('D'); // true
+ * string.startsWith(new RegExp(r'[A-Z][a-z]')); // true
+ *
+ * If [index] is provided, this method checks if the substring starting
+ * at that index starts with a match of [pattern]:
+ *
+ * string.startsWith('art', 1); // true
+ * string.startsWith(new RegExp(r'\w{3}')); // true
+ *
+ * [index] must not be negative or greater than [length].
+ *
+ * A [RegExp] containing '^' does not match if the [index] is greater than
+ * zero. The pattern works on the string as a whole, and does not extract
+ * a substring starting at [index] first:
+ *
+ * string.startsWith(new RegExp(r'^art'), 1); // false
+ * string.startsWith(new RegExp(r'art'), 1); // true
+ */
+ bool startsWith(Pattern pattern, [int index = 0]);
+
+ /**
+ * Returns the position of the first match of [pattern] in this string,
+ * starting at [start], inclusive:
+ *
+ * var string = 'Dartisans';
+ * string.indexOf('art'); // 1
+ * string.indexOf(new RegExp(r'[A-Z][a-z]')); // 0
+ *
+ * Returns -1 if no match is found:
+ *
+ * string.indexOf(new RegExp(r'dart')); // -1
+ *
+ * [start] must be non-negative and not greater than [length].
+ */
+ int indexOf(Pattern pattern, [int start]);
+
+ /**
+ * Returns the position of the last match [pattern] in this string, searching
+ * backward starting at [start], inclusive:
+ *
+ * var string = 'Dartisans';
+ * string.lastIndexOf('a'); // 6
+ * string.lastIndexOf(new RegExp(r'a(r|n)')); // 6
+ *
+ * Returns -1 if [pattern] could not be found in this string.
+ *
+ * string.lastIndexOf(new RegExp(r'DART')); // -1
+ *
+ * The [start] must be non-negative and not greater than [length].
+ */
+ int lastIndexOf(Pattern pattern, [int start]);
+
+ /**
+ * Returns true if this string is empty.
+ */
+ bool get isEmpty;
+
+ /**
+ * Returns true if this string is not empty.
+ */
+ bool get isNotEmpty;
+
+ /**
+ * Creates a new string by concatenating this string with [other].
+ *
+ * 'dart' + 'lang'; // 'dartlang'
+ */
+ String operator +(String other);
+
+ /**
+ * Returns the substring of this string that extends from [startIndex],
+ * inclusive, to [endIndex], exclusive.
+ *
+ * var string = 'dartlang';
+ * string.substring(1); // 'artlang'
+ * string.substring(1, 4); // 'art'
+ */
+ String substring(int startIndex, [int endIndex]);
+
+ /**
+ * Returns the string without any leading and trailing whitespace.
+ *
+ * If the string contains leading or trailing whitespace, a new string with no
+ * leading and no trailing whitespace is returned:
+ * ```dart
+ * '\tDart is fun\n'.trim(); // 'Dart is fun'
+ * ```
+ * Otherwise, the original string itself is returned:
+ * ```dart
+ * var str1 = 'Dart';
+ * var str2 = str1.trim();
+ * identical(str1, str2); // true
+ * ```
+ * Whitespace is defined by the Unicode White_Space property (as defined in
+ * version 6.2 or later) and the BOM character, 0xFEFF.
+ *
+ * Here is the list of trimmed characters according to Unicode version 6.3:
+ * ```
+ * 0009..000D ; White_Space # Cc <control-0009>..<control-000D>
+ * 0020 ; White_Space # Zs SPACE
+ * 0085 ; White_Space # Cc <control-0085>
+ * 00A0 ; White_Space # Zs NO-BREAK SPACE
+ * 1680 ; White_Space # Zs OGHAM SPACE MARK
+ * 2000..200A ; White_Space # Zs EN QUAD..HAIR SPACE
+ * 2028 ; White_Space # Zl LINE SEPARATOR
+ * 2029 ; White_Space # Zp PARAGRAPH SEPARATOR
+ * 202F ; White_Space # Zs NARROW NO-BREAK SPACE
+ * 205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE
+ * 3000 ; White_Space # Zs IDEOGRAPHIC SPACE
+ *
+ * FEFF ; BOM ZERO WIDTH NO_BREAK SPACE
+ * ```
+ * Some later versions of Unicode do not include U+0085 as a whitespace
+ * character. Whether it is trimmed depends on the Unicode version
+ * used by the system.
+ */
+ String trim();
+
+ /**
+ * Returns the string without any leading whitespace.
+ *
+ * As [trim], but only removes leading whitespace.
+ */
+ String trimLeft();
+
+ /**
+ * Returns the string without any trailing whitespace.
+ *
+ * As [trim], but only removes trailing whitespace.
+ */
+ String trimRight();
+
+ /**
+ * Creates a new string by concatenating this string with itself a number
+ * of times.
+ *
+ * The result of `str * n` is equivalent to
+ * `str + str + ...`(n times)`... + str`.
+ *
+ * Returns an empty string if [times] is zero or negative.
+ */
+ String operator *(int times);
+
+ /**
+ * Pads this string on the left if it is shorter than [width].
+ *
+ * Return a new string that prepends [padding] onto this string
+ * one time for each position the length is less than [width].
+ *
+ * If [width] is already smaller than or equal to `this.length`,
+ * no padding is added. A negative `width` is treated as zero.
+ *
+ * If [padding] has length different from 1, the result will not
+ * have length `width`. This may be useful for cases where the
+ * padding is a longer string representing a single character, like
+ * `" "` or `"\u{10002}`".
+ * In that case, the user should make sure that `this.length` is
+ * the correct measure of the strings length.
+ */
+ String padLeft(int width, [String padding = ' ']);
+
+ /**
+ * Pads this string on the right if it is shorter than [width].
+ *
+ * Return a new string that appends [padding] after this string
+ * one time for each position the length is less than [width].
+ *
+ * If [width] is already smaller than or equal to `this.length`,
+ * no padding is added. A negative `width` is treated as zero.
+ *
+ * If [padding] has length different from 1, the result will not
+ * have length `width`. This may be useful for cases where the
+ * padding is a longer string representing a single character, like
+ * `" "` or `"\u{10002}`".
+ * In that case, the user should make sure that `this.length` is
+ * the correct measure of the strings length.
+ */
+ String padRight(int width, [String padding = ' ']);
+
+ /**
+ * Returns true if this string contains a match of [other]:
+ *
+ * var string = 'Dart strings';
+ * string.contains('D'); // true
+ * string.contains(new RegExp(r'[A-Z]')); // true
+ *
+ * If [startIndex] is provided, this method matches only at or after that
+ * index:
+ *
+ * string.contains('X', 1); // false
+ * string.contains(new RegExp(r'[A-Z]'), 1); // false
+ *
+ * [startIndex] must not be negative or greater than [length].
+ */
+ bool contains(Pattern other, [int startIndex = 0]);
+
+ /**
+ * Returns a new string in which the first occurrence of [from] in this string
+ * is replaced with [to], starting from [startIndex]:
+ *
+ * '0.0001'.replaceFirst(new RegExp(r'0'), ''); // '.0001'
+ * '0.0001'.replaceFirst(new RegExp(r'0'), '7', 1); // '0.7001'
+ */
+ String replaceFirst(Pattern from, String to, [int startIndex = 0]);
+
+ /**
+ * Replace the first occurrence of [from] in this string.
+ *
+ * Returns a new string, which is this string
+ * except that the first match of [from], starting from [startIndex],
+ * is replaced by the result of calling [replace] with the match object.
+ *
+ * The optional [startIndex] is by default set to 0. If provided, it must be
+ * an integer in the range `[0 .. len]`, where `len` is this string's length.
+ */
+ String replaceFirstMapped(Pattern from, String replace(Match match),
+ [int startIndex = 0]);
+
+ /**
+ * Replaces all substrings that match [from] with [replace].
+ *
+ * Returns a new string in which the non-overlapping substrings matching
+ * [from] (the ones iterated by `from.allMatches(thisString)`) are replaced
+ * by the literal string [replace].
+ *
+ * 'resume'.replaceAll(new RegExp(r'e'), 'é'); // 'résumé'
+ *
+ * Notice that the [replace] string is not interpreted. If the replacement
+ * depends on the match (for example on a [RegExp]'s capture groups), use
+ * the [replaceAllMapped] method instead.
+ */
+ String replaceAll(Pattern from, String replace);
+
+ /**
+ * Replace all substrings that match [from] by a string computed from the
+ * match.
+ *
+ * Returns a new string in which the non-overlapping substrings that match
+ * [from] (the ones iterated by `from.allMatches(thisString)`) are replaced
+ * by the result of calling [replace] on the corresponding [Match] object.
+ *
+ * This can be used to replace matches with new content that depends on the
+ * match, unlike [replaceAll] where the replacement string is always the same.
+ *
+ * The [replace] function is called with the [Match] generated
+ * by the pattern, and its result is used as replacement.
+ *
+ * The function defined below converts each word in a string to simplified
+ * 'pig latin' using [replaceAllMapped]:
+ *
+ * pigLatin(String words) => words.replaceAllMapped(
+ * new RegExp(r'\b(\w*?)([aeiou]\w*)', caseSensitive: false),
+ * (Match m) => "${m[2]}${m[1]}${m[1].isEmpty ? 'way' : 'ay'}");
+ *
+ * pigLatin('I have a secret now!'); // 'Iway avehay away ecretsay ownay!'
+ */
+ String replaceAllMapped(Pattern from, String replace(Match match));
+
+ /**
+ * Replaces the substring from [start] to [end] with [replacement].
+ *
+ * Returns a new string equivalent to:
+ *
+ * this.substring(0, start) + replacement + this.substring(end)
+ *
+ * The [start] and [end] indices must specify a valid range of this string.
+ * That is `0 <= start <= end <= this.length`.
+ * If [end] is `null`, it defaults to [length].
+ */
+ String replaceRange(int start, int end, String replacement);
+
+ /**
+ * Splits the string at matches of [pattern] and returns a list of substrings.
+ *
+ * Finds all the matches of `pattern` in this string,
+ * and returns the list of the substrings between the matches.
+ *
+ * var string = "Hello world!";
+ * string.split(" "); // ['Hello', 'world!'];
+ *
+ * Empty matches at the beginning and end of the strings are ignored,
+ * and so are empty matches right after another match.
+ *
+ * var string = "abba";
+ * string.split(new RegExp(r"b*")); // ['a', 'a']
+ * // not ['', 'a', 'a', '']
+ *
+ * If this string is empty, the result is an empty list if `pattern` matches
+ * the empty string, and it is `[""]` if the pattern doesn't match.
+ *
+ * var string = '';
+ * string.split(''); // []
+ * string.split("a"); // ['']
+ *
+ * Splitting with an empty pattern splits the string into single-code unit
+ * strings.
+ *
+ * var string = 'Pub';
+ * string.split(''); // ['P', 'u', 'b']
+ *
+ * string.codeUnits.map((unit) {
+ * return new String.fromCharCode(unit);
+ * }).toList(); // ['P', 'u', 'b']
+ *
+ * Splitting happens at UTF-16 code unit boundaries,
+ * and not at rune boundaries:
+ *
+ * // String made up of two code units, but one rune.
+ * string = '\u{1D11E}';
+ * string.split('').length; // 2 surrogate values
+ *
+ * To get a list of strings containing the individual runes of a string,
+ * you should not use split. You can instead map each rune to a string
+ * as follows:
+ *
+ * string.runes.map((rune) => new String.fromCharCode(rune)).toList();
+ */
+ List<String> split(Pattern pattern);
+
+ /**
+ * Splits the string, converts its parts, and combines them into a new
+ * string.
+ *
+ * [pattern] is used to split the string into parts and separating matches.
+ *
+ * Each match is converted to a string by calling [onMatch]. If [onMatch]
+ * is omitted, the matched string is used.
+ *
+ * Each non-matched part is converted by a call to [onNonMatch]. If
+ * [onNonMatch] is omitted, the non-matching part is used.
+ *
+ * Then all the converted parts are combined into the resulting string.
+ *
+ * 'Eats shoots leaves'.splitMapJoin((new RegExp(r'shoots')),
+ * onMatch: (m) => '${m.group(0)}',
+ * onNonMatch: (n) => '*'); // *shoots*
+ */
+ String splitMapJoin(Pattern pattern,
+ {String onMatch(Match match), String onNonMatch(String nonMatch)});
+
+ /**
+ * Returns an unmodifiable list of the UTF-16 code units of this string.
+ */
+ List<int> get codeUnits;
+
+ /**
+ * Returns an [Iterable] of Unicode code-points of this string.
+ *
+ * If the string contains surrogate pairs, they are combined and returned
+ * as one integer by this iterator. Unmatched surrogate halves are treated
+ * like valid 16-bit code-units.
+ */
+ Runes get runes;
+
+ /**
+ * Converts all characters in this string to lower case.
+ * If the string is already in all lower case, this method returns [:this:].
+ *
+ * 'ALPHABET'.toLowerCase(); // 'alphabet'
+ * 'abc'.toLowerCase(); // 'abc'
+ *
+ * This function uses the language independent Unicode mapping and thus only
+ * works in some languages.
+ */
+ // TODO(floitsch): document better. (See EcmaScript for description).
+ String toLowerCase();
+
+ /**
+ * Converts all characters in this string to upper case.
+ * If the string is already in all upper case, this method returns [:this:].
+ *
+ * 'alphabet'.toUpperCase(); // 'ALPHABET'
+ * 'ABC'.toUpperCase(); // 'ABC'
+ *
+ * This function uses the language independent Unicode mapping and thus only
+ * works in some languages.
+ */
+ // TODO(floitsch): document better. (See EcmaScript for description).
+ String toUpperCase();
+}
+
+/**
+ * The runes (integer Unicode code points) of a [String].
+ */
+class Runes extends Iterable<int> {
+ final String string;
+ Runes(this.string);
+
+ RuneIterator get iterator => RuneIterator(string);
+
+ int get last {
+ if (string.length == 0) {
+ throw StateError('No elements.');
+ }
+ int length = string.length;
+ int code = string.codeUnitAt(length - 1);
+ if (_isTrailSurrogate(code) && string.length > 1) {
+ int previousCode = string.codeUnitAt(length - 2);
+ if (_isLeadSurrogate(previousCode)) {
+ return _combineSurrogatePair(previousCode, code);
+ }
+ }
+ return code;
+ }
+}
+
+// Is then code (a 16-bit unsigned integer) a UTF-16 lead surrogate.
+bool _isLeadSurrogate(int code) => (code & 0xFC00) == 0xD800;
+
+// Is then code (a 16-bit unsigned integer) a UTF-16 trail surrogate.
+bool _isTrailSurrogate(int code) => (code & 0xFC00) == 0xDC00;
+
+// Combine a lead and a trail surrogate value into a single code point.
+int _combineSurrogatePair(int start, int end) {
+ return 0x10000 + ((start & 0x3FF) << 10) + (end & 0x3FF);
+}
+
+/** [Iterator] for reading runes (integer Unicode code points) out of a Dart
+ * string.
+ */
+class RuneIterator implements BidirectionalIterator<int> {
+ /** String being iterated. */
+ final String string;
+ /** Position before the current code point. */
+ int _position;
+ /** Position after the current code point. */
+ int _nextPosition;
+ /**
+ * Current code point.
+ *
+ * If the iterator has hit either end, the [_currentCodePoint] is null
+ * and [: _position == _nextPosition :].
+ */
+ int _currentCodePoint;
+
+ /** Create an iterator positioned at the beginning of the string. */
+ RuneIterator(String string)
+ : this.string = string,
+ _position = 0,
+ _nextPosition = 0;
+
+ /**
+ * Create an iterator positioned before the [index]th code unit of the string.
+ *
+ * When created, there is no [current] value.
+ * A [moveNext] will use the rune starting at [index] the current value,
+ * and a [movePrevious] will use the rune ending just before [index] as the
+ * the current value.
+ *
+ * The [index] position must not be in the middle of a surrogate pair.
+ */
+ RuneIterator.at(String string, int index)
+ : string = string,
+ _position = index,
+ _nextPosition = index {
+ RangeError.checkValueInInterval(index, 0, string.length);
+ _checkSplitSurrogate(index);
+ }
+
+ /** Throw an error if the index is in the middle of a surrogate pair. */
+ void _checkSplitSurrogate(int index) {
+ if (index > 0 &&
+ index < string.length &&
+ _isLeadSurrogate(string.codeUnitAt(index - 1)) &&
+ _isTrailSurrogate(string.codeUnitAt(index))) {
+ throw ArgumentError('Index inside surrogate pair: $index');
+ }
+ }
+
+ /**
+ * Returns the starting position of the current rune in the string.
+ *
+ * Returns null if the [current] rune is null.
+ */
+ int get rawIndex => (_position != _nextPosition) ? _position : null;
+
+ /**
+ * Resets the iterator to the rune at the specified index of the string.
+ *
+ * Setting a negative [rawIndex], or one greater than or equal to
+ * [:string.length:],
+ * is an error. So is setting it in the middle of a surrogate pair.
+ *
+ * Setting the position to the end of then string will set [current] to null.
+ */
+ void set rawIndex(int rawIndex) {
+ RangeError.checkValidIndex(rawIndex, string, "rawIndex");
+ reset(rawIndex);
+ moveNext();
+ }
+
+ /**
+ * Resets the iterator to the given index into the string.
+ *
+ * After this the [current] value is unset.
+ * You must call [moveNext] make the rune at the position current,
+ * or [movePrevious] for the last rune before the position.
+ *
+ * Setting a negative [rawIndex], or one greater than [:string.length:],
+ * is an error. So is setting it in the middle of a surrogate pair.
+ */
+ void reset([int rawIndex = 0]) {
+ RangeError.checkValueInInterval(rawIndex, 0, string.length, "rawIndex");
+ _checkSplitSurrogate(rawIndex);
+ _position = _nextPosition = rawIndex;
+ _currentCodePoint = null;
+ }
+
+ /** The rune (integer Unicode code point) starting at the current position in
+ * the string.
+ */
+ int get current => _currentCodePoint;
+
+ /**
+ * The number of code units comprising the current rune.
+ *
+ * Returns zero if there is no current rune ([current] is null).
+ */
+ int get currentSize => _nextPosition - _position;
+
+ /**
+ * A string containing the current rune.
+ *
+ * For runes outside the basic multilingual plane, this will be
+ * a String of length 2, containing two code units.
+ *
+ * Returns null if [current] is null.
+ */
+ String get currentAsString {
+ if (_position == _nextPosition) return null;
+ if (_position + 1 == _nextPosition) return string[_position];
+ return string.substring(_position, _nextPosition);
+ }
+
+ bool moveNext() {
+ _position = _nextPosition;
+ if (_position == string.length) {
+ _currentCodePoint = null;
+ return false;
+ }
+ int codeUnit = string.codeUnitAt(_position);
+ int nextPosition = _position + 1;
+ if (_isLeadSurrogate(codeUnit) && nextPosition < string.length) {
+ int nextCodeUnit = string.codeUnitAt(nextPosition);
+ if (_isTrailSurrogate(nextCodeUnit)) {
+ _nextPosition = nextPosition + 1;
+ _currentCodePoint = _combineSurrogatePair(codeUnit, nextCodeUnit);
+ return true;
+ }
+ }
+ _nextPosition = nextPosition;
+ _currentCodePoint = codeUnit;
+ return true;
+ }
+
+ bool movePrevious() {
+ _nextPosition = _position;
+ if (_position == 0) {
+ _currentCodePoint = null;
+ return false;
+ }
+ int position = _position - 1;
+ int codeUnit = string.codeUnitAt(position);
+ if (_isTrailSurrogate(codeUnit) && position > 0) {
+ int prevCodeUnit = string.codeUnitAt(position - 1);
+ if (_isLeadSurrogate(prevCodeUnit)) {
+ _position = position - 1;
+ _currentCodePoint = _combineSurrogatePair(prevCodeUnit, codeUnit);
+ return true;
+ }
+ }
+ _position = position;
+ _currentCodePoint = codeUnit;
+ return true;
+ }
+}
diff --git a/sdk_nnbd/lib/core/string_buffer.dart b/sdk_nnbd/lib/core/string_buffer.dart
new file mode 100644
index 0000000..8fe17f5
--- /dev/null
+++ b/sdk_nnbd/lib/core/string_buffer.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * A class for concatenating strings efficiently.
+ *
+ * Allows for the incremental building of a string using write*() methods.
+ * The strings are concatenated to a single string only when [toString] is
+ * called.
+ */
+class StringBuffer implements StringSink {
+ /** Creates the string buffer with an initial content. */
+ external StringBuffer([Object content = ""]);
+
+ /**
+ * Returns the length of the content that has been accumulated so far.
+ * This is a constant-time operation.
+ */
+ external int get length;
+
+ /** Returns whether the buffer is empty. This is a constant-time operation. */
+ bool get isEmpty => length == 0;
+
+ /**
+ * Returns whether the buffer is not empty. This is a constant-time
+ * operation.
+ */
+ bool get isNotEmpty => !isEmpty;
+
+ /// Adds the contents of [obj], converted to a string, to the buffer.
+ external void write(Object obj);
+
+ /// Adds the string representation of [charCode] to the buffer.
+ external void writeCharCode(int charCode);
+
+ external void writeAll(Iterable objects, [String separator = ""]);
+
+ external void writeln([Object obj = ""]);
+
+ /**
+ * Clears the string buffer.
+ */
+ external void clear();
+
+ /// Returns the contents of buffer as a concatenated string.
+ external String toString();
+}
diff --git a/sdk_nnbd/lib/core/string_sink.dart b/sdk_nnbd/lib/core/string_sink.dart
new file mode 100644
index 0000000..e7d950c
--- /dev/null
+++ b/sdk_nnbd/lib/core/string_sink.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+abstract class StringSink {
+ /**
+ * Converts [obj] to a String by invoking [Object.toString] and
+ * adds the result to `this`.
+ */
+ void write(Object obj);
+
+ /**
+ * Iterates over the given [objects] and [write]s them in sequence.
+ */
+ void writeAll(Iterable objects, [String separator = ""]);
+
+ /**
+ * Converts [obj] to a String by invoking [Object.toString] and
+ * adds the result to `this`, followed by a newline.
+ */
+ void writeln([Object obj = ""]);
+
+ /**
+ * Writes the [charCode] to `this`.
+ *
+ * This method is equivalent to `write(new String.fromCharCode(charCode))`.
+ */
+ void writeCharCode(int charCode);
+}
diff --git a/sdk_nnbd/lib/core/symbol.dart b/sdk_nnbd/lib/core/symbol.dart
new file mode 100644
index 0000000..a46ec97
--- /dev/null
+++ b/sdk_nnbd/lib/core/symbol.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/// Opaque name used by mirrors, invocations and [Function.apply].
+abstract class Symbol {
+ /** The symbol corresponding to the name of the unary minus operator. */
+ static const Symbol unaryMinus = Symbol("unary-");
+
+ /**
+ * The empty symbol.
+ *
+ * The empty symbol is the name of libraries with no library declaration,
+ * and the base-name of the unnamed constructor.
+ */
+ static const Symbol empty = Symbol("");
+
+ /**
+ * Constructs a new [Symbol] representing the provided name.
+ *
+ * The name must be a valid public Dart member name,
+ * public constructor name, or library name, optionally qualified.
+ *
+ * A qualified name is a valid name preceded by a public identifier name
+ * and a '`.`', e.g., `foo.bar.baz=` is a qualified version of `baz=`.
+ * That means that the content of the [name] String must be either
+ *
+ * * a valid public Dart identifier
+ * (that is, an identifier not starting with "`_`"),
+ * * such an identifier followed by "=" (a setter name),
+ * * the name of a declarable operator
+ * (one of "`+`", "`-`", "`*`", "`/`", "`%`", "`~/`", "`&`", "`|`",
+ * "`^`", "`~`", "`<<`", "`>>`", "`<`", "`<=`", "`>`", "`>=`", "`==`",
+ * "`[]`", "`[]=`", or "`unary-`"),
+ * * any of the above preceded by any number of qualifiers,
+ * where a qualifier is a non-private identifier followed by '`.`',
+ * * or the empty string (the default name of a library with no library
+ * name declaration).
+ *
+ * Symbol instances created from the same [name] are equal,
+ * but not necessarily identical, but symbols created as compile-time
+ * constants are canonicalized, as all other constant object creations.
+ *
+ * ```dart
+ * assert(new Symbol("foo") == new Symbol("foo"));
+ * assert(identical(const Symbol("foo"), const Symbol("foo")));
+ * ```
+ *
+ * If [name] is a single identifier that does not start with an underscore,
+ * or it is a qualified identifier,
+ * or it is an operator name different from `unary-`,
+ * then the result of `const Symbol(name)` is the same instance that
+ * the symbol literal created by prefixing `#` to the content of [name]
+ * would evaluate to.
+ *
+ * ```dart
+ * assert(new Symbol("foo") == #foo);
+ * assert(new Symbol("[]=") == #[]=]);
+ * assert(new Symbol("foo.bar") == #foo.bar);
+ * assert(identical(const Symbol("foo"), #foo));
+ * assert(identical(const Symbol("[]="), #[]=]));
+ * assert(identical(const Symbol("foo.bar"), #foo.bar));
+ * ```
+ *
+ * This constructor cannot create a [Symbol] instance that is equal to
+ * a private symbol literal like `#_foo`.
+ * ```dart
+ * const Symbol("_foo") // Invalid
+ * ```
+ *
+ * The created instance overrides [Object.==].
+ *
+ * The following text is non-normative:
+ *
+ * Creating non-const Symbol instances may result in larger output. If
+ * possible, use `MirrorsUsed` from "dart:mirrors" to specify which names
+ * might be passed to this constructor.
+ */
+ const factory Symbol(String name) = internal.Symbol;
+
+ /**
+ * Returns a hash code compatible with [operator==].
+ *
+ * Equal symbols have the same hash code.
+ */
+ int get hashCode;
+
+ /**
+ * Symbols are equal to other symbols that correspond to the same member name.
+ *
+ * Qualified member names, like `#foo.bar` are equal only if they have the
+ * same identifiers before the same final member name.
+ */
+ bool operator ==(other);
+}
diff --git a/sdk_nnbd/lib/core/type.dart b/sdk_nnbd/lib/core/type.dart
new file mode 100644
index 0000000..d2e107b
--- /dev/null
+++ b/sdk_nnbd/lib/core/type.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+/**
+ * Runtime representation of a type.
+ */
+abstract class Type {}
diff --git a/sdk_nnbd/lib/core/uri.dart b/sdk_nnbd/lib/core/uri.dart
new file mode 100644
index 0000000..2ca94a1
--- /dev/null
+++ b/sdk_nnbd/lib/core/uri.dart
@@ -0,0 +1,4784 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.core;
+
+// Frequently used character codes.
+const int _SPACE = 0x20;
+const int _PERCENT = 0x25;
+const int _AMPERSAND = 0x26;
+const int _PLUS = 0x2B;
+const int _DOT = 0x2E;
+const int _SLASH = 0x2F;
+const int _COLON = 0x3A;
+const int _EQUALS = 0x3d;
+const int _UPPER_CASE_A = 0x41;
+const int _UPPER_CASE_Z = 0x5A;
+const int _LEFT_BRACKET = 0x5B;
+const int _BACKSLASH = 0x5C;
+const int _RIGHT_BRACKET = 0x5D;
+const int _LOWER_CASE_A = 0x61;
+const int _LOWER_CASE_F = 0x66;
+const int _LOWER_CASE_Z = 0x7A;
+
+const String _hexDigits = "0123456789ABCDEF";
+
+/**
+ * A parsed URI, such as a URL.
+ *
+ * **See also:**
+ *
+ * * [URIs][uris] in the [library tour][libtour]
+ * * [RFC-3986](http://tools.ietf.org/html/rfc3986)
+ *
+ * [uris]: https://www.dartlang.org/docs/dart-up-and-running/ch03.html#uris
+ * [libtour]: https://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html
+ */
+abstract class Uri {
+ /**
+ * Returns the natural base URI for the current platform.
+ *
+ * When running in a browser this is the current URL of the current page
+ * (from `window.location.href`).
+ *
+ * When not running in a browser this is the file URI referencing
+ * the current working directory.
+ */
+ external static Uri get base;
+
+ /**
+ * Creates a new URI from its components.
+ *
+ * Each component is set through a named argument. Any number of
+ * components can be provided. The [path] and [query] components can be set
+ * using either of two different named arguments.
+ *
+ * The scheme component is set through [scheme]. The scheme is
+ * normalized to all lowercase letters. If the scheme is omitted or empty,
+ * the URI will not have a scheme part.
+ *
+ * The user info part of the authority component is set through
+ * [userInfo]. It defaults to the empty string, which will be omitted
+ * from the string representation of the URI.
+ *
+ * The host part of the authority component is set through
+ * [host]. The host can either be a hostname, an IPv4 address or an
+ * IPv6 address, contained in '[' and ']'. If the host contains a
+ * ':' character, the '[' and ']' are added if not already provided.
+ * The host is normalized to all lowercase letters.
+ *
+ * The port part of the authority component is set through
+ * [port].
+ * If [port] is omitted or `null`, it implies the default port for
+ * the URI's scheme, and is equivalent to passing that port explicitly.
+ * The recognized schemes, and their default ports, are "http" (80) and
+ * "https" (443). All other schemes are considered as having zero as the
+ * default port.
+ *
+ * If any of `userInfo`, `host` or `port` are provided,
+ * the URI has an authority according to [hasAuthority].
+ *
+ * The path component is set through either [path] or
+ * [pathSegments].
+ * When [path] is used, it should be a valid URI path,
+ * but invalid characters, except the general delimiters ':/@[]?#',
+ * will be escaped if necessary.
+ * When [pathSegments] is used, each of the provided segments
+ * is first percent-encoded and then joined using the forward slash
+ * separator.
+ *
+ * The percent-encoding of the path segments encodes all
+ * characters except for the unreserved characters and the following
+ * list of characters: `!$&'()*+,;=:@`. If the other components
+ * necessitate an absolute path, a leading slash `/` is prepended if
+ * not already there.
+ *
+ * The query component is set through either [query] or [queryParameters].
+ * When [query] is used, the provided string should be a valid URI query,
+ * but invalid characters, other than general delimiters,
+ * will be escaped if necessary.
+ * When [queryParameters] is used the query is built from the
+ * provided map. Each key and value in the map is percent-encoded
+ * and joined using equal and ampersand characters.
+ * A value in the map must be either a string, or an [Iterable] of strings,
+ * where the latter corresponds to multiple values for the same key.
+ *
+ * The percent-encoding of the keys and values encodes all characters
+ * except for the unreserved characters, and replaces spaces with `+`.
+ * If `query` is the empty string, it is equivalent to omitting it.
+ * To have an actual empty query part,
+ * use an empty map for `queryParameters`.
+ *
+ * If both `query` and `queryParameters` are omitted or `null`,
+ * the URI has no query part.
+ *
+ * The fragment component is set through [fragment].
+ * It should be a valid URI fragment, but invalid characters other than
+ * general delimiters, are escaped if necessary.
+ * If `fragment` is omitted or `null`, the URI has no fragment part.
+ */
+ factory Uri(
+ {String scheme,
+ String userInfo,
+ String host,
+ int port,
+ String path,
+ Iterable<String> pathSegments,
+ String query,
+ Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
+ String fragment}) = _Uri;
+
+ /**
+ * Creates a new `http` URI from authority, path and query.
+ *
+ * Examples:
+ *
+ * ```
+ * // http://example.org/path?q=dart.
+ * new Uri.http("example.org", "/path", { "q" : "dart" });
+ *
+ * // http://user:pass@localhost:8080
+ * new Uri.http("user:pass@localhost:8080", "");
+ *
+ * // http://example.org/a%20b
+ * new Uri.http("example.org", "a b");
+ *
+ * // http://example.org/a%252F
+ * new Uri.http("example.org", "/a%2F");
+ * ```
+ *
+ * The `scheme` is always set to `http`.
+ *
+ * The `userInfo`, `host` and `port` components are set from the
+ * [authority] argument. If `authority` is `null` or empty,
+ * the created `Uri` has no authority, and isn't directly usable
+ * as an HTTP URL, which must have a non-empty host.
+ *
+ * The `path` component is set from the [unencodedPath]
+ * argument. The path passed must not be encoded as this constructor
+ * encodes the path.
+ *
+ * The `query` component is set from the optional [queryParameters]
+ * argument.
+ */
+ factory Uri.http(String authority, String unencodedPath,
+ [Map<String, String> queryParameters]) = _Uri.http;
+
+ /**
+ * Creates a new `https` URI from authority, path and query.
+ *
+ * This constructor is the same as [Uri.http] except for the scheme
+ * which is set to `https`.
+ */
+ factory Uri.https(String authority, String unencodedPath,
+ [Map<String, String> queryParameters]) = _Uri.https;
+
+ /**
+ * Creates a new file URI from an absolute or relative file path.
+ *
+ * The file path is passed in [path].
+ *
+ * This path is interpreted using either Windows or non-Windows
+ * semantics.
+ *
+ * With non-Windows semantics the slash (`/`) is used to separate
+ * path segments in the input [path].
+ *
+ * With Windows semantics, backslash (`\`) and forward-slash (`/`)
+ * are used to separate path segments in the input [path],
+ * except if the path starts with `\\?\` in which case
+ * only backslash (`\`) separates path segments in [path].
+ *
+ * If the path starts with a path separator, an absolute URI (with the
+ * `file` scheme and an empty authority) is created.
+ * Otherwise a relative URI reference with no scheme or authority is created.
+ * One exception from this rule is that when Windows semantics is used
+ * and the path starts with a drive letter followed by a colon (":") and a
+ * path separator, then an absolute URI is created.
+ *
+ * The default for whether to use Windows or non-Windows semantics
+ * determined from the platform Dart is running on. When running in
+ * the standalone VM, this is detected by the VM based on the
+ * operating system. When running in a browser non-Windows semantics
+ * is always used.
+ *
+ * To override the automatic detection of which semantics to use pass
+ * a value for [windows]. Passing `true` will use Windows
+ * semantics and passing `false` will use non-Windows semantics.
+ *
+ * Examples using non-Windows semantics:
+ *
+ * ```
+ * // xxx/yyy
+ * new Uri.file("xxx/yyy", windows: false);
+ *
+ * // xxx/yyy/
+ * new Uri.file("xxx/yyy/", windows: false);
+ *
+ * // file:///xxx/yyy
+ * new Uri.file("/xxx/yyy", windows: false);
+ *
+ * // file:///xxx/yyy/
+ * new Uri.file("/xxx/yyy/", windows: false);
+ *
+ * // C%3A
+ * new Uri.file("C:", windows: false);
+ * ```
+ *
+ * Examples using Windows semantics:
+ *
+ * ```
+ * // xxx/yyy
+ * new Uri.file(r"xxx\yyy", windows: true);
+ *
+ * // xxx/yyy/
+ * new Uri.file(r"xxx\yyy\", windows: true);
+ *
+ * file:///xxx/yyy
+ * new Uri.file(r"\xxx\yyy", windows: true);
+ *
+ * file:///xxx/yyy/
+ * new Uri.file(r"\xxx\yyy/", windows: true);
+ *
+ * // file:///C:/xxx/yyy
+ * new Uri.file(r"C:\xxx\yyy", windows: true);
+ *
+ * // This throws an error. A path with a drive letter, but no following
+ * // path, is not allowed.
+ * new Uri.file(r"C:", windows: true);
+ *
+ * // This throws an error. A path with a drive letter is not absolute.
+ * new Uri.file(r"C:xxx\yyy", windows: true);
+ *
+ * // file://server/share/file
+ * new Uri.file(r"\\server\share\file", windows: true);
+ * ```
+ *
+ * If the path passed is not a valid file path, an error is thrown.
+ */
+ factory Uri.file(String path, {bool windows}) = _Uri.file;
+
+ /**
+ * Like [Uri.file] except that a non-empty URI path ends in a slash.
+ *
+ * If [path] is not empty, and it doesn't end in a directory separator,
+ * then a slash is added to the returned URI's path.
+ * In all other cases, the result is the same as returned by `Uri.file`.
+ */
+ factory Uri.directory(String path, {bool windows}) = _Uri.directory;
+
+ /**
+ * Creates a `data:` URI containing the [content] string.
+ *
+ * Converts the content to a bytes using [encoding] or the charset specified
+ * in [parameters] (defaulting to US-ASCII if not specified or unrecognized),
+ * then encodes the bytes into the resulting data URI.
+ *
+ * Defaults to encoding using percent-encoding (any non-ASCII or non-URI-valid
+ * bytes is replaced by a percent encoding). If [base64] is true, the bytes
+ * are instead encoded using [base64].
+ *
+ * If [encoding] is not provided and [parameters] has a `charset` entry,
+ * that name is looked up using [Encoding.getByName],
+ * and if the lookup returns an encoding, that encoding is used to convert
+ * [content] to bytes.
+ * If providing both an [encoding] and a charset in [parameters], they should
+ * agree, otherwise decoding won't be able to use the charset parameter
+ * to determine the encoding.
+ *
+ * If [mimeType] and/or [parameters] are supplied, they are added to the
+ * created URI. If any of these contain characters that are not allowed
+ * in the data URI, the character is percent-escaped. If the character is
+ * non-ASCII, it is first UTF-8 encoded and then the bytes are percent
+ * encoded. An omitted [mimeType] in a data URI means `text/plain`, just
+ * as an omitted `charset` parameter defaults to meaning `US-ASCII`.
+ *
+ * To read the content back, use [UriData.contentAsString].
+ */
+ factory Uri.dataFromString(String content,
+ {String mimeType,
+ Encoding encoding,
+ Map<String, String> parameters,
+ bool base64 = false}) {
+ UriData data = UriData.fromString(content,
+ mimeType: mimeType,
+ encoding: encoding,
+ parameters: parameters,
+ base64: base64);
+ return data.uri;
+ }
+
+ /**
+ * Creates a `data:` URI containing an encoding of [bytes].
+ *
+ * Defaults to Base64 encoding the bytes, but if [percentEncoded]
+ * is `true`, the bytes will instead be percent encoded (any non-ASCII
+ * or non-valid-ASCII-character byte is replaced by a percent encoding).
+ *
+ * To read the bytes back, use [UriData.contentAsBytes].
+ *
+ * It defaults to having the mime-type `application/octet-stream`.
+ * The [mimeType] and [parameters] are added to the created URI.
+ * If any of these contain characters that are not allowed
+ * in the data URI, the character is percent-escaped. If the character is
+ * non-ASCII, it is first UTF-8 encoded and then the bytes are percent
+ * encoded.
+ */
+ factory Uri.dataFromBytes(List<int> bytes,
+ {mimeType = "application/octet-stream",
+ Map<String, String> parameters,
+ percentEncoded = false}) {
+ UriData data = UriData.fromBytes(bytes,
+ mimeType: mimeType,
+ parameters: parameters,
+ percentEncoded: percentEncoded);
+ return data.uri;
+ }
+
+ /**
+ * The scheme component of the URI.
+ *
+ * Returns the empty string if there is no scheme component.
+ *
+ * A URI scheme is case insensitive.
+ * The returned scheme is canonicalized to lowercase letters.
+ */
+ String get scheme;
+
+ /**
+ * Returns the authority component.
+ *
+ * The authority is formatted from the [userInfo], [host] and [port]
+ * parts.
+ *
+ * Returns the empty string if there is no authority component.
+ */
+ String get authority;
+
+ /**
+ * Returns the user info part of the authority component.
+ *
+ * Returns the empty string if there is no user info in the
+ * authority component.
+ */
+ String get userInfo;
+
+ /**
+ * Returns the host part of the authority component.
+ *
+ * Returns the empty string if there is no authority component and
+ * hence no host.
+ *
+ * If the host is an IP version 6 address, the surrounding `[` and `]` is
+ * removed.
+ *
+ * The host string is case-insensitive.
+ * The returned host name is canonicalized to lower-case
+ * with upper-case percent-escapes.
+ */
+ String get host;
+
+ /**
+ * Returns the port part of the authority component.
+ *
+ * Returns the default port if there is no port number in the authority
+ * component. That's 80 for http, 443 for https, and 0 for everything else.
+ */
+ int get port;
+
+ /**
+ * Returns the path component.
+ *
+ * The returned path is encoded. To get direct access to the decoded
+ * path use [pathSegments].
+ *
+ * Returns the empty string if there is no path component.
+ */
+ String get path;
+
+ /**
+ * Returns the query component. The returned query is encoded. To get
+ * direct access to the decoded query use [queryParameters].
+ *
+ * Returns the empty string if there is no query component.
+ */
+ String get query;
+
+ /**
+ * Returns the fragment identifier component.
+ *
+ * Returns the empty string if there is no fragment identifier
+ * component.
+ */
+ String get fragment;
+
+ /**
+ * Returns the URI path split into its segments. Each of the segments in the
+ * returned list have been decoded. If the path is empty the empty list will
+ * be returned. A leading slash `/` does not affect the segments returned.
+ *
+ * The returned list is unmodifiable and will throw [UnsupportedError] on any
+ * calls that would mutate it.
+ */
+ List<String> get pathSegments;
+
+ /**
+ * Returns the URI query split into a map according to the rules
+ * specified for FORM post in the [HTML 4.01 specification section
+ * 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
+ * Each key and value in the returned map has been decoded.
+ * If there is no query the empty map is returned.
+ *
+ * Keys in the query string that have no value are mapped to the
+ * empty string.
+ * If a key occurs more than once in the query string, it is mapped to
+ * an arbitrary choice of possible value.
+ * The [queryParametersAll] getter can provide a map
+ * that maps keys to all of their values.
+ *
+ * The returned map is unmodifiable.
+ */
+ Map<String, String> get queryParameters;
+
+ /**
+ * Returns the URI query split into a map according to the rules
+ * specified for FORM post in the [HTML 4.01 specification section
+ * 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
+ * Each key and value in the returned map has been decoded. If there is no
+ * query the empty map is returned.
+ *
+ * Keys are mapped to lists of their values. If a key occurs only once,
+ * its value is a singleton list. If a key occurs with no value, the
+ * empty string is used as the value for that occurrence.
+ *
+ * The returned map and the lists it contains are unmodifiable.
+ */
+ Map<String, List<String>> get queryParametersAll;
+
+ /**
+ * Returns whether the URI is absolute.
+ *
+ * A URI is an absolute URI in the sense of RFC 3986 if it has a scheme
+ * and no fragment.
+ */
+ bool get isAbsolute;
+
+ /**
+ * Returns whether the URI has a [scheme] component.
+ */
+ bool get hasScheme => scheme.isNotEmpty;
+
+ /**
+ * Returns whether the URI has an [authority] component.
+ */
+ bool get hasAuthority;
+
+ /**
+ * Returns whether the URI has an explicit port.
+ *
+ * If the port number is the default port number
+ * (zero for unrecognized schemes, with http (80) and https (443) being
+ * recognized),
+ * then the port is made implicit and omitted from the URI.
+ */
+ bool get hasPort;
+
+ /**
+ * Returns whether the URI has a query part.
+ */
+ bool get hasQuery;
+
+ /**
+ * Returns whether the URI has a fragment part.
+ */
+ bool get hasFragment;
+
+ /**
+ * Returns whether the URI has an empty path.
+ */
+ bool get hasEmptyPath;
+
+ /**
+ * Returns whether the URI has an absolute path (starting with '/').
+ */
+ bool get hasAbsolutePath;
+
+ /**
+ * Returns the origin of the URI in the form scheme://host:port for the
+ * schemes http and https.
+ *
+ * It is an error if the scheme is not "http" or "https", or if the host name
+ * is missing or empty.
+ *
+ * See: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin
+ */
+ String get origin;
+
+ /// Whether the scheme of this [Uri] is [scheme].
+ ///
+ /// The [scheme] should be the same as the one returned by [Uri.scheme],
+ /// but doesn't have to be case-normalized to lower-case characters.
+ ///
+ /// Example:
+ /// ```dart
+ /// var uri = Uri.parse("http://example.com/");
+ /// print(uri.isScheme("HTTP")); // Prints true.
+ /// ```
+ ///
+ /// A `null` or empty [scheme] string matches a URI with no scheme
+ /// (one where [hasScheme] returns false).
+ bool isScheme(String scheme);
+
+ /**
+ * Returns the file path from a file URI.
+ *
+ * The returned path has either Windows or non-Windows
+ * semantics.
+ *
+ * For non-Windows semantics the slash ("/") is used to separate
+ * path segments.
+ *
+ * For Windows semantics the backslash ("\\") separator is used to
+ * separate path segments.
+ *
+ * If the URI is absolute the path starts with a path separator
+ * unless Windows semantics is used and the first path segment is a
+ * drive letter. When Windows semantics is used a host component in
+ * the uri in interpreted as a file server and a UNC path is
+ * returned.
+ *
+ * The default for whether to use Windows or non-Windows semantics
+ * determined from the platform Dart is running on. When running in
+ * the standalone VM this is detected by the VM based on the
+ * operating system. When running in a browser non-Windows semantics
+ * is always used.
+ *
+ * To override the automatic detection of which semantics to use pass
+ * a value for [windows]. Passing `true` will use Windows
+ * semantics and passing `false` will use non-Windows semantics.
+ *
+ * If the URI ends with a slash (i.e. the last path component is
+ * empty) the returned file path will also end with a slash.
+ *
+ * With Windows semantics URIs starting with a drive letter cannot
+ * be relative to the current drive on the designated drive. That is
+ * for the URI `file:///c:abc` calling `toFilePath` will throw as a
+ * path segment cannot contain colon on Windows.
+ *
+ * Examples using non-Windows semantics (resulting of calling
+ * toFilePath in comment):
+ *
+ * Uri.parse("xxx/yyy"); // xxx/yyy
+ * Uri.parse("xxx/yyy/"); // xxx/yyy/
+ * Uri.parse("file:///xxx/yyy"); // /xxx/yyy
+ * Uri.parse("file:///xxx/yyy/"); // /xxx/yyy/
+ * Uri.parse("file:///C:"); // /C:
+ * Uri.parse("file:///C:a"); // /C:a
+ *
+ * Examples using Windows semantics (resulting URI in comment):
+ *
+ * Uri.parse("xxx/yyy"); // xxx\yyy
+ * Uri.parse("xxx/yyy/"); // xxx\yyy\
+ * Uri.parse("file:///xxx/yyy"); // \xxx\yyy
+ * Uri.parse("file:///xxx/yyy/"); // \xxx\yyy\
+ * Uri.parse("file:///C:/xxx/yyy"); // C:\xxx\yyy
+ * Uri.parse("file:C:xxx/yyy"); // Throws as a path segment
+ * // cannot contain colon on Windows.
+ * Uri.parse("file://server/share/file"); // \\server\share\file
+ *
+ * If the URI is not a file URI calling this throws
+ * [UnsupportedError].
+ *
+ * If the URI cannot be converted to a file path calling this throws
+ * [UnsupportedError].
+ */
+ // TODO(lrn): Deprecate and move functionality to File class or similar.
+ // The core libraries should not worry about the platform.
+ String toFilePath({bool windows});
+
+ /**
+ * Access the structure of a `data:` URI.
+ *
+ * Returns a [UriData] object for `data:` URIs and `null` for all other
+ * URIs.
+ * The [UriData] object can be used to access the media type and data
+ * of a `data:` URI.
+ */
+ UriData get data;
+
+ /// Returns a hash code computed as `toString().hashCode`.
+ ///
+ /// This guarantees that URIs with the same normalized
+ int get hashCode;
+
+ /// A URI is equal to another URI with the same normalized representation.
+ bool operator ==(Object other);
+
+ /// Returns the normalized string representation of the URI.
+ String toString();
+
+ /**
+ * Returns a new `Uri` based on this one, but with some parts replaced.
+ *
+ * This method takes the same parameters as the [new Uri] constructor,
+ * and they have the same meaning.
+ *
+ * At most one of [path] and [pathSegments] must be provided.
+ * Likewise, at most one of [query] and [queryParameters] must be provided.
+ *
+ * Each part that is not provided will default to the corresponding
+ * value from this `Uri` instead.
+ *
+ * This method is different from [Uri.resolve] which overrides in a
+ * hierarchical manner,
+ * and can instead replace each part of a `Uri` individually.
+ *
+ * Example:
+ *
+ * Uri uri1 = Uri.parse("a://b@c:4/d/e?f#g");
+ * Uri uri2 = uri1.replace(scheme: "A", path: "D/E/E", fragment: "G");
+ * print(uri2); // prints "a://b@c:4/D/E/E?f#G"
+ *
+ * This method acts similarly to using the `new Uri` constructor with
+ * some of the arguments taken from this `Uri`. Example:
+ *
+ * Uri uri3 = new Uri(
+ * scheme: "A",
+ * userInfo: uri1.userInfo,
+ * host: uri1.host,
+ * port: uri1.port,
+ * path: "D/E/E",
+ * query: uri1.query,
+ * fragment: "G");
+ * print(uri3); // prints "a://b@c:4/D/E/E?f#G"
+ * print(uri2 == uri3); // prints true.
+ *
+ * Using this method can be seen as a shorthand for the `Uri` constructor
+ * call above, but may also be slightly faster because the parts taken
+ * from this `Uri` need not be checked for validity again.
+ */
+ Uri replace(
+ {String scheme,
+ String userInfo,
+ String host,
+ int port,
+ String path,
+ Iterable<String> pathSegments,
+ String query,
+ Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
+ String fragment});
+
+ /**
+ * Returns a `Uri` that differs from this only in not having a fragment.
+ *
+ * If this `Uri` does not have a fragment, it is itself returned.
+ */
+ Uri removeFragment();
+
+ /**
+ * Resolve [reference] as an URI relative to `this`.
+ *
+ * First turn [reference] into a URI using [Uri.parse]. Then resolve the
+ * resulting URI relative to `this`.
+ *
+ * Returns the resolved URI.
+ *
+ * See [resolveUri] for details.
+ */
+ Uri resolve(String reference);
+
+ /**
+ * Resolve [reference] as an URI relative to `this`.
+ *
+ * Returns the resolved URI.
+ *
+ * The algorithm "Transform Reference" for resolving a reference is described
+ * in [RFC-3986 Section 5](http://tools.ietf.org/html/rfc3986#section-5 "RFC-1123").
+ *
+ * Updated to handle the case where the base URI is just a relative path -
+ * that is: when it has no scheme and no authority and the path does not start
+ * with a slash.
+ * In that case, the paths are combined without removing leading "..", and
+ * an empty path is not converted to "/".
+ */
+ Uri resolveUri(Uri reference);
+
+ /**
+ * Returns a URI where the path has been normalized.
+ *
+ * A normalized path does not contain `.` segments or non-leading `..`
+ * segments.
+ * Only a relative path with no scheme or authority may contain
+ * leading `..` segments,
+ * a path that starts with `/` will also drop any leading `..` segments.
+ *
+ * This uses the same normalization strategy as `new Uri().resolve(this)`.
+ *
+ * Does not change any part of the URI except the path.
+ *
+ * The default implementation of `Uri` always normalizes paths, so calling
+ * this function has no effect.
+ */
+ Uri normalizePath();
+
+ /**
+ * Creates a new `Uri` object by parsing a URI string.
+ *
+ * If [start] and [end] are provided, they must specify a valid substring
+ * of [uri], and only the substring from `start` to `end` is parsed as a URI.
+ *
+ * The [uri] must not be `null`.
+ * If the [uri] string is not valid as a URI or URI reference,
+ * a [FormatException] is thrown.
+ */
+ static Uri parse(String uri, [int start = 0, int end]) {
+ // This parsing will not validate percent-encoding, IPv6, etc.
+ // When done splitting into parts, it will call, e.g., [_makeFragment]
+ // to do the final parsing.
+ //
+ // Important parts of the RFC 3986 used here:
+ // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+ //
+ // hier-part = "//" authority path-abempty
+ // / path-absolute
+ // / path-rootless
+ // / path-empty
+ //
+ // URI-reference = URI / relative-ref
+ //
+ // absolute-URI = scheme ":" hier-part [ "?" query ]
+ //
+ // relative-ref = relative-part [ "?" query ] [ "#" fragment ]
+ //
+ // relative-part = "//" authority path-abempty
+ // / path-absolute
+ // / path-noscheme
+ // / path-empty
+ //
+ // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ //
+ // authority = [ userinfo "@" ] host [ ":" port ]
+ // userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+ // host = IP-literal / IPv4address / reg-name
+ // IP-literal = "[" ( IPv6address / IPv6addrz / IPvFuture ) "]"
+ // IPv6addrz = IPv6address "%25" ZoneID
+ // ZoneID = 1*( unreserved / pct-encoded )
+ // port = *DIGIT
+ // reg-name = *( unreserved / pct-encoded / sub-delims )
+ //
+ // path = path-abempty ; begins with "/" or is empty
+ // / path-absolute ; begins with "/" but not "//"
+ // / path-noscheme ; begins with a non-colon segment
+ // / path-rootless ; begins with a segment
+ // / path-empty ; zero characters
+ //
+ // path-abempty = *( "/" segment )
+ // path-absolute = "/" [ segment-nz *( "/" segment ) ]
+ // path-noscheme = segment-nz-nc *( "/" segment )
+ // path-rootless = segment-nz *( "/" segment )
+ // path-empty = 0<pchar>
+ //
+ // segment = *pchar
+ // segment-nz = 1*pchar
+ // segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
+ // ; non-zero-length segment without any colon ":"
+ //
+ // pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ //
+ // query = *( pchar / "/" / "?" )
+ //
+ // fragment = *( pchar / "/" / "?" )
+ end ??= uri.length;
+
+ // Special case data:URIs. Ignore case when testing.
+ if (end >= start + 5) {
+ int dataDelta = _startsWithData(uri, start);
+ if (dataDelta == 0) {
+ // The case is right.
+ if (start > 0 || end < uri.length) uri = uri.substring(start, end);
+ return UriData._parse(uri, 5, null).uri;
+ } else if (dataDelta == 0x20) {
+ return UriData._parse(uri.substring(start + 5, end), 0, null).uri;
+ }
+ // Otherwise the URI doesn't start with "data:" or any case variant of it.
+ }
+
+ // The following index-normalization belongs with the scanning, but is
+ // easier to do here because we already have extracted variables from the
+ // indices list.
+ var indices = List<int>(8);
+
+ // Set default values for each position.
+ // The value will either be correct in some cases where it isn't set
+ // by the scanner, or it is clearly recognizable as an unset value.
+ indices
+ ..[0] = 0
+ ..[_schemeEndIndex] = start - 1
+ ..[_hostStartIndex] = start - 1
+ ..[_notSimpleIndex] = start - 1
+ ..[_portStartIndex] = start
+ ..[_pathStartIndex] = start
+ ..[_queryStartIndex] = end
+ ..[_fragmentStartIndex] = end;
+ var state = _scan(uri, start, end, _uriStart, indices);
+ // Some states that should be non-simple, but the URI ended early.
+ // Paths that end at a ".." must be normalized to end in "../".
+ if (state >= _nonSimpleEndStates) {
+ indices[_notSimpleIndex] = end;
+ }
+ int schemeEnd = indices[_schemeEndIndex];
+ if (schemeEnd >= start) {
+ // Rescan the scheme part now that we know it's not a path.
+ state = _scan(uri, start, schemeEnd, _schemeStart, indices);
+ if (state == _schemeStart) {
+ // Empty scheme.
+ indices[_notSimpleIndex] = schemeEnd;
+ }
+ }
+ // The returned positions are limited by the scanners ability to write only
+ // one position per character, and only the current position.
+ // Scanning from left to right, we only know whether something is a scheme
+ // or a path when we see a `:` or `/`, and likewise we only know if the first
+ // `/` is part of the path or is leading an authority component when we see
+ // the next character.
+
+ int hostStart = indices[_hostStartIndex] + 1;
+ int portStart = indices[_portStartIndex];
+ int pathStart = indices[_pathStartIndex];
+ int queryStart = indices[_queryStartIndex];
+ int fragmentStart = indices[_fragmentStartIndex];
+
+ // We may discover scheme while handling special cases.
+ String scheme;
+
+ // Derive some positions that weren't set to normalize the indices.
+ if (fragmentStart < queryStart) queryStart = fragmentStart;
+ // If pathStart isn't set (it's before scheme end or host start), then
+ // the path is empty, or there is no authority part and the path
+ // starts with a non-simple character.
+ if (pathStart < hostStart) {
+ // There is an authority, but no path. The path would start with `/`
+ // if it was there.
+ pathStart = queryStart;
+ } else if (pathStart <= schemeEnd) {
+ // There is a scheme, but no authority.
+ pathStart = schemeEnd + 1;
+ }
+ // If there is an authority with no port, set the port position
+ // to be at the end of the authority (equal to pathStart).
+ // This also handles a ":" in a user-info component incorrectly setting
+ // the port start position.
+ if (portStart < hostStart) portStart = pathStart;
+
+ assert(hostStart == start || schemeEnd <= hostStart);
+ assert(hostStart <= portStart);
+ assert(schemeEnd <= pathStart);
+ assert(portStart <= pathStart);
+ assert(pathStart <= queryStart);
+ assert(queryStart <= fragmentStart);
+
+ bool isSimple = indices[_notSimpleIndex] < start;
+
+ if (isSimple) {
+ // Check/do normalizations that weren't detected by the scanner.
+ // This includes removal of empty port or userInfo,
+ // or scheme specific port and path normalizations.
+ if (hostStart > schemeEnd + 3) {
+ // Always be non-simple if URI contains user-info.
+ // The scanner doesn't set the not-simple position in this case because
+ // it's setting the host-start position instead.
+ isSimple = false;
+ } else if (portStart > start && portStart + 1 == pathStart) {
+ // If the port is empty, it should be omitted.
+ // Pathological case, don't bother correcting it.
+ isSimple = false;
+ } else if (queryStart < end &&
+ (queryStart == pathStart + 2 &&
+ uri.startsWith("..", pathStart)) ||
+ (queryStart > pathStart + 2 &&
+ uri.startsWith("/..", queryStart - 3))) {
+ // The path ends in a ".." segment. This should be normalized to "../".
+ // We didn't detect this while scanning because a query or fragment was
+ // detected at the same time (which is why we only need to check this
+ // if there is something after the path).
+ isSimple = false;
+ } else {
+ // There are a few scheme-based normalizations that
+ // the scanner couldn't check.
+ // That means that the input is very close to simple, so just do
+ // the normalizations.
+ if (schemeEnd == start + 4) {
+ // Do scheme based normalizations for file, http.
+ if (uri.startsWith("file", start)) {
+ scheme = "file";
+ if (hostStart <= start) {
+ // File URIs should have an authority.
+ // Paths after an authority should be absolute.
+ String schemeAuth = "file://";
+ int delta = 2;
+ if (!uri.startsWith("/", pathStart)) {
+ schemeAuth = "file:///";
+ delta = 3;
+ }
+ uri = schemeAuth + uri.substring(pathStart, end);
+ schemeEnd -= start;
+ hostStart = 7;
+ portStart = 7;
+ pathStart = 7;
+ queryStart += delta - start;
+ fragmentStart += delta - start;
+ start = 0;
+ end = uri.length;
+ } else if (pathStart == queryStart) {
+ // Uri has authority and empty path. Add "/" as path.
+ if (start == 0 && end == uri.length) {
+ uri = uri.replaceRange(pathStart, queryStart, "/");
+ queryStart += 1;
+ fragmentStart += 1;
+ end += 1;
+ } else {
+ uri = "${uri.substring(start, pathStart)}/"
+ "${uri.substring(queryStart, end)}";
+ schemeEnd -= start;
+ hostStart -= start;
+ portStart -= start;
+ pathStart -= start;
+ queryStart += 1 - start;
+ fragmentStart += 1 - start;
+ start = 0;
+ end = uri.length;
+ }
+ }
+ } else if (uri.startsWith("http", start)) {
+ scheme = "http";
+ // HTTP URIs should not have an explicit port of 80.
+ if (portStart > start &&
+ portStart + 3 == pathStart &&
+ uri.startsWith("80", portStart + 1)) {
+ if (start == 0 && end == uri.length) {
+ uri = uri.replaceRange(portStart, pathStart, "");
+ pathStart -= 3;
+ queryStart -= 3;
+ fragmentStart -= 3;
+ end -= 3;
+ } else {
+ uri = uri.substring(start, portStart) +
+ uri.substring(pathStart, end);
+ schemeEnd -= start;
+ hostStart -= start;
+ portStart -= start;
+ pathStart -= 3 + start;
+ queryStart -= 3 + start;
+ fragmentStart -= 3 + start;
+ start = 0;
+ end = uri.length;
+ }
+ }
+ }
+ } else if (schemeEnd == start + 5 && uri.startsWith("https", start)) {
+ scheme = "https";
+ // HTTPS URIs should not have an explicit port of 443.
+ if (portStart > start &&
+ portStart + 4 == pathStart &&
+ uri.startsWith("443", portStart + 1)) {
+ if (start == 0 && end == uri.length) {
+ uri = uri.replaceRange(portStart, pathStart, "");
+ pathStart -= 4;
+ queryStart -= 4;
+ fragmentStart -= 4;
+ end -= 3;
+ } else {
+ uri = uri.substring(start, portStart) +
+ uri.substring(pathStart, end);
+ schemeEnd -= start;
+ hostStart -= start;
+ portStart -= start;
+ pathStart -= 4 + start;
+ queryStart -= 4 + start;
+ fragmentStart -= 4 + start;
+ start = 0;
+ end = uri.length;
+ }
+ }
+ }
+ }
+ }
+
+ if (isSimple) {
+ if (start > 0 || end < uri.length) {
+ uri = uri.substring(start, end);
+ schemeEnd -= start;
+ hostStart -= start;
+ portStart -= start;
+ pathStart -= start;
+ queryStart -= start;
+ fragmentStart -= start;
+ }
+ return _SimpleUri(uri, schemeEnd, hostStart, portStart, pathStart,
+ queryStart, fragmentStart, scheme);
+ }
+
+ return _Uri.notSimple(uri, start, end, schemeEnd, hostStart, portStart,
+ pathStart, queryStart, fragmentStart, scheme);
+ }
+
+ /**
+ * Creates a new `Uri` object by parsing a URI string.
+ *
+ * If [start] and [end] are provided, they must specify a valid substring
+ * of [uri], and only the substring from `start` to `end` is parsed as a URI.
+ * The [uri] must not be `null`.
+ *
+ * Returns `null` if the [uri] string is not valid as a URI or URI reference.
+ */
+ static Uri tryParse(String uri, [int start = 0, int end]) {
+ // TODO: Optimize to avoid throwing-and-recatching.
+ try {
+ return parse(uri, start, end);
+ } on FormatException {
+ return null;
+ }
+ }
+
+ /**
+ * Encode the string [component] using percent-encoding to make it
+ * safe for literal use as a URI component.
+ *
+ * All characters except uppercase and lowercase letters, digits and
+ * the characters `-_.!~*'()` are percent-encoded. This is the
+ * set of characters specified in RFC 2396 and the which is
+ * specified for the encodeUriComponent in ECMA-262 version 5.1.
+ *
+ * When manually encoding path segments or query components remember
+ * to encode each part separately before building the path or query
+ * string.
+ *
+ * For encoding the query part consider using
+ * [encodeQueryComponent].
+ *
+ * To avoid the need for explicitly encoding use the [pathSegments]
+ * and [queryParameters] optional named arguments when constructing
+ * a [Uri].
+ */
+ static String encodeComponent(String component) {
+ return _Uri._uriEncode(_Uri._unreserved2396Table, component, utf8, false);
+ }
+
+ /**
+ * Encode the string [component] according to the HTML 4.01 rules
+ * for encoding the posting of a HTML form as a query string
+ * component.
+ *
+ * Encode the string [component] according to the HTML 4.01 rules
+ * for encoding the posting of a HTML form as a query string
+ * component.
+
+ * The component is first encoded to bytes using [encoding].
+ * The default is to use [utf8] encoding, which preserves all
+ * the characters that don't need encoding.
+
+ * Then the resulting bytes are "percent-encoded". This transforms
+ * spaces (U+0020) to a plus sign ('+') and all bytes that are not
+ * the ASCII decimal digits, letters or one of '-._~' are written as
+ * a percent sign '%' followed by the two-digit hexadecimal
+ * representation of the byte.
+
+ * Note that the set of characters which are percent-encoded is a
+ * superset of what HTML 4.01 requires, since it refers to RFC 1738
+ * for reserved characters.
+ *
+ * When manually encoding query components remember to encode each
+ * part separately before building the query string.
+ *
+ * To avoid the need for explicitly encoding the query use the
+ * [queryParameters] optional named arguments when constructing a
+ * [Uri].
+ *
+ * See http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 for more
+ * details.
+ */
+ static String encodeQueryComponent(String component,
+ {Encoding encoding = utf8}) {
+ return _Uri._uriEncode(_Uri._unreservedTable, component, encoding, true);
+ }
+
+ /**
+ * Decodes the percent-encoding in [encodedComponent].
+ *
+ * Note that decoding a URI component might change its meaning as
+ * some of the decoded characters could be characters with are
+ * delimiters for a given URI component type. Always split a URI
+ * component using the delimiters for the component before decoding
+ * the individual parts.
+ *
+ * For handling the [path] and [query] components consider using
+ * [pathSegments] and [queryParameters] to get the separated and
+ * decoded component.
+ */
+ static String decodeComponent(String encodedComponent) {
+ return _Uri._uriDecode(
+ encodedComponent, 0, encodedComponent.length, utf8, false);
+ }
+
+ /**
+ * Decodes the percent-encoding in [encodedComponent], converting
+ * pluses to spaces.
+ *
+ * It will create a byte-list of the decoded characters, and then use
+ * [encoding] to decode the byte-list to a String. The default encoding is
+ * UTF-8.
+ */
+ static String decodeQueryComponent(String encodedComponent,
+ {Encoding encoding = utf8}) {
+ return _Uri._uriDecode(
+ encodedComponent, 0, encodedComponent.length, encoding, true);
+ }
+
+ /**
+ * Encode the string [uri] using percent-encoding to make it
+ * safe for literal use as a full URI.
+ *
+ * All characters except uppercase and lowercase letters, digits and
+ * the characters `!#$&'()*+,-./:;=?@_~` are percent-encoded. This
+ * is the set of characters specified in in ECMA-262 version 5.1 for
+ * the encodeURI function .
+ */
+ static String encodeFull(String uri) {
+ return _Uri._uriEncode(_Uri._encodeFullTable, uri, utf8, false);
+ }
+
+ /**
+ * Decodes the percent-encoding in [uri].
+ *
+ * Note that decoding a full URI might change its meaning as some of
+ * the decoded characters could be reserved characters. In most
+ * cases an encoded URI should be parsed into components using
+ * [Uri.parse] before decoding the separate components.
+ */
+ static String decodeFull(String uri) {
+ return _Uri._uriDecode(uri, 0, uri.length, utf8, false);
+ }
+
+ /**
+ * Returns the [query] split into a map according to the rules
+ * specified for FORM post in the [HTML 4.01 specification section
+ * 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
+ * Each key and value in the returned map has been decoded. If the [query]
+ * is the empty string an empty map is returned.
+ *
+ * Keys in the query string that have no value are mapped to the
+ * empty string.
+ *
+ * Each query component will be decoded using [encoding]. The default encoding
+ * is UTF-8.
+ */
+ static Map<String, String> splitQueryString(String query,
+ {Encoding encoding = utf8}) {
+ return query.split("&").fold({}, (map, element) {
+ int index = element.indexOf("=");
+ if (index == -1) {
+ if (element != "") {
+ map[decodeQueryComponent(element, encoding: encoding)] = "";
+ }
+ } else if (index != 0) {
+ var key = element.substring(0, index);
+ var value = element.substring(index + 1);
+ map[decodeQueryComponent(key, encoding: encoding)] =
+ decodeQueryComponent(value, encoding: encoding);
+ }
+ return map;
+ });
+ }
+
+ /**
+ * Parse the [host] as an IP version 4 (IPv4) address, returning the address
+ * as a list of 4 bytes in network byte order (big endian).
+ *
+ * Throws a [FormatException] if [host] is not a valid IPv4 address
+ * representation.
+ */
+ static List<int> parseIPv4Address(String host) =>
+ _parseIPv4Address(host, 0, host.length);
+
+ /// Implementation of [parseIPv4Address] that can work on a substring.
+ static List<int> _parseIPv4Address(String host, int start, int end) {
+ void error(String msg, int position) {
+ throw FormatException('Illegal IPv4 address, $msg', host, position);
+ }
+
+ var result = Uint8List(4);
+ int partIndex = 0;
+ int partStart = start;
+ for (int i = start; i < end; i++) {
+ int char = host.codeUnitAt(i);
+ if (char != _DOT) {
+ if (char ^ 0x30 > 9) {
+ // Fail on a non-digit character.
+ error("invalid character", i);
+ }
+ } else {
+ if (partIndex == 3) {
+ error('IPv4 address should contain exactly 4 parts', i);
+ }
+ int part = int.parse(host.substring(partStart, i));
+ if (part > 255) {
+ error("each part must be in the range 0..255", partStart);
+ }
+ result[partIndex++] = part;
+ partStart = i + 1;
+ }
+ }
+
+ if (partIndex != 3) {
+ error('IPv4 address should contain exactly 4 parts', end);
+ }
+
+ int part = int.parse(host.substring(partStart, end));
+ if (part > 255) {
+ error("each part must be in the range 0..255", partStart);
+ }
+ result[partIndex] = part;
+
+ return result;
+ }
+
+ /**
+ * Parse the [host] as an IP version 6 (IPv6) address, returning the address
+ * as a list of 16 bytes in network byte order (big endian).
+ *
+ * Throws a [FormatException] if [host] is not a valid IPv6 address
+ * representation.
+ *
+ * Acts on the substring from [start] to [end]. If [end] is omitted, it
+ * defaults ot the end of the string.
+ *
+ * Some examples of IPv6 addresses:
+ * * `::1`
+ * * `FEDC:BA98:7654:3210:FEDC:BA98:7654:3210`
+ * * `3ffe:2a00:100:7031::1`
+ * * `::FFFF:129.144.52.38`
+ * * `2010:836B:4179::836B:4179`
+ */
+ static List<int> parseIPv6Address(String host, [int start = 0, int end]) {
+ end ??= host.length;
+ // An IPv6 address consists of exactly 8 parts of 1-4 hex digits, separated
+ // by `:`'s, with the following exceptions:
+ //
+ // - One (and only one) wildcard (`::`) may be present, representing a fill
+ // of 0's. The IPv6 `::` is thus 16 bytes of `0`.
+ // - The last two parts may be replaced by an IPv4 "dotted-quad" address.
+
+ // Helper function for reporting a badly formatted IPv6 address.
+ void error(String msg, [position]) {
+ throw FormatException('Illegal IPv6 address, $msg', host, position);
+ }
+
+ // Parse a hex block.
+ int parseHex(int start, int end) {
+ if (end - start > 4) {
+ error('an IPv6 part can only contain a maximum of 4 hex digits', start);
+ }
+ int value = int.parse(host.substring(start, end), radix: 16);
+ if (value < 0 || value > 0xFFFF) {
+ error('each part must be in the range of `0x0..0xFFFF`', start);
+ }
+ return value;
+ }
+
+ if (host.length < 2) error('address is too short');
+ List<int> parts = [];
+ bool wildcardSeen = false;
+ // Set if seeing a ".", suggesting that there is an IPv4 address.
+ bool seenDot = false;
+ int partStart = start;
+ // Parse all parts, except a potential last one.
+ for (int i = start; i < end; i++) {
+ int char = host.codeUnitAt(i);
+ if (char == _COLON) {
+ if (i == start) {
+ // If we see a `:` in the beginning, expect wildcard.
+ i++;
+ if (host.codeUnitAt(i) != _COLON) {
+ error('invalid start colon.', i);
+ }
+ partStart = i;
+ }
+ if (i == partStart) {
+ // Wildcard. We only allow one.
+ if (wildcardSeen) {
+ error('only one wildcard `::` is allowed', i);
+ }
+ wildcardSeen = true;
+ parts.add(-1);
+ } else {
+ // Found a single colon. Parse [partStart..i] as a hex entry.
+ parts.add(parseHex(partStart, i));
+ }
+ partStart = i + 1;
+ } else if (char == _DOT) {
+ seenDot = true;
+ }
+ }
+ if (parts.length == 0) error('too few parts');
+ bool atEnd = (partStart == end);
+ bool isLastWildcard = (parts.last == -1);
+ if (atEnd && !isLastWildcard) {
+ error('expected a part after last `:`', end);
+ }
+ if (!atEnd) {
+ if (!seenDot) {
+ parts.add(parseHex(partStart, end));
+ } else {
+ List<int> last = _parseIPv4Address(host, partStart, end);
+ parts.add(last[0] << 8 | last[1]);
+ parts.add(last[2] << 8 | last[3]);
+ }
+ }
+ if (wildcardSeen) {
+ if (parts.length > 7) {
+ error('an address with a wildcard must have less than 7 parts');
+ }
+ } else if (parts.length != 8) {
+ error('an address without a wildcard must contain exactly 8 parts');
+ }
+ List<int> bytes = Uint8List(16);
+ for (int i = 0, index = 0; i < parts.length; i++) {
+ int value = parts[i];
+ if (value == -1) {
+ int wildCardLength = 9 - parts.length;
+ for (int j = 0; j < wildCardLength; j++) {
+ bytes[index] = 0;
+ bytes[index + 1] = 0;
+ index += 2;
+ }
+ } else {
+ bytes[index] = value >> 8;
+ bytes[index + 1] = value & 0xff;
+ index += 2;
+ }
+ }
+ return bytes;
+ }
+}
+
+class _Uri implements Uri {
+ // We represent the missing scheme as an empty string.
+ // A valid scheme cannot be empty.
+ final String scheme;
+
+ /**
+ * The user-info part of the authority.
+ *
+ * Does not distinguish between an empty user-info and an absent one.
+ * The value is always non-null.
+ * Is considered absent if [_host] is `null`.
+ */
+ final String _userInfo;
+
+ /**
+ * The host name of the URI.
+ *
+ * Set to `null` if there is no authority in the URI.
+ * The host name is the only mandatory part of an authority, so we use
+ * it to mark whether an authority part was present or not.
+ */
+ final String _host;
+
+ /**
+ * The port number part of the authority.
+ *
+ * The port. Set to null if there is no port. Normalized to null if
+ * the port is the default port for the scheme.
+ */
+ int _port;
+
+ /**
+ * The path of the URI.
+ *
+ * Always non-null.
+ */
+ final String path;
+
+ // The query content, or null if there is no query.
+ final String _query;
+
+ // The fragment content, or null if there is no fragment.
+ final String _fragment;
+
+ /**
+ * Cache the computed return value of [pathSegments].
+ */
+ List<String> _pathSegments;
+
+ /**
+ * Cache of the full normalized text representation of the URI.
+ */
+ String _text;
+
+ /**
+ * Cache of the hashCode of [_text].
+ *
+ * Is null until computed.
+ */
+ int _hashCodeCache;
+
+ /**
+ * Cache the computed return value of [queryParameters].
+ */
+ Map<String, String> _queryParameters;
+ Map<String, List<String>> _queryParameterLists;
+
+ /// Internal non-verifying constructor. Only call with validated arguments.
+ ///
+ /// The components must be properly normalized.
+ ///
+ /// Use `null` for [_host] if there is no authority. In that case, always
+ /// pass `null` for [_port] and [_userInfo] as well.
+ ///
+ /// Use `null` for [_port], [_userInfo], [_query] and [_fragment] if there is
+ /// component of that type.
+ ///
+ /// The [path] and [scheme] are never empty.
+ _Uri._internal(this.scheme, this._userInfo, this._host, this._port, this.path,
+ this._query, this._fragment);
+
+ /// Create a [_Uri] from parts of [uri].
+ ///
+ /// The parameters specify the start/end of particular components of the URI.
+ /// The [scheme] may contain a string representing a normalized scheme
+ /// component if one has already been discovered.
+ factory _Uri.notSimple(
+ String uri,
+ int start,
+ int end,
+ int schemeEnd,
+ int hostStart,
+ int portStart,
+ int pathStart,
+ int queryStart,
+ int fragmentStart,
+ String scheme) {
+ if (scheme == null) {
+ scheme = "";
+ if (schemeEnd > start) {
+ scheme = _makeScheme(uri, start, schemeEnd);
+ } else if (schemeEnd == start) {
+ _fail(uri, start, "Invalid empty scheme");
+ }
+ }
+ String userInfo = "";
+ String host;
+ int port;
+ if (hostStart > start) {
+ int userInfoStart = schemeEnd + 3;
+ if (userInfoStart < hostStart) {
+ userInfo = _makeUserInfo(uri, userInfoStart, hostStart - 1);
+ }
+ host = _makeHost(uri, hostStart, portStart, false);
+ if (portStart + 1 < pathStart) {
+ // Should throw because invalid.
+ port = int.parse(uri.substring(portStart + 1, pathStart), onError: (_) {
+ throw FormatException("Invalid port", uri, portStart + 1);
+ });
+ port = _makePort(port, scheme);
+ }
+ }
+ String path =
+ _makePath(uri, pathStart, queryStart, null, scheme, host != null);
+ String query;
+ if (queryStart < fragmentStart) {
+ query = _makeQuery(uri, queryStart + 1, fragmentStart, null);
+ }
+ String fragment;
+ if (fragmentStart < end) {
+ fragment = _makeFragment(uri, fragmentStart + 1, end);
+ }
+ return _Uri._internal(scheme, userInfo, host, port, path, query, fragment);
+ }
+
+ /// Implementation of [Uri.Uri].
+ factory _Uri(
+ {String scheme,
+ String userInfo,
+ String host,
+ int port,
+ String path,
+ Iterable<String> pathSegments,
+ String query,
+ Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
+ String fragment}) {
+ scheme = _makeScheme(scheme, 0, _stringOrNullLength(scheme));
+ userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo));
+ host = _makeHost(host, 0, _stringOrNullLength(host), false);
+ // Special case this constructor for backwards compatibility.
+ if (query == "") query = null;
+ query = _makeQuery(query, 0, _stringOrNullLength(query), queryParameters);
+ fragment = _makeFragment(fragment, 0, _stringOrNullLength(fragment));
+ port = _makePort(port, scheme);
+ bool isFile = (scheme == "file");
+ if (host == null && (userInfo.isNotEmpty || port != null || isFile)) {
+ host = "";
+ }
+ bool hasAuthority = (host != null);
+ path = _makePath(
+ path, 0, _stringOrNullLength(path), pathSegments, scheme, hasAuthority);
+ if (scheme.isEmpty && host == null && !path.startsWith('/')) {
+ bool allowScheme = scheme.isNotEmpty || host != null;
+ path = _normalizeRelativePath(path, allowScheme);
+ } else {
+ path = _removeDotSegments(path);
+ }
+ if (host == null && path.startsWith("//")) {
+ host = "";
+ }
+ return _Uri._internal(scheme, userInfo, host, port, path, query, fragment);
+ }
+
+ /// Implementation of [Uri.http].
+ factory _Uri.http(String authority, String unencodedPath,
+ [Map<String, String> queryParameters]) {
+ return _makeHttpUri("http", authority, unencodedPath, queryParameters);
+ }
+
+ /// Implementation of [Uri.https].
+ factory _Uri.https(String authority, String unencodedPath,
+ [Map<String, String> queryParameters]) {
+ return _makeHttpUri("https", authority, unencodedPath, queryParameters);
+ }
+
+ String get authority {
+ if (!hasAuthority) return "";
+ var sb = StringBuffer();
+ _writeAuthority(sb);
+ return sb.toString();
+ }
+
+ String get userInfo => _userInfo;
+
+ String get host {
+ if (_host == null) return "";
+ if (_host.startsWith('[')) {
+ return _host.substring(1, _host.length - 1);
+ }
+ return _host;
+ }
+
+ int get port {
+ if (_port == null) return _defaultPort(scheme);
+ return _port;
+ }
+
+ // The default port for the scheme of this Uri.
+ static int _defaultPort(String scheme) {
+ if (scheme == "http") return 80;
+ if (scheme == "https") return 443;
+ return 0;
+ }
+
+ String get query => _query ?? "";
+
+ String get fragment => _fragment ?? "";
+
+ bool isScheme(String scheme) {
+ String thisScheme = this.scheme;
+ if (scheme == null) return thisScheme.isEmpty;
+ if (scheme.length != thisScheme.length) return false;
+ return _compareScheme(scheme, thisScheme);
+ }
+
+ /// Compares scheme characters in [scheme] and at the start of [uri].
+ ///
+ /// Returns `true` if [scheme] represents the same scheme as the start of
+ /// [uri]. That means having the same characters, but possibly different case
+ /// for letters.
+ ///
+ /// This function doesn't check that the characters are valid URI scheme
+ /// characters. The [uri] is assumed to be valid, so if [scheme] matches
+ /// it, it has to be valid too.
+ ///
+ /// The length should be tested before calling this function,
+ /// so the scheme part of [uri] is known to have the same length as [scheme].
+ static bool _compareScheme(String scheme, String uri) {
+ for (int i = 0; i < scheme.length; i++) {
+ int schemeChar = scheme.codeUnitAt(i);
+ int uriChar = uri.codeUnitAt(i);
+ int delta = schemeChar ^ uriChar;
+ if (delta != 0) {
+ if (delta == 0x20) {
+ // Might be a case difference.
+ int lowerChar = uriChar | delta;
+ if (0x61 /*a*/ <= lowerChar && lowerChar <= 0x7a /*z*/) {
+ continue;
+ }
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Report a parse failure.
+ static void _fail(String uri, int index, String message) {
+ throw FormatException(message, uri, index);
+ }
+
+ static Uri _makeHttpUri(String scheme, String authority, String unencodedPath,
+ Map<String, String> queryParameters) {
+ var userInfo = "";
+ String host;
+ int port;
+
+ if (authority != null && authority.isNotEmpty) {
+ var hostStart = 0;
+ // Split off the user info.
+ bool hasUserInfo = false;
+ for (int i = 0; i < authority.length; i++) {
+ const int atSign = 0x40;
+ if (authority.codeUnitAt(i) == atSign) {
+ hasUserInfo = true;
+ userInfo = authority.substring(0, i);
+ hostStart = i + 1;
+ break;
+ }
+ }
+ var hostEnd = hostStart;
+ if (hostStart < authority.length &&
+ authority.codeUnitAt(hostStart) == _LEFT_BRACKET) {
+ // IPv6 host.
+ int escapeForZoneID = -1;
+ for (; hostEnd < authority.length; hostEnd++) {
+ int char = authority.codeUnitAt(hostEnd);
+ if (char == _PERCENT && escapeForZoneID < 0) {
+ escapeForZoneID = hostEnd;
+ if (authority.startsWith("25", hostEnd + 1)) {
+ hostEnd += 2; // Might as well skip the already checked escape.
+ }
+ } else if (char == _RIGHT_BRACKET) {
+ break;
+ }
+ }
+ if (hostEnd == authority.length) {
+ throw FormatException(
+ "Invalid IPv6 host entry.", authority, hostStart);
+ }
+ Uri.parseIPv6Address(authority, hostStart + 1,
+ (escapeForZoneID < 0) ? hostEnd : escapeForZoneID);
+ hostEnd++; // Skip the closing bracket.
+ if (hostEnd != authority.length &&
+ authority.codeUnitAt(hostEnd) != _COLON) {
+ throw FormatException("Invalid end of authority", authority, hostEnd);
+ }
+ }
+ // Split host and port.
+ bool hasPort = false;
+ for (; hostEnd < authority.length; hostEnd++) {
+ if (authority.codeUnitAt(hostEnd) == _COLON) {
+ var portString = authority.substring(hostEnd + 1);
+ // We allow the empty port - falling back to initial value.
+ if (portString.isNotEmpty) port = int.parse(portString);
+ break;
+ }
+ }
+ host = authority.substring(hostStart, hostEnd);
+ }
+ return Uri(
+ scheme: scheme,
+ userInfo: userInfo,
+ host: host,
+ port: port,
+ pathSegments: unencodedPath.split("/"),
+ queryParameters: queryParameters);
+ }
+
+ /// Implementation of [Uri.file].
+ factory _Uri.file(String path, {bool windows}) {
+ windows = (windows == null) ? _Uri._isWindows : windows;
+ return windows
+ ? _makeWindowsFileUrl(path, false)
+ : _makeFileUri(path, false);
+ }
+
+ /// Implementation of [Uri.directory].
+ factory _Uri.directory(String path, {bool windows}) {
+ windows = (windows == null) ? _Uri._isWindows : windows;
+ return windows ? _makeWindowsFileUrl(path, true) : _makeFileUri(path, true);
+ }
+
+ /// Used internally in path-related constructors.
+ external static bool get _isWindows;
+
+ static _checkNonWindowsPathReservedCharacters(
+ List<String> segments, bool argumentError) {
+ segments.forEach((segment) {
+ if (segment.contains("/")) {
+ if (argumentError) {
+ throw ArgumentError("Illegal path character $segment");
+ } else {
+ throw UnsupportedError("Illegal path character $segment");
+ }
+ }
+ });
+ }
+
+ static _checkWindowsPathReservedCharacters(
+ List<String> segments, bool argumentError,
+ [int firstSegment = 0]) {
+ for (var segment in segments.skip(firstSegment)) {
+ if (segment.contains(RegExp(r'["*/:<>?\\|]'))) {
+ if (argumentError) {
+ throw ArgumentError("Illegal character in path");
+ } else {
+ throw UnsupportedError("Illegal character in path: $segment");
+ }
+ }
+ }
+ }
+
+ static _checkWindowsDriveLetter(int charCode, bool argumentError) {
+ if ((_UPPER_CASE_A <= charCode && charCode <= _UPPER_CASE_Z) ||
+ (_LOWER_CASE_A <= charCode && charCode <= _LOWER_CASE_Z)) {
+ return;
+ }
+ if (argumentError) {
+ throw ArgumentError(
+ "Illegal drive letter " + String.fromCharCode(charCode));
+ } else {
+ throw UnsupportedError(
+ "Illegal drive letter " + String.fromCharCode(charCode));
+ }
+ }
+
+ static _makeFileUri(String path, bool slashTerminated) {
+ const String sep = "/";
+ var segments = path.split(sep);
+ if (slashTerminated && segments.isNotEmpty && segments.last.isNotEmpty) {
+ segments.add(""); // Extra separator at end.
+ }
+ if (path.startsWith(sep)) {
+ // Absolute file:// URI.
+ return Uri(scheme: "file", pathSegments: segments);
+ } else {
+ // Relative URI.
+ return Uri(pathSegments: segments);
+ }
+ }
+
+ static _makeWindowsFileUrl(String path, bool slashTerminated) {
+ if (path.startsWith(r"\\?\")) {
+ if (path.startsWith(r"UNC\", 4)) {
+ path = path.replaceRange(0, 7, r'\');
+ } else {
+ path = path.substring(4);
+ if (path.length < 3 ||
+ path.codeUnitAt(1) != _COLON ||
+ path.codeUnitAt(2) != _BACKSLASH) {
+ throw ArgumentError(
+ r"Windows paths with \\?\ prefix must be absolute");
+ }
+ }
+ } else {
+ path = path.replaceAll("/", r'\');
+ }
+ const String sep = r'\';
+ if (path.length > 1 && path.codeUnitAt(1) == _COLON) {
+ _checkWindowsDriveLetter(path.codeUnitAt(0), true);
+ if (path.length == 2 || path.codeUnitAt(2) != _BACKSLASH) {
+ throw ArgumentError("Windows paths with drive letter must be absolute");
+ }
+ // Absolute file://C:/ URI.
+ var pathSegments = path.split(sep);
+ if (slashTerminated && pathSegments.last.isNotEmpty) {
+ pathSegments.add(""); // Extra separator at end.
+ }
+ _checkWindowsPathReservedCharacters(pathSegments, true, 1);
+ return Uri(scheme: "file", pathSegments: pathSegments);
+ }
+
+ if (path.startsWith(sep)) {
+ if (path.startsWith(sep, 1)) {
+ // Absolute file:// URI with host.
+ int pathStart = path.indexOf(r'\', 2);
+ String hostPart =
+ (pathStart < 0) ? path.substring(2) : path.substring(2, pathStart);
+ String pathPart = (pathStart < 0) ? "" : path.substring(pathStart + 1);
+ var pathSegments = pathPart.split(sep);
+ _checkWindowsPathReservedCharacters(pathSegments, true);
+ if (slashTerminated && pathSegments.last.isNotEmpty) {
+ pathSegments.add(""); // Extra separator at end.
+ }
+ return Uri(scheme: "file", host: hostPart, pathSegments: pathSegments);
+ } else {
+ // Absolute file:// URI.
+ var pathSegments = path.split(sep);
+ if (slashTerminated && pathSegments.last.isNotEmpty) {
+ pathSegments.add(""); // Extra separator at end.
+ }
+ _checkWindowsPathReservedCharacters(pathSegments, true);
+ return Uri(scheme: "file", pathSegments: pathSegments);
+ }
+ } else {
+ // Relative URI.
+ var pathSegments = path.split(sep);
+ _checkWindowsPathReservedCharacters(pathSegments, true);
+ if (slashTerminated &&
+ pathSegments.isNotEmpty &&
+ pathSegments.last.isNotEmpty) {
+ pathSegments.add(""); // Extra separator at end.
+ }
+ return Uri(pathSegments: pathSegments);
+ }
+ }
+
+ Uri replace(
+ {String scheme,
+ String userInfo,
+ String host,
+ int port,
+ String path,
+ Iterable<String> pathSegments,
+ String query,
+ Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
+ String fragment}) {
+ // Set to true if the scheme has (potentially) changed.
+ // In that case, the default port may also have changed and we need
+ // to check even the existing port.
+ bool schemeChanged = false;
+ if (scheme != null) {
+ scheme = _makeScheme(scheme, 0, scheme.length);
+ schemeChanged = (scheme != this.scheme);
+ } else {
+ scheme = this.scheme;
+ }
+ bool isFile = (scheme == "file");
+ if (userInfo != null) {
+ userInfo = _makeUserInfo(userInfo, 0, userInfo.length);
+ } else {
+ userInfo = this._userInfo;
+ }
+ if (port != null) {
+ port = _makePort(port, scheme);
+ } else {
+ port = this._port;
+ if (schemeChanged) {
+ // The default port might have changed.
+ port = _makePort(port, scheme);
+ }
+ }
+ if (host != null) {
+ host = _makeHost(host, 0, host.length, false);
+ } else if (this.hasAuthority) {
+ host = this._host;
+ } else if (userInfo.isNotEmpty || port != null || isFile) {
+ host = "";
+ }
+
+ bool hasAuthority = host != null;
+ if (path != null || pathSegments != null) {
+ path = _makePath(path, 0, _stringOrNullLength(path), pathSegments, scheme,
+ hasAuthority);
+ } else {
+ path = this.path;
+ if ((isFile || (hasAuthority && !path.isEmpty)) &&
+ !path.startsWith('/')) {
+ path = "/" + path;
+ }
+ }
+
+ if (query != null || queryParameters != null) {
+ query = _makeQuery(query, 0, _stringOrNullLength(query), queryParameters);
+ } else {
+ query = this._query;
+ }
+
+ if (fragment != null) {
+ fragment = _makeFragment(fragment, 0, fragment.length);
+ } else {
+ fragment = this._fragment;
+ }
+
+ return _Uri._internal(scheme, userInfo, host, port, path, query, fragment);
+ }
+
+ Uri removeFragment() {
+ if (!this.hasFragment) return this;
+ return _Uri._internal(scheme, _userInfo, _host, _port, path, _query, null);
+ }
+
+ List<String> get pathSegments {
+ var result = _pathSegments;
+ if (result != null) return result;
+
+ var pathToSplit = path;
+ if (pathToSplit.isNotEmpty && pathToSplit.codeUnitAt(0) == _SLASH) {
+ pathToSplit = pathToSplit.substring(1);
+ }
+ result = (pathToSplit == "")
+ ? const <String>[]
+ : List<String>.unmodifiable(
+ pathToSplit.split("/").map(Uri.decodeComponent));
+ _pathSegments = result;
+ return result;
+ }
+
+ Map<String, String> get queryParameters {
+ _queryParameters ??=
+ UnmodifiableMapView<String, String>(Uri.splitQueryString(query));
+ return _queryParameters;
+ }
+
+ Map<String, List<String>> get queryParametersAll {
+ if (_queryParameterLists == null) {
+ Map queryParameterLists = _splitQueryStringAll(query);
+ for (var key in queryParameterLists.keys) {
+ queryParameterLists[key] =
+ List<String>.unmodifiable(queryParameterLists[key]);
+ }
+ _queryParameterLists =
+ Map<String, List<String>>.unmodifiable(queryParameterLists);
+ }
+ return _queryParameterLists;
+ }
+
+ Uri normalizePath() {
+ String path = _normalizePath(this.path, scheme, hasAuthority);
+ if (identical(path, this.path)) return this;
+ return this.replace(path: path);
+ }
+
+ static int _makePort(int port, String scheme) {
+ // Perform scheme specific normalization.
+ if (port != null && port == _defaultPort(scheme)) return null;
+ return port;
+ }
+
+ /**
+ * Check and normalize a host name.
+ *
+ * If the host name starts and ends with '[' and ']', it is considered an
+ * IPv6 address. If [strictIPv6] is false, the address is also considered
+ * an IPv6 address if it contains any ':' character.
+ *
+ * If it is not an IPv6 address, it is case- and escape-normalized.
+ * This escapes all characters not valid in a reg-name,
+ * and converts all non-escape upper-case letters to lower-case.
+ */
+ static String _makeHost(String host, int start, int end, bool strictIPv6) {
+ // TODO(lrn): Should we normalize IPv6 addresses according to RFC 5952?
+ if (host == null) return null;
+ if (start == end) return "";
+ // Host is an IPv6 address if it starts with '[' or contains a colon.
+ if (host.codeUnitAt(start) == _LEFT_BRACKET) {
+ if (host.codeUnitAt(end - 1) != _RIGHT_BRACKET) {
+ _fail(host, start, 'Missing end `]` to match `[` in host');
+ }
+ String zoneID = "";
+ int index = _checkZoneID(host, start + 1, end - 1);
+ if (index < end - 1) {
+ int zoneIDstart =
+ (host.startsWith("25", index + 1)) ? index + 3 : index + 1;
+ zoneID = _normalizeZoneID(host, zoneIDstart, end - 1, "%25");
+ }
+ Uri.parseIPv6Address(host, start + 1, index);
+ // RFC 5952 requires hex digits to be lower case.
+ return host.substring(start, index).toLowerCase() + zoneID + ']';
+ }
+ if (!strictIPv6) {
+ // TODO(lrn): skip if too short to be a valid IPv6 address?
+ for (int i = start; i < end; i++) {
+ if (host.codeUnitAt(i) == _COLON) {
+ String zoneID = "";
+ int index = _checkZoneID(host, start, end);
+ if (index < end) {
+ int zoneIDstart =
+ (host.startsWith("25", index + 1)) ? index + 3 : index + 1;
+ zoneID = _normalizeZoneID(host, zoneIDstart, end, "%25");
+ }
+ Uri.parseIPv6Address(host, start, index);
+ return '[${host.substring(start, index)}' + zoneID + ']';
+ }
+ }
+ }
+ return _normalizeRegName(host, start, end);
+ }
+
+ // RFC 6874 check for ZoneID
+ // Return the index of first appeared `%`.
+ static int _checkZoneID(String host, int start, int end) {
+ int index = host.indexOf('%', start);
+ index = (index >= start && index < end) ? index : end;
+ return index;
+ }
+
+ static bool _isZoneIDChar(int char) {
+ return char < 127 && (_zoneIDTable[char >> 4] & (1 << (char & 0xf))) != 0;
+ }
+
+ /**
+ * Validates and does case- and percent-encoding normalization.
+ *
+ * The same as [_normalizeOrSubstring]
+ * except this function does not convert characters to lower case.
+ * The [host] must be an RFC6874 "ZoneID".
+ * ZoneID = 1*(unreserved / pct-encoded)
+ */
+ static String _normalizeZoneID(String host, int start, int end,
+ [String prefix = '']) {
+ StringBuffer buffer;
+ if (prefix != '') {
+ buffer = StringBuffer(prefix);
+ }
+ int sectionStart = start;
+ int index = start;
+ // Whether all characters between sectionStart and index are normalized,
+ bool isNormalized = true;
+
+ while (index < end) {
+ int char = host.codeUnitAt(index);
+ if (char == _PERCENT) {
+ String replacement = _normalizeEscape(host, index, true);
+ if (replacement == null && isNormalized) {
+ index += 3;
+ continue;
+ }
+ buffer ??= StringBuffer();
+ String slice = host.substring(sectionStart, index);
+ buffer.write(slice);
+ int sourceLength = 3;
+ if (replacement == null) {
+ replacement = host.substring(index, index + 3);
+ } else if (replacement == "%") {
+ _fail(host, index, "ZoneID should not contain % anymore");
+ }
+ buffer.write(replacement);
+ index += sourceLength;
+ sectionStart = index;
+ isNormalized = true;
+ } else if (_isZoneIDChar(char)) {
+ if (isNormalized && _UPPER_CASE_A <= char && _UPPER_CASE_Z >= char) {
+ // Put initial slice in buffer and continue in non-normalized mode
+ buffer ??= StringBuffer();
+ if (sectionStart < index) {
+ buffer.write(host.substring(sectionStart, index));
+ sectionStart = index;
+ }
+ isNormalized = false;
+ }
+ index++;
+ } else {
+ int sourceLength = 1;
+ if ((char & 0xFC00) == 0xD800 && (index + 1) < end) {
+ int tail = host.codeUnitAt(index + 1);
+ if ((tail & 0xFC00) == 0xDC00) {
+ char = 0x10000 | ((char & 0x3ff) << 10) | (tail & 0x3ff);
+ sourceLength = 2;
+ }
+ }
+ buffer ??= StringBuffer();
+ String slice = host.substring(sectionStart, index);
+ buffer.write(slice);
+ buffer.write(_escapeChar(char));
+ index += sourceLength;
+ sectionStart = index;
+ }
+ }
+ if (buffer == null) return host.substring(start, end);
+ if (sectionStart < end) {
+ String slice = host.substring(sectionStart, end);
+ buffer.write(slice);
+ }
+ return buffer.toString();
+ }
+
+ static bool _isRegNameChar(int char) {
+ return char < 127 && (_regNameTable[char >> 4] & (1 << (char & 0xf))) != 0;
+ }
+
+ /**
+ * Validates and does case- and percent-encoding normalization.
+ *
+ * The [host] must be an RFC3986 "reg-name". It is converted
+ * to lower case, and percent escapes are converted to either
+ * lower case unreserved characters or upper case escapes.
+ */
+ static String _normalizeRegName(String host, int start, int end) {
+ StringBuffer buffer;
+ int sectionStart = start;
+ int index = start;
+ // Whether all characters between sectionStart and index are normalized,
+ bool isNormalized = true;
+
+ while (index < end) {
+ int char = host.codeUnitAt(index);
+ if (char == _PERCENT) {
+ // The _regNameTable contains "%", so we check that first.
+ String replacement = _normalizeEscape(host, index, true);
+ if (replacement == null && isNormalized) {
+ index += 3;
+ continue;
+ }
+ buffer ??= StringBuffer();
+ String slice = host.substring(sectionStart, index);
+ if (!isNormalized) slice = slice.toLowerCase();
+ buffer.write(slice);
+ int sourceLength = 3;
+ if (replacement == null) {
+ replacement = host.substring(index, index + 3);
+ } else if (replacement == "%") {
+ replacement = "%25";
+ sourceLength = 1;
+ }
+ buffer.write(replacement);
+ index += sourceLength;
+ sectionStart = index;
+ isNormalized = true;
+ } else if (_isRegNameChar(char)) {
+ if (isNormalized && _UPPER_CASE_A <= char && _UPPER_CASE_Z >= char) {
+ // Put initial slice in buffer and continue in non-normalized mode
+ buffer ??= StringBuffer();
+ if (sectionStart < index) {
+ buffer.write(host.substring(sectionStart, index));
+ sectionStart = index;
+ }
+ isNormalized = false;
+ }
+ index++;
+ } else if (_isGeneralDelimiter(char)) {
+ _fail(host, index, "Invalid character");
+ } else {
+ int sourceLength = 1;
+ if ((char & 0xFC00) == 0xD800 && (index + 1) < end) {
+ int tail = host.codeUnitAt(index + 1);
+ if ((tail & 0xFC00) == 0xDC00) {
+ char = 0x10000 | ((char & 0x3ff) << 10) | (tail & 0x3ff);
+ sourceLength = 2;
+ }
+ }
+ buffer ??= StringBuffer();
+ String slice = host.substring(sectionStart, index);
+ if (!isNormalized) slice = slice.toLowerCase();
+ buffer.write(slice);
+ buffer.write(_escapeChar(char));
+ index += sourceLength;
+ sectionStart = index;
+ }
+ }
+ if (buffer == null) return host.substring(start, end);
+ if (sectionStart < end) {
+ String slice = host.substring(sectionStart, end);
+ if (!isNormalized) slice = slice.toLowerCase();
+ buffer.write(slice);
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Validates scheme characters and does case-normalization.
+ *
+ * Schemes are converted to lower case. They cannot contain escapes.
+ */
+ static String _makeScheme(String scheme, int start, int end) {
+ if (start == end) return "";
+ final int firstCodeUnit = scheme.codeUnitAt(start);
+ if (!_isAlphabeticCharacter(firstCodeUnit)) {
+ _fail(scheme, start, "Scheme not starting with alphabetic character");
+ }
+ bool containsUpperCase = false;
+ for (int i = start; i < end; i++) {
+ final int codeUnit = scheme.codeUnitAt(i);
+ if (!_isSchemeCharacter(codeUnit)) {
+ _fail(scheme, i, "Illegal scheme character");
+ }
+ if (_UPPER_CASE_A <= codeUnit && codeUnit <= _UPPER_CASE_Z) {
+ containsUpperCase = true;
+ }
+ }
+ scheme = scheme.substring(start, end);
+ if (containsUpperCase) scheme = scheme.toLowerCase();
+ return _canonicalizeScheme(scheme);
+ }
+
+ // Canonicalize a few often-used scheme strings.
+ //
+ // This improves memory usage and makes comparison faster.
+ static String _canonicalizeScheme(String scheme) {
+ if (scheme == "http") return "http";
+ if (scheme == "file") return "file";
+ if (scheme == "https") return "https";
+ if (scheme == "package") return "package";
+ return scheme;
+ }
+
+ static String _makeUserInfo(String userInfo, int start, int end) {
+ if (userInfo == null) return "";
+ return _normalizeOrSubstring(userInfo, start, end, _userinfoTable);
+ }
+
+ static String _makePath(String path, int start, int end,
+ Iterable<String> pathSegments, String scheme, bool hasAuthority) {
+ bool isFile = (scheme == "file");
+ bool ensureLeadingSlash = isFile || hasAuthority;
+ if (path == null && pathSegments == null) return isFile ? "/" : "";
+ if (path != null && pathSegments != null) {
+ throw ArgumentError('Both path and pathSegments specified');
+ }
+ String result;
+ if (path != null) {
+ result = _normalizeOrSubstring(path, start, end, _pathCharOrSlashTable,
+ escapeDelimiters: true);
+ } else {
+ result = pathSegments
+ .map((s) => _uriEncode(_pathCharTable, s, utf8, false))
+ .join("/");
+ }
+ if (result.isEmpty) {
+ if (isFile) return "/";
+ } else if (ensureLeadingSlash && !result.startsWith('/')) {
+ result = "/" + result;
+ }
+ result = _normalizePath(result, scheme, hasAuthority);
+ return result;
+ }
+
+ /// Performs path normalization (remove dot segments) on a path.
+ ///
+ /// If the URI has neither scheme nor authority, it's considered a
+ /// "pure path" and normalization won't remove leading ".." segments.
+ /// Otherwise it follows the RFC 3986 "remove dot segments" algorithm.
+ static String _normalizePath(String path, String scheme, bool hasAuthority) {
+ if (scheme.isEmpty && !hasAuthority && !path.startsWith('/')) {
+ return _normalizeRelativePath(path, scheme.isNotEmpty || hasAuthority);
+ }
+ return _removeDotSegments(path);
+ }
+
+ static String _makeQuery(String query, int start, int end,
+ Map<String, dynamic /*String|Iterable<String>*/ > queryParameters) {
+ if (query != null) {
+ if (queryParameters != null) {
+ throw ArgumentError('Both query and queryParameters specified');
+ }
+ return _normalizeOrSubstring(query, start, end, _queryCharTable,
+ escapeDelimiters: true);
+ }
+ if (queryParameters == null) return null;
+
+ var result = StringBuffer();
+ var separator = "";
+
+ void writeParameter(String key, String value) {
+ result.write(separator);
+ separator = "&";
+ result.write(Uri.encodeQueryComponent(key));
+ if (value != null && value.isNotEmpty) {
+ result.write("=");
+ result.write(Uri.encodeQueryComponent(value));
+ }
+ }
+
+ queryParameters.forEach((key, value) {
+ if (value == null || value is String) {
+ writeParameter(key, value);
+ } else {
+ Iterable values = value;
+ for (String value in values) {
+ writeParameter(key, value);
+ }
+ }
+ });
+ return result.toString();
+ }
+
+ static String _makeFragment(String fragment, int start, int end) {
+ if (fragment == null) return null;
+ return _normalizeOrSubstring(fragment, start, end, _queryCharTable,
+ escapeDelimiters: true);
+ }
+
+ /**
+ * Performs RFC 3986 Percent-Encoding Normalization.
+ *
+ * Returns a replacement string that should be replace the original escape.
+ * Returns null if no replacement is necessary because the escape is
+ * not for an unreserved character and is already non-lower-case.
+ *
+ * Returns "%" if the escape is invalid (not two valid hex digits following
+ * the percent sign). The calling code should replace the percent
+ * sign with "%25", but leave the following two characters unmodified.
+ *
+ * If [lowerCase] is true, a single character returned is always lower case,
+ */
+ static String _normalizeEscape(String source, int index, bool lowerCase) {
+ assert(source.codeUnitAt(index) == _PERCENT);
+ if (index + 2 >= source.length) {
+ return "%"; // Marks the escape as invalid.
+ }
+ int firstDigit = source.codeUnitAt(index + 1);
+ int secondDigit = source.codeUnitAt(index + 2);
+ int firstDigitValue = hexDigitValue(firstDigit);
+ int secondDigitValue = hexDigitValue(secondDigit);
+ if (firstDigitValue < 0 || secondDigitValue < 0) {
+ return "%"; // Marks the escape as invalid.
+ }
+ int value = firstDigitValue * 16 + secondDigitValue;
+ if (_isUnreservedChar(value)) {
+ if (lowerCase && _UPPER_CASE_A <= value && _UPPER_CASE_Z >= value) {
+ value |= 0x20;
+ }
+ return String.fromCharCode(value);
+ }
+ if (firstDigit >= _LOWER_CASE_A || secondDigit >= _LOWER_CASE_A) {
+ // Either digit is lower case.
+ return source.substring(index, index + 3).toUpperCase();
+ }
+ // Escape is retained, and is already non-lower case, so return null to
+ // represent "no replacement necessary".
+ return null;
+ }
+
+ static String _escapeChar(int char) {
+ assert(char <= 0x10ffff); // It's a valid unicode code point.
+ List<int> codeUnits;
+ if (char < 0x80) {
+ // ASCII, a single percent encoded sequence.
+ codeUnits = List(3);
+ codeUnits[0] = _PERCENT;
+ codeUnits[1] = _hexDigits.codeUnitAt(char >> 4);
+ codeUnits[2] = _hexDigits.codeUnitAt(char & 0xf);
+ } else {
+ // Do UTF-8 encoding of character, then percent encode bytes.
+ int flag = 0xc0; // The high-bit markers on the first byte of UTF-8.
+ int encodedBytes = 2;
+ if (char > 0x7ff) {
+ flag = 0xe0;
+ encodedBytes = 3;
+ if (char > 0xffff) {
+ encodedBytes = 4;
+ flag = 0xf0;
+ }
+ }
+ codeUnits = List(3 * encodedBytes);
+ int index = 0;
+ while (--encodedBytes >= 0) {
+ int byte = ((char >> (6 * encodedBytes)) & 0x3f) | flag;
+ codeUnits[index] = _PERCENT;
+ codeUnits[index + 1] = _hexDigits.codeUnitAt(byte >> 4);
+ codeUnits[index + 2] = _hexDigits.codeUnitAt(byte & 0xf);
+ index += 3;
+ flag = 0x80; // Following bytes have only high bit set.
+ }
+ }
+ return String.fromCharCodes(codeUnits);
+ }
+
+ /**
+ * Normalizes using [_normalize] or returns substring of original.
+ *
+ * If [_normalize] returns `null` (original content is already normalized),
+ * this methods returns the substring if [component] from [start] to [end].
+ */
+ static String _normalizeOrSubstring(
+ String component, int start, int end, List<int> charTable,
+ {bool escapeDelimiters = false}) {
+ return _normalize(component, start, end, charTable,
+ escapeDelimiters: escapeDelimiters) ??
+ component.substring(start, end);
+ }
+
+ /**
+ * Runs through component checking that each character is valid and
+ * normalize percent escapes.
+ *
+ * Uses [charTable] to check if a non-`%` character is allowed.
+ * Each `%` character must be followed by two hex digits.
+ * If the hex-digits are lower case letters, they are converted to
+ * upper case.
+ *
+ * Returns `null` if the original content was already normalized.
+ */
+ static String _normalize(
+ String component, int start, int end, List<int> charTable,
+ {bool escapeDelimiters = false}) {
+ StringBuffer buffer;
+ int sectionStart = start;
+ int index = start;
+ // Loop while characters are valid and escapes correct and upper-case.
+ while (index < end) {
+ int char = component.codeUnitAt(index);
+ if (char < 127 && (charTable[char >> 4] & (1 << (char & 0x0f))) != 0) {
+ index++;
+ } else {
+ String replacement;
+ int sourceLength;
+ if (char == _PERCENT) {
+ replacement = _normalizeEscape(component, index, false);
+ // Returns null if we should keep the existing escape.
+ if (replacement == null) {
+ index += 3;
+ continue;
+ }
+ // Returns "%" if we should escape the existing percent.
+ if ("%" == replacement) {
+ replacement = "%25";
+ sourceLength = 1;
+ } else {
+ sourceLength = 3;
+ }
+ } else if (!escapeDelimiters && _isGeneralDelimiter(char)) {
+ _fail(component, index, "Invalid character");
+ } else {
+ sourceLength = 1;
+ if ((char & 0xFC00) == 0xD800) {
+ // Possible lead surrogate.
+ if (index + 1 < end) {
+ int tail = component.codeUnitAt(index + 1);
+ if ((tail & 0xFC00) == 0xDC00) {
+ // Tail surrogate.
+ sourceLength = 2;
+ char = 0x10000 | ((char & 0x3ff) << 10) | (tail & 0x3ff);
+ }
+ }
+ }
+ replacement = _escapeChar(char);
+ }
+ buffer ??= StringBuffer();
+ buffer.write(component.substring(sectionStart, index));
+ buffer.write(replacement);
+ index += sourceLength;
+ sectionStart = index;
+ }
+ }
+ if (buffer == null) {
+ return null;
+ }
+ if (sectionStart < end) {
+ buffer.write(component.substring(sectionStart, end));
+ }
+ return buffer.toString();
+ }
+
+ static bool _isSchemeCharacter(int ch) {
+ return ch < 128 && ((_schemeTable[ch >> 4] & (1 << (ch & 0x0f))) != 0);
+ }
+
+ static bool _isGeneralDelimiter(int ch) {
+ return ch <= _RIGHT_BRACKET &&
+ ((_genDelimitersTable[ch >> 4] & (1 << (ch & 0x0f))) != 0);
+ }
+
+ /**
+ * Returns whether the URI is absolute.
+ */
+ bool get isAbsolute => scheme != "" && fragment == "";
+
+ String _mergePaths(String base, String reference) {
+ // Optimize for the case: absolute base, reference beginning with "../".
+ int backCount = 0;
+ int refStart = 0;
+ // Count number of "../" at beginning of reference.
+ while (reference.startsWith("../", refStart)) {
+ refStart += 3;
+ backCount++;
+ }
+
+ // Drop last segment - everything after last '/' of base.
+ int baseEnd = base.lastIndexOf('/');
+ // Drop extra segments for each leading "../" of reference.
+ while (baseEnd > 0 && backCount > 0) {
+ int newEnd = base.lastIndexOf('/', baseEnd - 1);
+ if (newEnd < 0) {
+ break;
+ }
+ int delta = baseEnd - newEnd;
+ // If we see a "." or ".." segment in base, stop here and let
+ // _removeDotSegments handle it.
+ if ((delta == 2 || delta == 3) &&
+ base.codeUnitAt(newEnd + 1) == _DOT &&
+ (delta == 2 || base.codeUnitAt(newEnd + 2) == _DOT)) {
+ break;
+ }
+ baseEnd = newEnd;
+ backCount--;
+ }
+ return base.replaceRange(
+ baseEnd + 1, null, reference.substring(refStart - 3 * backCount));
+ }
+
+ /// Make a guess at whether a path contains a `..` or `.` segment.
+ ///
+ /// This is a primitive test that can cause false positives.
+ /// It's only used to avoid a more expensive operation in the case where
+ /// it's not necessary.
+ static bool _mayContainDotSegments(String path) {
+ if (path.startsWith('.')) return true;
+ int index = path.indexOf("/.");
+ return index != -1;
+ }
+
+ /// Removes '.' and '..' segments from a path.
+ ///
+ /// Follows the RFC 2986 "remove dot segments" algorithm.
+ /// This algorithm is only used on paths of URIs with a scheme,
+ /// and it treats the path as if it is absolute (leading '..' are removed).
+ static String _removeDotSegments(String path) {
+ if (!_mayContainDotSegments(path)) return path;
+ assert(path.isNotEmpty); // An empty path would not have dot segments.
+ List<String> output = [];
+ bool appendSlash = false;
+ for (String segment in path.split("/")) {
+ appendSlash = false;
+ if (segment == "..") {
+ if (output.isNotEmpty) {
+ output.removeLast();
+ if (output.isEmpty) {
+ output.add("");
+ }
+ }
+ appendSlash = true;
+ } else if ("." == segment) {
+ appendSlash = true;
+ } else {
+ output.add(segment);
+ }
+ }
+ if (appendSlash) output.add("");
+ return output.join("/");
+ }
+
+ /// Removes all `.` segments and any non-leading `..` segments.
+ ///
+ /// If the path starts with something that looks like a scheme,
+ /// and [allowScheme] is false, the colon is escaped.
+ ///
+ /// Removing the ".." from a "bar/foo/.." sequence results in "bar/"
+ /// (trailing "/"). If the entire path is removed (because it contains as
+ /// many ".." segments as real segments), the result is "./".
+ /// This is different from an empty string, which represents "no path",
+ /// when you resolve it against a base URI with a path with a non-empty
+ /// final segment.
+ static String _normalizeRelativePath(String path, bool allowScheme) {
+ assert(!path.startsWith('/')); // Only get called for relative paths.
+ if (!_mayContainDotSegments(path)) {
+ if (!allowScheme) path = _escapeScheme(path);
+ return path;
+ }
+ assert(path.isNotEmpty); // An empty path would not have dot segments.
+ List<String> output = [];
+ bool appendSlash = false;
+ for (String segment in path.split("/")) {
+ appendSlash = false;
+ if (".." == segment) {
+ if (!output.isEmpty && output.last != "..") {
+ output.removeLast();
+ appendSlash = true;
+ } else {
+ output.add("..");
+ }
+ } else if ("." == segment) {
+ appendSlash = true;
+ } else {
+ output.add(segment);
+ }
+ }
+ if (output.isEmpty || (output.length == 1 && output[0].isEmpty)) {
+ return "./";
+ }
+ if (appendSlash || output.last == '..') output.add("");
+ if (!allowScheme) output[0] = _escapeScheme(output[0]);
+ return output.join("/");
+ }
+
+ /// If [path] starts with a valid scheme, escape the percent.
+ static String _escapeScheme(String path) {
+ if (path.length >= 2 && _isAlphabeticCharacter(path.codeUnitAt(0))) {
+ for (int i = 1; i < path.length; i++) {
+ int char = path.codeUnitAt(i);
+ if (char == _COLON) {
+ return "${path.substring(0, i)}%3A${path.substring(i + 1)}";
+ }
+ if (char > 127 ||
+ ((_schemeTable[char >> 4] & (1 << (char & 0x0f))) == 0)) {
+ break;
+ }
+ }
+ }
+ return path;
+ }
+
+ Uri resolve(String reference) {
+ return resolveUri(Uri.parse(reference));
+ }
+
+ Uri resolveUri(Uri reference) {
+ // From RFC 3986.
+ String targetScheme;
+ String targetUserInfo = "";
+ String targetHost;
+ int targetPort;
+ String targetPath;
+ String targetQuery;
+ if (reference.scheme.isNotEmpty) {
+ targetScheme = reference.scheme;
+ if (reference.hasAuthority) {
+ targetUserInfo = reference.userInfo;
+ targetHost = reference.host;
+ targetPort = reference.hasPort ? reference.port : null;
+ }
+ targetPath = _removeDotSegments(reference.path);
+ if (reference.hasQuery) {
+ targetQuery = reference.query;
+ }
+ } else {
+ targetScheme = this.scheme;
+ if (reference.hasAuthority) {
+ targetUserInfo = reference.userInfo;
+ targetHost = reference.host;
+ targetPort =
+ _makePort(reference.hasPort ? reference.port : null, targetScheme);
+ targetPath = _removeDotSegments(reference.path);
+ if (reference.hasQuery) targetQuery = reference.query;
+ } else {
+ targetUserInfo = this._userInfo;
+ targetHost = this._host;
+ targetPort = this._port;
+ if (reference.path == "") {
+ targetPath = this.path;
+ if (reference.hasQuery) {
+ targetQuery = reference.query;
+ } else {
+ targetQuery = this._query;
+ }
+ } else {
+ if (reference.hasAbsolutePath) {
+ targetPath = _removeDotSegments(reference.path);
+ } else {
+ // This is the RFC 3986 behavior for merging.
+ if (this.hasEmptyPath) {
+ if (!this.hasAuthority) {
+ if (!this.hasScheme) {
+ // Keep the path relative if no scheme or authority.
+ targetPath = reference.path;
+ } else {
+ // Remove leading dot-segments if the path is put
+ // beneath a scheme.
+ targetPath = _removeDotSegments(reference.path);
+ }
+ } else {
+ // RFC algorithm for base with authority and empty path.
+ targetPath = _removeDotSegments("/" + reference.path);
+ }
+ } else {
+ var mergedPath = _mergePaths(this.path, reference.path);
+ if (this.hasScheme || this.hasAuthority || this.hasAbsolutePath) {
+ targetPath = _removeDotSegments(mergedPath);
+ } else {
+ // Non-RFC 3986 behavior.
+ // If both base and reference are relative paths,
+ // allow the merged path to start with "..".
+ // The RFC only specifies the case where the base has a scheme.
+ targetPath = _normalizeRelativePath(
+ mergedPath, this.hasScheme || this.hasAuthority);
+ }
+ }
+ }
+ if (reference.hasQuery) targetQuery = reference.query;
+ }
+ }
+ }
+ String fragment = reference.hasFragment ? reference.fragment : null;
+ return _Uri._internal(targetScheme, targetUserInfo, targetHost, targetPort,
+ targetPath, targetQuery, fragment);
+ }
+
+ bool get hasScheme => scheme.isNotEmpty;
+
+ bool get hasAuthority => _host != null;
+
+ bool get hasPort => _port != null;
+
+ bool get hasQuery => _query != null;
+
+ bool get hasFragment => _fragment != null;
+
+ bool get hasEmptyPath => path.isEmpty;
+
+ bool get hasAbsolutePath => path.startsWith('/');
+
+ String get origin {
+ if (scheme == "") {
+ throw StateError("Cannot use origin without a scheme: $this");
+ }
+ if (scheme != "http" && scheme != "https") {
+ throw StateError(
+ "Origin is only applicable schemes http and https: $this");
+ }
+ if (_host == null || _host == "") {
+ throw StateError(
+ "A $scheme: URI should have a non-empty host name: $this");
+ }
+ if (_port == null) return "$scheme://$_host";
+ return "$scheme://$_host:$_port";
+ }
+
+ String toFilePath({bool windows}) {
+ if (scheme != "" && scheme != "file") {
+ throw UnsupportedError("Cannot extract a file path from a $scheme URI");
+ }
+ if (query != "") {
+ throw UnsupportedError(
+ "Cannot extract a file path from a URI with a query component");
+ }
+ if (fragment != "") {
+ throw UnsupportedError(
+ "Cannot extract a file path from a URI with a fragment component");
+ }
+ windows ??= _isWindows;
+ return windows ? _toWindowsFilePath(this) : _toFilePath();
+ }
+
+ String _toFilePath() {
+ if (hasAuthority && host != "") {
+ throw UnsupportedError(
+ "Cannot extract a non-Windows file path from a file URI "
+ "with an authority");
+ }
+ // Use path segments to have any escapes unescaped.
+ var pathSegments = this.pathSegments;
+ _checkNonWindowsPathReservedCharacters(pathSegments, false);
+ var result = StringBuffer();
+ if (hasAbsolutePath) result.write("/");
+ result.writeAll(pathSegments, "/");
+ return result.toString();
+ }
+
+ static String _toWindowsFilePath(Uri uri) {
+ bool hasDriveLetter = false;
+ var segments = uri.pathSegments;
+ if (segments.length > 0 &&
+ segments[0].length == 2 &&
+ segments[0].codeUnitAt(1) == _COLON) {
+ _checkWindowsDriveLetter(segments[0].codeUnitAt(0), false);
+ _checkWindowsPathReservedCharacters(segments, false, 1);
+ hasDriveLetter = true;
+ } else {
+ _checkWindowsPathReservedCharacters(segments, false, 0);
+ }
+ var result = StringBuffer();
+ if (uri.hasAbsolutePath && !hasDriveLetter) result.write(r"\");
+ if (uri.hasAuthority) {
+ var host = uri.host;
+ if (host.isNotEmpty) {
+ result.write(r"\");
+ result.write(host);
+ result.write(r"\");
+ }
+ }
+ result.writeAll(segments, r"\");
+ if (hasDriveLetter && segments.length == 1) result.write(r"\");
+ return result.toString();
+ }
+
+ bool get _isPathAbsolute {
+ return path != null && path.startsWith('/');
+ }
+
+ void _writeAuthority(StringSink ss) {
+ if (_userInfo.isNotEmpty) {
+ ss.write(_userInfo);
+ ss.write("@");
+ }
+ if (_host != null) ss.write(_host);
+ if (_port != null) {
+ ss.write(":");
+ ss.write(_port);
+ }
+ }
+
+ /**
+ * Access the structure of a `data:` URI.
+ *
+ * Returns a [UriData] object for `data:` URIs and `null` for all other
+ * URIs.
+ * The [UriData] object can be used to access the media type and data
+ * of a `data:` URI.
+ */
+ UriData get data => (scheme == "data") ? UriData.fromUri(this) : null;
+
+ String toString() {
+ return _text ??= _initializeText();
+ }
+
+ String _initializeText() {
+ assert(_text == null);
+ StringBuffer sb = StringBuffer();
+ if (scheme.isNotEmpty) sb..write(scheme)..write(":");
+ if (hasAuthority || (scheme == "file")) {
+ // File URIS always have the authority, even if it is empty.
+ // The empty URI means "localhost".
+ sb.write("//");
+ _writeAuthority(sb);
+ }
+ sb.write(path);
+ if (_query != null) sb..write("?")..write(_query);
+ if (_fragment != null) sb..write("#")..write(_fragment);
+ return sb.toString();
+ }
+
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+ return other is Uri &&
+ scheme == other.scheme &&
+ hasAuthority == other.hasAuthority &&
+ userInfo == other.userInfo &&
+ host == other.host &&
+ port == other.port &&
+ path == other.path &&
+ hasQuery == other.hasQuery &&
+ query == other.query &&
+ hasFragment == other.hasFragment &&
+ fragment == other.fragment;
+ }
+
+ int get hashCode {
+ return _hashCodeCache ??= toString().hashCode;
+ }
+
+ static List<String> _createList() => <String>[];
+
+ static Map<String, List<String>> _splitQueryStringAll(String query,
+ {Encoding encoding = utf8}) {
+ var result = <String, List<String>>{};
+ int i = 0;
+ int start = 0;
+ int equalsIndex = -1;
+
+ void parsePair(int start, int equalsIndex, int end) {
+ String key;
+ String value;
+ if (start == end) return;
+ if (equalsIndex < 0) {
+ key = _uriDecode(query, start, end, encoding, true);
+ value = "";
+ } else {
+ key = _uriDecode(query, start, equalsIndex, encoding, true);
+ value = _uriDecode(query, equalsIndex + 1, end, encoding, true);
+ }
+ result.putIfAbsent(key, _createList).add(value);
+ }
+
+ while (i < query.length) {
+ int char = query.codeUnitAt(i);
+ if (char == _EQUALS) {
+ if (equalsIndex < 0) equalsIndex = i;
+ } else if (char == _AMPERSAND) {
+ parsePair(start, equalsIndex, i);
+ start = i + 1;
+ equalsIndex = -1;
+ }
+ i++;
+ }
+ parsePair(start, equalsIndex, i);
+ return result;
+ }
+
+ external static String _uriEncode(List<int> canonicalTable, String text,
+ Encoding encoding, bool spaceToPlus);
+
+ /**
+ * Convert a byte (2 character hex sequence) in string [s] starting
+ * at position [pos] to its ordinal value
+ */
+ static int _hexCharPairToByte(String s, int pos) {
+ int byte = 0;
+ for (int i = 0; i < 2; i++) {
+ var charCode = s.codeUnitAt(pos + i);
+ if (0x30 <= charCode && charCode <= 0x39) {
+ byte = byte * 16 + charCode - 0x30;
+ } else {
+ // Check ranges A-F (0x41-0x46) and a-f (0x61-0x66).
+ charCode |= 0x20;
+ if (0x61 <= charCode && charCode <= 0x66) {
+ byte = byte * 16 + charCode - 0x57;
+ } else {
+ throw ArgumentError("Invalid URL encoding");
+ }
+ }
+ }
+ return byte;
+ }
+
+ /**
+ * Uri-decode a percent-encoded string.
+ *
+ * It unescapes the string [text] and returns the unescaped string.
+ *
+ * This function is similar to the JavaScript-function `decodeURI`.
+ *
+ * If [plusToSpace] is `true`, plus characters will be converted to spaces.
+ *
+ * The decoder will create a byte-list of the percent-encoded parts, and then
+ * decode the byte-list using [encoding]. The default encodings UTF-8.
+ */
+ static String _uriDecode(
+ String text, int start, int end, Encoding encoding, bool plusToSpace) {
+ assert(0 <= start);
+ assert(start <= end);
+ assert(end <= text.length);
+ assert(encoding != null);
+ // First check whether there is any characters which need special handling.
+ bool simple = true;
+ for (int i = start; i < end; i++) {
+ var codeUnit = text.codeUnitAt(i);
+ if (codeUnit > 127 ||
+ codeUnit == _PERCENT ||
+ (plusToSpace && codeUnit == _PLUS)) {
+ simple = false;
+ break;
+ }
+ }
+ List<int> bytes;
+ if (simple) {
+ if (utf8 == encoding || latin1 == encoding || ascii == encoding) {
+ return text.substring(start, end);
+ } else {
+ bytes = text.substring(start, end).codeUnits;
+ }
+ } else {
+ bytes = List();
+ for (int i = start; i < end; i++) {
+ var codeUnit = text.codeUnitAt(i);
+ if (codeUnit > 127) {
+ throw ArgumentError("Illegal percent encoding in URI");
+ }
+ if (codeUnit == _PERCENT) {
+ if (i + 3 > text.length) {
+ throw ArgumentError('Truncated URI');
+ }
+ bytes.add(_hexCharPairToByte(text, i + 1));
+ i += 2;
+ } else if (plusToSpace && codeUnit == _PLUS) {
+ bytes.add(_SPACE);
+ } else {
+ bytes.add(codeUnit);
+ }
+ }
+ }
+ return encoding.decode(bytes);
+ }
+
+ static bool _isAlphabeticCharacter(int codeUnit) {
+ var lowerCase = codeUnit | 0x20;
+ return (_LOWER_CASE_A <= lowerCase && lowerCase <= _LOWER_CASE_Z);
+ }
+
+ static bool _isUnreservedChar(int char) {
+ return char < 127 &&
+ ((_unreservedTable[char >> 4] & (1 << (char & 0x0f))) != 0);
+ }
+
+ // Tables of char-codes organized as a bit vector of 128 bits where
+ // each bit indicate whether a character code on the 0-127 needs to
+ // be escaped or not.
+
+ // The unreserved characters of RFC 3986.
+ static const _unreservedTable = <int>[
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // -.
+ 0x6000, // 0x20 - 0x2f 0000000000000110
+ // 0123456789
+ 0x03ff, // 0x30 - 0x3f 1111111111000000
+ // ABCDEFGHIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 0111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff, // 0x70 - 0x7f 1111111111100010
+ ];
+
+ // The unreserved characters of RFC 2396.
+ static const _unreserved2396Table = <int>[
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! '()* -.
+ 0x6782, // 0x20 - 0x2f 0100000111100110
+ // 0123456789
+ 0x03ff, // 0x30 - 0x3f 1111111111000000
+ // ABCDEFGHIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 0111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff, // 0x70 - 0x7f 1111111111100010
+ ];
+
+ // Table of reserved characters specified by ECMAScript 5.
+ static const _encodeFullTable = <int>[
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! #$ &'()*+,-./
+ 0xffda, // 0x20 - 0x2f 0101101111111111
+ // 0123456789:; = ?
+ 0xafff, // 0x30 - 0x3f 1111111111110101
+ // @ABCDEFGHIJKLMNO
+ 0xffff, // 0x40 - 0x4f 1111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff, // 0x70 - 0x7f 1111111111100010
+ ];
+
+ // Characters allowed in the scheme.
+ static const _schemeTable = <int>[
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // + -.
+ 0x6800, // 0x20 - 0x2f 0000000000010110
+ // 0123456789
+ 0x03ff, // 0x30 - 0x3f 1111111111000000
+ // ABCDEFGHIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 0111111111111111
+ // PQRSTUVWXYZ
+ 0x07ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz
+ 0x07ff, // 0x70 - 0x7f 1111111111100010
+ ];
+
+ // Characters allowed in scheme except for upper case letters.
+ static const _schemeLowerTable = <int>[
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // + -.
+ 0x6800, // 0x20 - 0x2f 0000000000010110
+ // 0123456789
+ 0x03ff, // 0x30 - 0x3f 1111111111000000
+ //
+ 0x0000, // 0x40 - 0x4f 0111111111111111
+ //
+ 0x0000, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz
+ 0x07ff, // 0x70 - 0x7f 1111111111100010
+ ];
+
+ // Sub delimiter characters combined with unreserved as of 3986.
+ // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ // / "*" / "+" / "," / ";" / "="
+ // RFC 3986 section 2.3.
+ // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ static const _subDelimitersTable = <int>[
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! $ &'()*+,-.
+ 0x7fd2, // 0x20 - 0x2f 0100101111111110
+ // 0123456789 ; =
+ 0x2bff, // 0x30 - 0x3f 1111111111010100
+ // ABCDEFGHIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 0111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff, // 0x70 - 0x7f 1111111111100010
+ ];
+
+ // General delimiter characters, RFC 3986 section 2.2.
+ // gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+ //
+ static const _genDelimitersTable = <int>[
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // # /
+ 0x8008, // 0x20 - 0x2f 0001000000000001
+ // : ?
+ 0x8400, // 0x30 - 0x3f 0000000000100001
+ // @
+ 0x0001, // 0x40 - 0x4f 1000000000000000
+ // [ ]
+ 0x2800, // 0x50 - 0x5f 0000000000010100
+ //
+ 0x0000, // 0x60 - 0x6f 0000000000000000
+ //
+ 0x0000, // 0x70 - 0x7f 0000000000000000
+ ];
+
+ // Characters allowed in the userinfo as of RFC 3986.
+ // RFC 3986 Appendix A
+ // userinfo = *( unreserved / pct-encoded / sub-delims / ':')
+ static const _userinfoTable = <int>[
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! $ &'()*+,-.
+ 0x7fd2, // 0x20 - 0x2f 0100101111111110
+ // 0123456789:; =
+ 0x2fff, // 0x30 - 0x3f 1111111111110100
+ // ABCDEFGHIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 0111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff, // 0x70 - 0x7f 1111111111100010
+ ];
+
+ // Characters allowed in the reg-name as of RFC 3986.
+ // RFC 3986 Appendix A
+ // reg-name = *( unreserved / pct-encoded / sub-delims )
+ static const _regNameTable = <int>[
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! $%&'()*+,-.
+ 0x7ff2, // 0x20 - 0x2f 0100111111111110
+ // 0123456789 ; =
+ 0x2bff, // 0x30 - 0x3f 1111111111010100
+ // ABCDEFGHIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 0111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff, // 0x70 - 0x7f 1111111111100010
+ ];
+
+ // Characters allowed in the path as of RFC 3986.
+ // RFC 3986 section 3.3.
+ // pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ static const _pathCharTable = <int>[
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! $ &'()*+,-.
+ 0x7fd2, // 0x20 - 0x2f 0100101111111110
+ // 0123456789:; =
+ 0x2fff, // 0x30 - 0x3f 1111111111110100
+ // @ABCDEFGHIJKLMNO
+ 0xffff, // 0x40 - 0x4f 1111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff, // 0x70 - 0x7f 1111111111100010
+ ];
+
+ // Characters allowed in the path as of RFC 3986.
+ // RFC 3986 section 3.3 *and* slash.
+ static const _pathCharOrSlashTable = [
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! $ &'()*+,-./
+ 0xffd2, // 0x20 - 0x2f 0100101111111111
+ // 0123456789:; =
+ 0x2fff, // 0x30 - 0x3f 1111111111110100
+ // @ABCDEFGHIJKLMNO
+ 0xffff, // 0x40 - 0x4f 1111111111111111
+
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff, // 0x70 - 0x7f 1111111111100010
+ ];
+
+ // Characters allowed in the query as of RFC 3986.
+ // RFC 3986 section 3.4.
+ // query = *( pchar / "/" / "?" )
+ static const _queryCharTable = [
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! $ &'()*+,-./
+ 0xffd2, // 0x20 - 0x2f 0100101111111111
+ // 0123456789:; = ?
+ 0xafff, // 0x30 - 0x3f 1111111111110101
+ // @ABCDEFGHIJKLMNO
+ 0xffff, // 0x40 - 0x4f 1111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff, // 0x70 - 0x7f 1111111111100010
+ ];
+
+ // Characters allowed in the ZoneID as of RFC 6874.
+ // ZoneID = 1*( unreserved / pct-encoded )
+ static const _zoneIDTable = <int>[
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! $%&'()*+,-.
+ 0x6000, // 0x20 - 0x2f 0000000000000110
+ // 0123456789 ; =
+ 0x03ff, // 0x30 - 0x3f 1111111111000000
+ // ABCDEFGHIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 0111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff, // 0x70 - 0x7f 1111111111100010
+ ];
+}
+
+// --------------------------------------------------------------------
+// Data URI
+// --------------------------------------------------------------------
+
+/**
+ * A way to access the structure of a `data:` URI.
+ *
+ * Data URIs are non-hierarchical URIs that can contain any binary data.
+ * They are defined by [RFC 2397](https://tools.ietf.org/html/rfc2397).
+ *
+ * This class allows parsing the URI text and extracting individual parts of the
+ * URI, as well as building the URI text from structured parts.
+ */
+class UriData {
+ static const int _noScheme = -1;
+ /**
+ * Contains the text content of a `data:` URI, with or without a
+ * leading `data:`.
+ *
+ * If [_separatorIndices] starts with `4` (the index of the `:`), then
+ * there is a leading `data:`, otherwise [_separatorIndices] starts with
+ * `-1`.
+ */
+ final String _text;
+
+ /**
+ * List of the separators (';', '=' and ',') in the text.
+ *
+ * Starts with the index of the `:` in `data:` of the mimeType.
+ * That is always either -1 or 4, depending on whether `_text` includes the
+ * `data:` scheme or not.
+ *
+ * The first speparator ends the mime type. We don't bother with finding
+ * the '/' inside the mime type.
+ *
+ * Each two separators after that marks a parameter key and value.
+ *
+ * If there is a single separator left, it ends the "base64" marker.
+ *
+ * So the following separators are found for a text:
+ * ```
+ * data:text/plain;foo=bar;base64,ARGLEBARGLE=
+ * ^ ^ ^ ^ ^
+ * ```
+ */
+ final List<int> _separatorIndices;
+
+ /**
+ * Cache of the result returned by [uri].
+ */
+ Uri _uriCache;
+
+ UriData._(this._text, this._separatorIndices, this._uriCache);
+
+ // Avoid shadowing by argument.
+ static const Base64Codec _base64 = base64;
+
+ /**
+ * Creates a `data:` URI containing the [content] string.
+ *
+ * Equivalent to `new Uri.dataFromString(...).data`, but may
+ * be more efficient if the [uri] itself isn't used.
+ */
+ factory UriData.fromString(String content,
+ {String mimeType,
+ Encoding encoding,
+ Map<String, String> parameters,
+ bool base64 = false}) {
+ StringBuffer buffer = StringBuffer();
+ List<int> indices = [_noScheme];
+ String charsetName;
+ String encodingName;
+ if (parameters != null) charsetName = parameters["charset"];
+ if (encoding == null) {
+ if (charsetName != null) {
+ encoding = Encoding.getByName(charsetName);
+ }
+ } else if (charsetName == null) {
+ // Non-null only if parameters does not contain "charset".
+ encodingName = encoding.name;
+ }
+ encoding ??= ascii;
+ _writeUri(mimeType, encodingName, parameters, buffer, indices);
+ indices.add(buffer.length);
+ if (base64) {
+ buffer.write(';base64,');
+ indices.add(buffer.length - 1);
+ buffer.write(encoding.fuse(_base64).encode(content));
+ } else {
+ buffer.write(',');
+ _uriEncodeBytes(_uricTable, encoding.encode(content), buffer);
+ }
+ return UriData._(buffer.toString(), indices, null);
+ }
+
+ /**
+ * Creates a `data:` URI containing an encoding of [bytes].
+ *
+ * Equivalent to `new Uri.dataFromBytes(...).data`, but may
+ * be more efficient if the [uri] itself isn't used.
+ */
+ factory UriData.fromBytes(List<int> bytes,
+ {mimeType = "application/octet-stream",
+ Map<String, String> parameters,
+ percentEncoded = false}) {
+ StringBuffer buffer = StringBuffer();
+ List<int> indices = [_noScheme];
+ _writeUri(mimeType, null, parameters, buffer, indices);
+ indices.add(buffer.length);
+ if (percentEncoded) {
+ buffer.write(',');
+ _uriEncodeBytes(_uricTable, bytes, buffer);
+ } else {
+ buffer.write(';base64,');
+ indices.add(buffer.length - 1);
+ _base64.encoder
+ .startChunkedConversion(StringConversionSink.fromStringSink(buffer))
+ .addSlice(bytes, 0, bytes.length, true);
+ }
+
+ return UriData._(buffer.toString(), indices, null);
+ }
+
+ /**
+ * Creates a `DataUri` from a [Uri] which must have `data` as [Uri.scheme].
+ *
+ * The [uri] must have scheme `data` and no authority or fragment,
+ * and the path (concatenated with the query, if there is one) must be valid
+ * as data URI content with the same rules as [parse].
+ */
+ factory UriData.fromUri(Uri uri) {
+ if (uri.scheme != "data") {
+ throw ArgumentError.value(uri, "uri", "Scheme must be 'data'");
+ }
+ if (uri.hasAuthority) {
+ throw ArgumentError.value(uri, "uri", "Data uri must not have authority");
+ }
+ if (uri.hasFragment) {
+ throw ArgumentError.value(
+ uri, "uri", "Data uri must not have a fragment part");
+ }
+ if (!uri.hasQuery) {
+ return _parse(uri.path, 0, uri);
+ }
+ // Includes path and query (and leading "data:").
+ return _parse("$uri", 5, uri);
+ }
+
+ /**
+ * Writes the initial part of a `data:` uri, from after the "data:"
+ * until just before the ',' before the data, or before a `;base64,`
+ * marker.
+ *
+ * Of an [indices] list is passed, separator indices are stored in that
+ * list.
+ */
+ static void _writeUri(String mimeType, String charsetName,
+ Map<String, String> parameters, StringBuffer buffer, List indices) {
+ if (mimeType == null || mimeType == "text/plain") {
+ mimeType = "";
+ }
+ if (mimeType.isEmpty || identical(mimeType, "application/octet-stream")) {
+ buffer.write(mimeType); // Common cases need no escaping.
+ } else {
+ int slashIndex = _validateMimeType(mimeType);
+ if (slashIndex < 0) {
+ throw ArgumentError.value(mimeType, "mimeType", "Invalid MIME type");
+ }
+ buffer.write(_Uri._uriEncode(
+ _tokenCharTable, mimeType.substring(0, slashIndex), utf8, false));
+ buffer.write("/");
+ buffer.write(_Uri._uriEncode(
+ _tokenCharTable, mimeType.substring(slashIndex + 1), utf8, false));
+ }
+ if (charsetName != null) {
+ if (indices != null) {
+ indices..add(buffer.length)..add(buffer.length + 8);
+ }
+ buffer.write(";charset=");
+ buffer.write(_Uri._uriEncode(_tokenCharTable, charsetName, utf8, false));
+ }
+ parameters?.forEach((key, value) {
+ if (key.isEmpty) {
+ throw ArgumentError.value("", "Parameter names must not be empty");
+ }
+ if (value.isEmpty) {
+ throw ArgumentError.value(
+ "", "Parameter values must not be empty", 'parameters["$key"]');
+ }
+ if (indices != null) indices.add(buffer.length);
+ buffer.write(';');
+ // Encode any non-RFC2045-token character and both '%' and '#'.
+ buffer.write(_Uri._uriEncode(_tokenCharTable, key, utf8, false));
+ if (indices != null) indices.add(buffer.length);
+ buffer.write('=');
+ buffer.write(_Uri._uriEncode(_tokenCharTable, value, utf8, false));
+ });
+ }
+
+ /**
+ * Checks mimeType is valid-ish (`token '/' token`).
+ *
+ * Returns the index of the slash, or -1 if the mime type is not
+ * considered valid.
+ *
+ * Currently only looks for slashes, all other characters will be
+ * percent-encoded as UTF-8 if necessary.
+ */
+ static int _validateMimeType(String mimeType) {
+ int slashIndex = -1;
+ for (int i = 0; i < mimeType.length; i++) {
+ var char = mimeType.codeUnitAt(i);
+ if (char != _SLASH) continue;
+ if (slashIndex < 0) {
+ slashIndex = i;
+ continue;
+ }
+ return -1;
+ }
+ return slashIndex;
+ }
+
+ /**
+ * Parses a string as a `data` URI.
+ *
+ * The string must have the format:
+ *
+ * ```
+ * 'data:' (type '/' subtype)? (';' attribute '=' value)* (';base64')? ',' data
+ * ````
+ *
+ * where `type`, `subtype`, `attribute` and `value` are specified in RFC-2045,
+ * and `data` is a sequence of URI-characters (RFC-2396 `uric`).
+ *
+ * This means that all the characters must be ASCII, but the URI may contain
+ * percent-escapes for non-ASCII byte values that need an interpretation
+ * to be converted to the corresponding string.
+ *
+ * Parsing checks that Base64 encoded data is valid, and it normalizes it
+ * to use the default Base64 alphabet and to use padding.
+ * Non-Base64 data is escaped using percent-escapes as necessary to make
+ * it valid, and existing escapes are case normalized.
+ *
+ * Accessing the individual parts may fail later if they turn out to have
+ * content that can't be decoded successfully as a string, for example if
+ * existing percent escapes represent bytes that cannot be decoded
+ * by the chosen [Encoding] (see [contentAsString]).
+ *
+ * A [FormatException] is thrown if [uri] is not a valid data URI.
+ */
+ static UriData parse(String uri) {
+ if (uri.length >= 5) {
+ int dataDelta = _startsWithData(uri, 0);
+ if (dataDelta == 0) {
+ // Exact match on "data:".
+ return _parse(uri, 5, null);
+ }
+ if (dataDelta == 0x20) {
+ // Starts with a non-normalized "data" scheme containing upper-case
+ // letters. Parse anyway, but throw away the scheme.
+ return _parse(uri.substring(5), 0, null);
+ }
+ }
+ throw FormatException("Does not start with 'data:'", uri, 0);
+ }
+
+ /**
+ * The [Uri] that this `UriData` is giving access to.
+ *
+ * Returns a `Uri` with scheme `data` and the remainder of the data URI
+ * as path.
+ */
+ Uri get uri {
+ if (_uriCache != null) return _uriCache;
+ String path = _text;
+ String query;
+ int colonIndex = _separatorIndices[0];
+ int queryIndex = _text.indexOf('?', colonIndex + 1);
+ int end = _text.length;
+ if (queryIndex >= 0) {
+ query = _Uri._normalizeOrSubstring(
+ _text, queryIndex + 1, end, _Uri._queryCharTable);
+ end = queryIndex;
+ }
+ path = _Uri._normalizeOrSubstring(
+ _text, colonIndex + 1, end, _Uri._pathCharOrSlashTable);
+ _uriCache = _DataUri(this, path, query);
+ return _uriCache;
+ }
+
+ /**
+ * The MIME type of the data URI.
+ *
+ * A data URI consists of a "media type" followed by data.
+ * The media type starts with a MIME type and can be followed by
+ * extra parameters.
+ * If the MIME type representation in the URI text contains URI escapes,
+ * they are unescaped in the returned string.
+ * If the value contain non-ASCII percent escapes, they are decoded as UTF-8.
+ *
+ * Example:
+ *
+ * data:text/plain;charset=utf-8,Hello%20World!
+ *
+ * This data URI has the media type `text/plain;charset=utf-8`, which is the
+ * MIME type `text/plain` with the parameter `charset` with value `utf-8`.
+ * See [RFC 2045](https://tools.ietf.org/html/rfc2045) for more detail.
+ *
+ * If the first part of the data URI is empty, it defaults to `text/plain`.
+ */
+ String get mimeType {
+ int start = _separatorIndices[0] + 1;
+ int end = _separatorIndices[1];
+ if (start == end) return "text/plain";
+ return _Uri._uriDecode(_text, start, end, utf8, false);
+ }
+
+ /**
+ * The charset parameter of the media type.
+ *
+ * If the parameters of the media type contains a `charset` parameter
+ * then this returns its value, otherwise it returns `US-ASCII`,
+ * which is the default charset for data URIs.
+ * If the value contain non-ASCII percent escapes, they are decoded as UTF-8.
+ *
+ * If the MIME type representation in the URI text contains URI escapes,
+ * they are unescaped in the returned string.
+ */
+ String get charset {
+ int parameterStart = 1;
+ int parameterEnd = _separatorIndices.length - 1; // The ',' before data.
+ if (isBase64) {
+ // There is a ";base64" separator, so subtract one for that as well.
+ parameterEnd -= 1;
+ }
+ for (int i = parameterStart; i < parameterEnd; i += 2) {
+ var keyStart = _separatorIndices[i] + 1;
+ var keyEnd = _separatorIndices[i + 1];
+ if (keyEnd == keyStart + 7 && _text.startsWith("charset", keyStart)) {
+ return _Uri._uriDecode(
+ _text, keyEnd + 1, _separatorIndices[i + 2], utf8, false);
+ }
+ }
+ return "US-ASCII";
+ }
+
+ /**
+ * Whether the data is Base64 encoded or not.
+ */
+ bool get isBase64 => _separatorIndices.length.isOdd;
+
+ /**
+ * The content part of the data URI, as its actual representation.
+ *
+ * This string may contain percent escapes.
+ */
+ String get contentText => _text.substring(_separatorIndices.last + 1);
+
+ /**
+ * The content part of the data URI as bytes.
+ *
+ * If the data is Base64 encoded, it will be decoded to bytes.
+ *
+ * If the data is not Base64 encoded, it will be decoded by unescaping
+ * percent-escaped characters and returning byte values of each unescaped
+ * character. The bytes will not be, e.g., UTF-8 decoded.
+ */
+ Uint8List contentAsBytes() {
+ String text = _text;
+ int start = _separatorIndices.last + 1;
+ if (isBase64) {
+ return base64.decoder.convert(text, start);
+ }
+
+ // Not base64, do percent-decoding and return the remaining bytes.
+ // Compute result size.
+ const int percent = 0x25;
+ int length = text.length - start;
+ for (int i = start; i < text.length; i++) {
+ var codeUnit = text.codeUnitAt(i);
+ if (codeUnit == percent) {
+ i += 2;
+ length -= 2;
+ }
+ }
+ // Fill result array.
+ Uint8List result = Uint8List(length);
+ if (length == text.length) {
+ result.setRange(0, length, text.codeUnits, start);
+ return result;
+ }
+ int index = 0;
+ for (int i = start; i < text.length; i++) {
+ var codeUnit = text.codeUnitAt(i);
+ if (codeUnit != percent) {
+ result[index++] = codeUnit;
+ } else {
+ if (i + 2 < text.length) {
+ int byte = parseHexByte(text, i + 1);
+ if (byte >= 0) {
+ result[index++] = byte;
+ i += 2;
+ continue;
+ }
+ }
+ throw FormatException("Invalid percent escape", text, i);
+ }
+ }
+ assert(index == result.length);
+ return result;
+ }
+
+ /**
+ * Returns a string created from the content of the data URI.
+ *
+ * If the content is Base64 encoded, it will be decoded to bytes and then
+ * decoded to a string using [encoding].
+ * If encoding is omitted, the value of a `charset` parameter is used
+ * if it is recognized by [Encoding.getByName], otherwise it defaults to
+ * the [ascii] encoding, which is the default encoding for data URIs
+ * that do not specify an encoding.
+ *
+ * If the content is not Base64 encoded, it will first have percent-escapes
+ * converted to bytes and then the character codes and byte values are
+ * decoded using [encoding].
+ */
+ String contentAsString({Encoding encoding}) {
+ if (encoding == null) {
+ var charset = this.charset; // Returns "US-ASCII" if not present.
+ encoding = Encoding.getByName(charset);
+ if (encoding == null) {
+ throw UnsupportedError("Unknown charset: $charset");
+ }
+ }
+ String text = _text;
+ int start = _separatorIndices.last + 1;
+ if (isBase64) {
+ var converter = base64.decoder.fuse(encoding.decoder);
+ return converter.convert(text.substring(start));
+ }
+ return _Uri._uriDecode(text, start, text.length, encoding, false);
+ }
+
+ /**
+ * A map representing the parameters of the media type.
+ *
+ * A data URI may contain parameters between the MIME type and the
+ * data. This converts these parameters to a map from parameter name
+ * to parameter value.
+ * The map only contains parameters that actually occur in the URI.
+ * The `charset` parameter has a default value even if it doesn't occur
+ * in the URI, which is reflected by the [charset] getter. This means that
+ * [charset] may return a value even if `parameters["charset"]` is `null`.
+ *
+ * If the values contain non-ASCII values or percent escapes,
+ * they are decoded as UTF-8.
+ */
+ Map<String, String> get parameters {
+ var result = <String, String>{};
+ for (int i = 3; i < _separatorIndices.length; i += 2) {
+ var start = _separatorIndices[i - 2] + 1;
+ var equals = _separatorIndices[i - 1];
+ var end = _separatorIndices[i];
+ String key = _Uri._uriDecode(_text, start, equals, utf8, false);
+ String value = _Uri._uriDecode(_text, equals + 1, end, utf8, false);
+ result[key] = value;
+ }
+ return result;
+ }
+
+ static UriData _parse(String text, int start, Uri sourceUri) {
+ assert(start == 0 || start == 5);
+ assert((start == 5) == text.startsWith("data:"));
+
+ /// Character codes.
+ const int comma = 0x2c;
+ const int slash = 0x2f;
+ const int semicolon = 0x3b;
+ const int equals = 0x3d;
+ List<int> indices = [start - 1];
+ int slashIndex = -1;
+ var char;
+ int i = start;
+ for (; i < text.length; i++) {
+ char = text.codeUnitAt(i);
+ if (char == comma || char == semicolon) break;
+ if (char == slash) {
+ if (slashIndex < 0) {
+ slashIndex = i;
+ continue;
+ }
+ throw FormatException("Invalid MIME type", text, i);
+ }
+ }
+ if (slashIndex < 0 && i > start) {
+ // An empty MIME type is allowed, but if non-empty it must contain
+ // exactly one slash.
+ throw FormatException("Invalid MIME type", text, i);
+ }
+ while (char != comma) {
+ // Parse parameters and/or "base64".
+ indices.add(i);
+ i++;
+ int equalsIndex = -1;
+ for (; i < text.length; i++) {
+ char = text.codeUnitAt(i);
+ if (char == equals) {
+ if (equalsIndex < 0) equalsIndex = i;
+ } else if (char == semicolon || char == comma) {
+ break;
+ }
+ }
+ if (equalsIndex >= 0) {
+ indices.add(equalsIndex);
+ } else {
+ // Have to be final "base64".
+ var lastSeparator = indices.last;
+ if (char != comma ||
+ i != lastSeparator + 7 /* "base64,".length */ ||
+ !text.startsWith("base64", lastSeparator + 1)) {
+ throw FormatException("Expecting '='", text, i);
+ }
+ break;
+ }
+ }
+ indices.add(i);
+ bool isBase64 = indices.length.isOdd;
+ if (isBase64) {
+ text = base64.normalize(text, i + 1, text.length);
+ } else {
+ // Validate "data" part, must only contain RFC 2396 'uric' characters
+ // (reserved, unreserved, or escape sequences).
+ // Normalize to this (throws on a fragment separator).
+ var data = _Uri._normalize(text, i + 1, text.length, _uricTable,
+ escapeDelimiters: true);
+ if (data != null) {
+ text = text.replaceRange(i + 1, text.length, data);
+ }
+ }
+ return UriData._(text, indices, sourceUri);
+ }
+
+ /**
+ * Like [Uri._uriEncode] but takes the input as bytes, not a string.
+ *
+ * Encodes into [buffer] instead of creating its own buffer.
+ */
+ static void _uriEncodeBytes(
+ List<int> canonicalTable, List<int> bytes, StringSink buffer) {
+ // Encode the string into bytes then generate an ASCII only string
+ // by percent encoding selected bytes.
+ int byteOr = 0;
+ for (int i = 0; i < bytes.length; i++) {
+ int byte = bytes[i];
+ byteOr |= byte;
+ if (byte < 128 &&
+ ((canonicalTable[byte >> 4] & (1 << (byte & 0x0f))) != 0)) {
+ buffer.writeCharCode(byte);
+ } else {
+ buffer.writeCharCode(_PERCENT);
+ buffer.writeCharCode(_hexDigits.codeUnitAt(byte >> 4));
+ buffer.writeCharCode(_hexDigits.codeUnitAt(byte & 0x0f));
+ }
+ }
+ if ((byteOr & ~0xFF) != 0) {
+ for (int i = 0; i < bytes.length; i++) {
+ var byte = bytes[i];
+ if (byte < 0 || byte > 255) {
+ throw ArgumentError.value(byte, "non-byte value");
+ }
+ }
+ }
+ }
+
+ String toString() =>
+ (_separatorIndices[0] == _noScheme) ? "data:$_text" : _text;
+
+ // Table of the `token` characters of RFC 2045 in a URI.
+ //
+ // A token is any US-ASCII character except SPACE, control characters and
+ // `tspecial` characters. The `tspecial` category is:
+ // '(', ')', '<', '>', '@', ',', ';', ':', '\', '"', '/', '[, ']', '?', '='.
+ //
+ // In a data URI, we also need to escape '%' and '#' characters.
+ static const _tokenCharTable = [
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 00000000 00000000
+ 0x0000, // 0x10 - 0x1f 00000000 00000000
+ // ! $ &' *+ -.
+ 0x6cd2, // 0x20 - 0x2f 01001011 00110110
+ // 01234567 89
+ 0x03ff, // 0x30 - 0x3f 11111111 11000000
+ // ABCDEFG HIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 01111111 11111111
+ // PQRSTUVW XYZ ^_
+ 0xc7ff, // 0x50 - 0x5f 11111111 11100011
+ // `abcdefg hijklmno
+ 0xffff, // 0x60 - 0x6f 11111111 11111111
+ // pqrstuvw xyz{|}~
+ 0x7fff, // 0x70 - 0x7f 11111111 11111110
+ ];
+
+ // All non-escape RFC-2396 uric characters.
+ //
+ // uric = reserved | unreserved | escaped
+ // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
+ // unreserved = alphanum | mark
+ // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+ //
+ // This is the same characters as in a URI query (which is URI pchar plus '?')
+ static const _uricTable = _Uri._queryCharTable;
+
+ // Characters allowed in base-64 encoding (alphanumeric, '/', '+' and '=').
+ static const _base64Table = [
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 00000000 00000000
+ 0x0000, // 0x10 - 0x1f 00000000 00000000
+ // + /
+ 0x8800, // 0x20 - 0x2f 00000000 00010001
+ // 01234567 89
+ 0x03ff, // 0x30 - 0x3f 11111111 11000000
+ // ABCDEFG HIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 01111111 11111111
+ // PQRSTUVW XYZ
+ 0x07ff, // 0x50 - 0x5f 11111111 11100000
+ // abcdefg hijklmno
+ 0xfffe, // 0x60 - 0x6f 01111111 11111111
+ // pqrstuvw xyz
+ 0x07ff, // 0x70 - 0x7f 11111111 11100000
+ ];
+}
+
+// --------------------------------------------------------------------
+// Constants used to read the scanner result.
+// The indices points into the table filled by [_scan] which contains
+// recognized positions in the scanned URI.
+// The `0` index is only used internally.
+
+/// Index of the position of that `:` after a scheme.
+const int _schemeEndIndex = 1;
+
+/// Index of the position of the character just before the host name.
+const int _hostStartIndex = 2;
+
+/// Index of the position of the `:` before a port value.
+const int _portStartIndex = 3;
+
+/// Index of the position of the first character of a path.
+const int _pathStartIndex = 4;
+
+/// Index of the position of the `?` before a query.
+const int _queryStartIndex = 5;
+
+/// Index of the position of the `#` before a fragment.
+const int _fragmentStartIndex = 6;
+
+/// Index of a position where the URI was determined to be "non-simple".
+const int _notSimpleIndex = 7;
+
+// Initial state for scanner.
+const int _uriStart = 00;
+
+// If scanning of a URI terminates in this state or above,
+// consider the URI non-simple
+const int _nonSimpleEndStates = 14;
+
+// Initial state for scheme validation.
+const int _schemeStart = 20;
+
+/// Transition tables used to scan a URI to determine its structure.
+///
+/// The tables represent a state machine with output.
+///
+/// To scan the URI, start in the [_uriStart] state, then read each character
+/// of the URI in order, from start to end, and for each character perform a
+/// transition to a new state while writing the current position into the output
+/// buffer at a designated index.
+///
+/// Each state, represented by an integer which is an index into
+/// [_scannerTables], has a set of transitions, one for each character.
+/// The transitions are encoded as a 5-bit integer representing the next state
+/// and a 3-bit index into the output table.
+///
+/// For URI scanning, only characters in the range U+0020 through U+007E are
+/// interesting, all characters outside that range are treated the same.
+/// The tables only contain 96 entries, representing that characters in the
+/// interesting range, plus one more to represent all values outside the range.
+/// The character entries are stored in one `Uint8List` per state, with the
+/// transition for a character at position `character ^ 0x60`,
+/// which maps the range U+0020 .. U+007F into positions 0 .. 95.
+/// All remaining characters are mapped to position 31 (`0x7f ^ 0x60`) which
+/// represents the transition for all remaining characters.
+final List<Uint8List> _scannerTables = _createTables();
+
+// ----------------------------------------------------------------------
+// Code to create the URI scanner table.
+
+/// Creates the tables for [_scannerTables] used by [Uri.parse].
+///
+/// See [_scannerTables] for the generated format.
+///
+/// The concrete tables are chosen as a trade-off between the number of states
+/// needed and the precision of the result.
+/// This allows definitely recognizing the general structure of the URI
+/// (presence and location of scheme, user-info, host, port, path, query and
+/// fragment) while at the same time detecting that some components are not
+/// in canonical form (anything containing a `%`, a host-name containing a
+/// capital letter). Since the scanner doesn't know whether something is a
+/// scheme or a path until it sees `:`, or user-info or host until it sees
+/// a `@`, a second pass is needed to validate the scheme and any user-info
+/// is considered non-canonical by default.
+///
+/// The states (starting from [_uriStart]) write positions while scanning
+/// a string from `start` to `end` as follows:
+///
+/// - [_schemeEndIndex]: Should be initialized to `start-1`.
+/// If the URI has a scheme, it is set to the position of the `:` after
+/// the scheme.
+/// - [_hostStartIndex]: Should be initialized to `start - 1`.
+/// If the URI has an authority, it is set to the character before the
+/// host name - either the second `/` in the `//` leading the authority,
+/// or the `@` after a user-info. Comparing this value to the scheme end
+/// position can be used to detect that there is a user-info component.
+/// - [_portStartIndex]: Should be initialized to `start`.
+/// Set to the position of the last `:` in an authority, and unchanged
+/// if there is no authority or no `:` in an authority.
+/// If this position is after the host start, there is a port, otherwise it
+/// is just marking a colon in the user-info component.
+/// - [_pathStartIndex]: Should be initialized to `start`.
+/// Is set to the first path character unless the path is empty.
+/// If the path is empty, the position is either unchanged (`start`) or
+/// the first slash of an authority. So, if the path start is before a
+/// host start or scheme end, the path is empty.
+/// - [_queryStartIndex]: Should be initialized to `end`.
+/// The position of the `?` leading a query if the URI contains a query.
+/// - [_fragmentStartIndex]: Should be initialized to `end`.
+/// The position of the `#` leading a fragment if the URI contains a fragment.
+/// - [_notSimpleIndex]: Should be initialized to `start - 1`.
+/// Set to another value if the URI is considered "not simple".
+/// This is elaborated below.
+///
+/// # Simple URIs
+/// A URI is considered "simple" if it is in a normalized form containing no
+/// escapes. This allows us to skip normalization and checking whether escapes
+/// are valid, and to extract components without worrying about unescaping.
+///
+/// The scanner computes a conservative approximation of being "simple".
+/// It rejects any URI with an escape, with a user-info component (mainly
+/// because they are rare and would increase the number of states in the
+/// scanner significantly), with an IPV6 host or with a capital letter in
+/// the scheme or host name (the scheme is handled in a second scan using
+/// a separate two-state table).
+/// Further, paths containing `..` or `.` path segments are considered
+/// non-simple except for pure relative paths (no scheme or authority) starting
+/// with a sequence of "../" segments.
+///
+/// The transition tables cannot detect a trailing ".." in the path,
+/// followed by a query or fragment, because the segment is not known to be
+/// complete until we are past it, and we then need to store the query/fragment
+/// start instead. This cast is checked manually post-scanning (such a path
+/// needs to be normalized to end in "../", so the URI shouldn't be considered
+/// simple).
+List<Uint8List> _createTables() {
+ // TODO(lrn): Use a precomputed table.
+
+ // Total number of states for the scanner.
+ const int stateCount = 22;
+
+ // States used to scan a URI from scratch.
+ const int schemeOrPath = 01;
+ const int authOrPath = 02;
+ const int authOrPathSlash = 03;
+ const int uinfoOrHost0 = 04;
+ const int uinfoOrHost = 05;
+ const int uinfoOrPort0 = 06;
+ const int uinfoOrPort = 07;
+ const int ipv6Host = 08;
+ const int relPathSeg = 09;
+ const int pathSeg = 10;
+ const int path = 11;
+ const int query = 12;
+ const int fragment = 13;
+ const int schemeOrPathDot = 14;
+ const int schemeOrPathDot2 = 15;
+ const int relPathSegDot = 16;
+ const int relPathSegDot2 = 17;
+ const int pathSegDot = 18;
+ const int pathSegDot2 = 19;
+
+ // States used to validate a scheme after its end position has been found.
+ const int scheme0 = _schemeStart;
+ const int scheme = 21;
+
+ // Constants encoding the write-index for the state transition into the top 5
+ // bits of a byte.
+ const int schemeEnd = _schemeEndIndex << 5;
+ const int hostStart = _hostStartIndex << 5;
+ const int portStart = _portStartIndex << 5;
+ const int pathStart = _pathStartIndex << 5;
+ const int queryStart = _queryStartIndex << 5;
+ const int fragmentStart = _fragmentStartIndex << 5;
+ const int notSimple = _notSimpleIndex << 5;
+
+ /// The `unreserved` characters of RFC 3986.
+ const unreserved =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._~";
+
+ /// The `sub-delim` characters of RFC 3986.
+ const subDelims = r"!$&'()*+,;=";
+ // The `pchar` characters of RFC 3986: characters that may occur in a path,
+ // excluding escapes.
+ const pchar = "$unreserved$subDelims";
+
+ var tables = List<Uint8List>.generate(stateCount, (_) => Uint8List(96));
+
+ // Helper function which initialize the table for [state] with a default
+ // transition and returns the table.
+ Uint8List build(state, defaultTransition) =>
+ tables[state]..fillRange(0, 96, defaultTransition);
+
+ // Helper function which sets the transition for each character in [chars]
+ // to [transition] in the [target] table.
+ // The [chars] string must contain only characters in the U+0020 .. U+007E
+ // range.
+ void setChars(Uint8List target, String chars, int transition) {
+ for (int i = 0; i < chars.length; i++) {
+ var char = chars.codeUnitAt(i);
+ target[char ^ 0x60] = transition;
+ }
+ }
+
+ /// Helper function which sets the transition for all characters in the
+ /// range from `range[0]` to `range[1]` to [transition] in the [target] table.
+ ///
+ /// The [range] must be a two-character string where both characters are in
+ /// the U+0020 .. U+007E range and the former character must have a lower
+ /// code point than the latter.
+ void setRange(Uint8List target, String range, int transition) {
+ for (int i = range.codeUnitAt(0), n = range.codeUnitAt(1); i <= n; i++) {
+ target[i ^ 0x60] = transition;
+ }
+ }
+
+ // Create the transitions for each state.
+ var b;
+
+ // Validate as path, if it is a scheme, we handle it later.
+ b = build(_uriStart, schemeOrPath | notSimple);
+ setChars(b, pchar, schemeOrPath);
+ setChars(b, ".", schemeOrPathDot);
+ setChars(b, ":", authOrPath | schemeEnd); // Handle later.
+ setChars(b, "/", authOrPathSlash);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(schemeOrPathDot, schemeOrPath | notSimple);
+ setChars(b, pchar, schemeOrPath);
+ setChars(b, ".", schemeOrPathDot2);
+ setChars(b, ':', authOrPath | schemeEnd);
+ setChars(b, "/", pathSeg | notSimple);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(schemeOrPathDot2, schemeOrPath | notSimple);
+ setChars(b, pchar, schemeOrPath);
+ setChars(b, "%", schemeOrPath | notSimple);
+ setChars(b, ':', authOrPath | schemeEnd);
+ setChars(b, "/", relPathSeg);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(schemeOrPath, schemeOrPath | notSimple);
+ setChars(b, pchar, schemeOrPath);
+ setChars(b, ':', authOrPath | schemeEnd);
+ setChars(b, "/", pathSeg);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(authOrPath, path | notSimple);
+ setChars(b, pchar, path | pathStart);
+ setChars(b, "/", authOrPathSlash | pathStart);
+ setChars(b, ".", pathSegDot | pathStart);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(authOrPathSlash, path | notSimple);
+ setChars(b, pchar, path);
+ setChars(b, "/", uinfoOrHost0 | hostStart);
+ setChars(b, ".", pathSegDot);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(uinfoOrHost0, uinfoOrHost | notSimple);
+ setChars(b, pchar, uinfoOrHost);
+ setRange(b, "AZ", uinfoOrHost | notSimple);
+ setChars(b, ":", uinfoOrPort0 | portStart);
+ setChars(b, "@", uinfoOrHost0 | hostStart);
+ setChars(b, "[", ipv6Host | notSimple);
+ setChars(b, "/", pathSeg | pathStart);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(uinfoOrHost, uinfoOrHost | notSimple);
+ setChars(b, pchar, uinfoOrHost);
+ setRange(b, "AZ", uinfoOrHost | notSimple);
+ setChars(b, ":", uinfoOrPort0 | portStart);
+ setChars(b, "@", uinfoOrHost0 | hostStart);
+ setChars(b, "/", pathSeg | pathStart);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(uinfoOrPort0, uinfoOrPort | notSimple);
+ setRange(b, "19", uinfoOrPort);
+ setChars(b, "@", uinfoOrHost0 | hostStart);
+ setChars(b, "/", pathSeg | pathStart);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(uinfoOrPort, uinfoOrPort | notSimple);
+ setRange(b, "09", uinfoOrPort);
+ setChars(b, "@", uinfoOrHost0 | hostStart);
+ setChars(b, "/", pathSeg | pathStart);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(ipv6Host, ipv6Host);
+ setChars(b, "]", uinfoOrHost);
+
+ b = build(relPathSeg, path | notSimple);
+ setChars(b, pchar, path);
+ setChars(b, ".", relPathSegDot);
+ setChars(b, "/", pathSeg | notSimple);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(relPathSegDot, path | notSimple);
+ setChars(b, pchar, path);
+ setChars(b, ".", relPathSegDot2);
+ setChars(b, "/", pathSeg | notSimple);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(relPathSegDot2, path | notSimple);
+ setChars(b, pchar, path);
+ setChars(b, "/", relPathSeg);
+ setChars(b, "?", query | queryStart); // This should be non-simple.
+ setChars(b, "#", fragment | fragmentStart); // This should be non-simple.
+
+ b = build(pathSeg, path | notSimple);
+ setChars(b, pchar, path);
+ setChars(b, ".", pathSegDot);
+ setChars(b, "/", pathSeg | notSimple);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(pathSegDot, path | notSimple);
+ setChars(b, pchar, path);
+ setChars(b, ".", pathSegDot2);
+ setChars(b, "/", pathSeg | notSimple);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(pathSegDot2, path | notSimple);
+ setChars(b, pchar, path);
+ setChars(b, "/", pathSeg | notSimple);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(path, path | notSimple);
+ setChars(b, pchar, path);
+ setChars(b, "/", pathSeg);
+ setChars(b, "?", query | queryStart);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(query, query | notSimple);
+ setChars(b, pchar, query);
+ setChars(b, "?", query);
+ setChars(b, "#", fragment | fragmentStart);
+
+ b = build(fragment, fragment | notSimple);
+ setChars(b, pchar, fragment);
+ setChars(b, "?", fragment);
+
+ // A separate two-state validator for lower-case scheme names.
+ // Any non-scheme character or upper-case letter is marked as non-simple.
+ b = build(scheme0, scheme | notSimple);
+ setRange(b, "az", scheme);
+
+ b = build(scheme, scheme | notSimple);
+ setRange(b, "az", scheme);
+ setRange(b, "09", scheme);
+ setChars(b, "+-.", scheme);
+
+ return tables;
+}
+
+// --------------------------------------------------------------------
+// Code that uses the URI scanner table.
+
+/// Scan a string using the [_scannerTables] state machine.
+///
+/// Scans [uri] from [start] to [end], starting in state [state] and
+/// writing output into [indices].
+///
+/// Returns the final state.
+int _scan(String uri, int start, int end, int state, List<int> indices) {
+ var tables = _scannerTables;
+ assert(end <= uri.length);
+ for (int i = start; i < end; i++) {
+ var table = tables[state];
+ // Xor with 0x60 to move range 0x20-0x7f into 0x00-0x5f
+ int char = uri.codeUnitAt(i) ^ 0x60;
+ // Use 0x1f (nee 0x7f) to represent all unhandled characters.
+ if (char > 0x5f) char = 0x1f;
+ int transition = table[char];
+ state = transition & 0x1f;
+ indices[transition >> 5] = i;
+ }
+ return state;
+}
+
+class _SimpleUri implements Uri {
+ final String _uri;
+ final int _schemeEnd;
+ final int _hostStart;
+ final int _portStart;
+ final int _pathStart;
+ final int _queryStart;
+ final int _fragmentStart;
+
+ /// The scheme is often used to distinguish URIs.
+ /// To make comparisons more efficient, we cache the value, and
+ /// canonicalize a few known types.
+ String _schemeCache;
+ int _hashCodeCache;
+
+ _SimpleUri(
+ this._uri,
+ this._schemeEnd,
+ this._hostStart,
+ this._portStart,
+ this._pathStart,
+ this._queryStart,
+ this._fragmentStart,
+ this._schemeCache);
+
+ bool get hasScheme => _schemeEnd > 0;
+ bool get hasAuthority => _hostStart > 0;
+ bool get hasUserInfo => _hostStart > _schemeEnd + 4;
+ bool get hasPort => _hostStart > 0 && _portStart + 1 < _pathStart;
+ bool get hasQuery => _queryStart < _fragmentStart;
+ bool get hasFragment => _fragmentStart < _uri.length;
+
+ bool get _isFile => _schemeEnd == 4 && _uri.startsWith("file");
+ bool get _isHttp => _schemeEnd == 4 && _uri.startsWith("http");
+ bool get _isHttps => _schemeEnd == 5 && _uri.startsWith("https");
+ bool get _isPackage => _schemeEnd == 7 && _uri.startsWith("package");
+
+ /// Like [isScheme] but expects argument to be case normalized.
+ bool _isScheme(String scheme) =>
+ _schemeEnd == scheme.length && _uri.startsWith(scheme);
+
+ bool get hasAbsolutePath => _uri.startsWith("/", _pathStart);
+ bool get hasEmptyPath => _pathStart == _queryStart;
+
+ bool get isAbsolute => hasScheme && !hasFragment;
+
+ bool isScheme(String scheme) {
+ if (scheme == null || scheme.isEmpty) return _schemeEnd < 0;
+ if (scheme.length != _schemeEnd) return false;
+ return _Uri._compareScheme(scheme, _uri);
+ }
+
+ String get scheme {
+ if (_schemeEnd <= 0) return "";
+ if (_schemeCache != null) return _schemeCache;
+ if (_isHttp) {
+ _schemeCache = "http";
+ } else if (_isHttps) {
+ _schemeCache = "https";
+ } else if (_isFile) {
+ _schemeCache = "file";
+ } else if (_isPackage) {
+ _schemeCache = "package";
+ } else {
+ _schemeCache = _uri.substring(0, _schemeEnd);
+ }
+ return _schemeCache;
+ }
+
+ String get authority =>
+ _hostStart > 0 ? _uri.substring(_schemeEnd + 3, _pathStart) : "";
+ String get userInfo => (_hostStart > _schemeEnd + 3)
+ ? _uri.substring(_schemeEnd + 3, _hostStart - 1)
+ : "";
+ String get host =>
+ _hostStart > 0 ? _uri.substring(_hostStart, _portStart) : "";
+ int get port {
+ if (hasPort) return int.parse(_uri.substring(_portStart + 1, _pathStart));
+ if (_isHttp) return 80;
+ if (_isHttps) return 443;
+ return 0;
+ }
+
+ String get path => _uri.substring(_pathStart, _queryStart);
+ String get query => (_queryStart < _fragmentStart)
+ ? _uri.substring(_queryStart + 1, _fragmentStart)
+ : "";
+ String get fragment =>
+ (_fragmentStart < _uri.length) ? _uri.substring(_fragmentStart + 1) : "";
+
+ String get origin {
+ // Check original behavior - W3C spec is wonky!
+ bool isHttp = _isHttp;
+ if (_schemeEnd < 0) {
+ throw StateError("Cannot use origin without a scheme: $this");
+ }
+ if (!isHttp && !_isHttps) {
+ throw StateError(
+ "Origin is only applicable to schemes http and https: $this");
+ }
+ if (_hostStart == _portStart) {
+ throw StateError(
+ "A $scheme: URI should have a non-empty host name: $this");
+ }
+ if (_hostStart == _schemeEnd + 3) {
+ return _uri.substring(0, _pathStart);
+ }
+ // Need to drop anon-empty userInfo.
+ return _uri.substring(0, _schemeEnd + 3) +
+ _uri.substring(_hostStart, _pathStart);
+ }
+
+ List<String> get pathSegments {
+ int start = _pathStart;
+ int end = _queryStart;
+ if (_uri.startsWith("/", start)) start++;
+ if (start == end) return const <String>[];
+ List<String> parts = [];
+ for (int i = start; i < end; i++) {
+ var char = _uri.codeUnitAt(i);
+ if (char == _SLASH) {
+ parts.add(_uri.substring(start, i));
+ start = i + 1;
+ }
+ }
+ parts.add(_uri.substring(start, end));
+ return List<String>.unmodifiable(parts);
+ }
+
+ Map<String, String> get queryParameters {
+ if (!hasQuery) return const <String, String>{};
+ return UnmodifiableMapView<String, String>(Uri.splitQueryString(query));
+ }
+
+ Map<String, List<String>> get queryParametersAll {
+ if (!hasQuery) return const <String, List<String>>{};
+ Map queryParameterLists = _Uri._splitQueryStringAll(query);
+ for (var key in queryParameterLists.keys) {
+ queryParameterLists[key] =
+ List<String>.unmodifiable(queryParameterLists[key]);
+ }
+ return Map<String, List<String>>.unmodifiable(queryParameterLists);
+ }
+
+ bool _isPort(String port) {
+ int portDigitStart = _portStart + 1;
+ return portDigitStart + port.length == _pathStart &&
+ _uri.startsWith(port, portDigitStart);
+ }
+
+ Uri normalizePath() => this;
+
+ Uri removeFragment() {
+ if (!hasFragment) return this;
+ return _SimpleUri(_uri.substring(0, _fragmentStart), _schemeEnd, _hostStart,
+ _portStart, _pathStart, _queryStart, _fragmentStart, _schemeCache);
+ }
+
+ Uri replace(
+ {String scheme,
+ String userInfo,
+ String host,
+ int port,
+ String path,
+ Iterable<String> pathSegments,
+ String query,
+ Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
+ String fragment}) {
+ bool schemeChanged = false;
+ if (scheme != null) {
+ scheme = _Uri._makeScheme(scheme, 0, scheme.length);
+ schemeChanged = !_isScheme(scheme);
+ } else {
+ scheme = this.scheme;
+ }
+ bool isFile = (scheme == "file");
+ if (userInfo != null) {
+ userInfo = _Uri._makeUserInfo(userInfo, 0, userInfo.length);
+ } else if (_hostStart > 0) {
+ userInfo = _uri.substring(_schemeEnd + 3, _hostStart);
+ } else {
+ userInfo = "";
+ }
+ if (port != null) {
+ port = _Uri._makePort(port, scheme);
+ } else {
+ port = this.hasPort ? this.port : null;
+ if (schemeChanged) {
+ // The default port might have changed.
+ port = _Uri._makePort(port, scheme);
+ }
+ }
+ if (host != null) {
+ host = _Uri._makeHost(host, 0, host.length, false);
+ } else if (_hostStart > 0) {
+ host = _uri.substring(_hostStart, _portStart);
+ } else if (userInfo.isNotEmpty || port != null || isFile) {
+ host = "";
+ }
+
+ bool hasAuthority = host != null;
+ if (path != null || pathSegments != null) {
+ path = _Uri._makePath(path, 0, _stringOrNullLength(path), pathSegments,
+ scheme, hasAuthority);
+ } else {
+ path = _uri.substring(_pathStart, _queryStart);
+ if ((isFile || (hasAuthority && !path.isEmpty)) &&
+ !path.startsWith('/')) {
+ path = "/" + path;
+ }
+ }
+
+ if (query != null || queryParameters != null) {
+ query = _Uri._makeQuery(
+ query, 0, _stringOrNullLength(query), queryParameters);
+ } else if (_queryStart < _fragmentStart) {
+ query = _uri.substring(_queryStart + 1, _fragmentStart);
+ }
+
+ if (fragment != null) {
+ fragment = _Uri._makeFragment(fragment, 0, fragment.length);
+ } else if (_fragmentStart < _uri.length) {
+ fragment = _uri.substring(_fragmentStart + 1);
+ }
+
+ return _Uri._internal(scheme, userInfo, host, port, path, query, fragment);
+ }
+
+ Uri resolve(String reference) {
+ return resolveUri(Uri.parse(reference));
+ }
+
+ Uri resolveUri(Uri reference) {
+ if (reference is _SimpleUri) {
+ return _simpleMerge(this, reference);
+ }
+ return _toNonSimple().resolveUri(reference);
+ }
+
+ // Merge two simple URIs. This should always result in a prefix of
+ // one concatenated with a suffix of the other, possibly with a `/` in
+ // the middle of two merged paths, which is again simple.
+ // In a few cases, there might be a need for extra normalization, when
+ // resolving on top of a known scheme.
+ Uri _simpleMerge(_SimpleUri base, _SimpleUri ref) {
+ if (ref.hasScheme) return ref;
+ if (ref.hasAuthority) {
+ if (!base.hasScheme) return ref;
+ bool isSimple = true;
+ if (base._isFile) {
+ isSimple = !ref.hasEmptyPath;
+ } else if (base._isHttp) {
+ isSimple = !ref._isPort("80");
+ } else if (base._isHttps) {
+ isSimple = !ref._isPort("443");
+ }
+ if (isSimple) {
+ var delta = base._schemeEnd + 1;
+ var newUri = base._uri.substring(0, base._schemeEnd + 1) +
+ ref._uri.substring(ref._schemeEnd + 1);
+ return _SimpleUri(
+ newUri,
+ base._schemeEnd,
+ ref._hostStart + delta,
+ ref._portStart + delta,
+ ref._pathStart + delta,
+ ref._queryStart + delta,
+ ref._fragmentStart + delta,
+ base._schemeCache);
+ } else {
+ // This will require normalization, so use the _Uri implementation.
+ return _toNonSimple().resolveUri(ref);
+ }
+ }
+ if (ref.hasEmptyPath) {
+ if (ref.hasQuery) {
+ int delta = base._queryStart - ref._queryStart;
+ var newUri = base._uri.substring(0, base._queryStart) +
+ ref._uri.substring(ref._queryStart);
+ return _SimpleUri(
+ newUri,
+ base._schemeEnd,
+ base._hostStart,
+ base._portStart,
+ base._pathStart,
+ ref._queryStart + delta,
+ ref._fragmentStart + delta,
+ base._schemeCache);
+ }
+ if (ref.hasFragment) {
+ int delta = base._fragmentStart - ref._fragmentStart;
+ var newUri = base._uri.substring(0, base._fragmentStart) +
+ ref._uri.substring(ref._fragmentStart);
+ return _SimpleUri(
+ newUri,
+ base._schemeEnd,
+ base._hostStart,
+ base._portStart,
+ base._pathStart,
+ base._queryStart,
+ ref._fragmentStart + delta,
+ base._schemeCache);
+ }
+ return base.removeFragment();
+ }
+ if (ref.hasAbsolutePath) {
+ var delta = base._pathStart - ref._pathStart;
+ var newUri = base._uri.substring(0, base._pathStart) +
+ ref._uri.substring(ref._pathStart);
+ return _SimpleUri(
+ newUri,
+ base._schemeEnd,
+ base._hostStart,
+ base._portStart,
+ base._pathStart,
+ ref._queryStart + delta,
+ ref._fragmentStart + delta,
+ base._schemeCache);
+ }
+ if (base.hasEmptyPath && base.hasAuthority) {
+ // ref has relative non-empty path.
+ // Add a "/" in front, then leading "/../" segments are folded to "/".
+ int refStart = ref._pathStart;
+ while (ref._uri.startsWith("../", refStart)) {
+ refStart += 3;
+ }
+ var delta = base._pathStart - refStart + 1;
+ var newUri = "${base._uri.substring(0, base._pathStart)}/"
+ "${ref._uri.substring(refStart)}";
+ return _SimpleUri(
+ newUri,
+ base._schemeEnd,
+ base._hostStart,
+ base._portStart,
+ base._pathStart,
+ ref._queryStart + delta,
+ ref._fragmentStart + delta,
+ base._schemeCache);
+ }
+ // Merge paths.
+
+ // The RFC 3986 algorithm merges the base path without its final segment
+ // (anything after the final "/", or everything if the base path doesn't
+ // contain any "/"), and the reference path.
+ // Then it removes "." and ".." segments using the remove-dot-segment
+ // algorithm.
+ // This code combines the two steps. It is simplified by knowing that
+ // the base path contains no "." or ".." segments, and the reference
+ // path can only contain leading ".." segments.
+
+ String baseUri = base._uri;
+ String refUri = ref._uri;
+ int baseStart = base._pathStart;
+ int baseEnd = base._queryStart;
+ while (baseUri.startsWith("../", baseStart)) baseStart += 3;
+ int refStart = ref._pathStart;
+ int refEnd = ref._queryStart;
+
+ /// Count of leading ".." segments in reference path.
+ /// The count is decremented when the segment is matched with a
+ /// segment of the base path, and both are then omitted from the result.
+ int backCount = 0;
+
+ /// Count "../" segments and advance `refStart` to after the segments.
+ while (refStart + 3 <= refEnd && refUri.startsWith("../", refStart)) {
+ refStart += 3;
+ backCount += 1;
+ }
+
+ // Extra slash inserted between base and reference path parts if
+ // the base path contains any slashes, or empty string if none.
+ // (We could use a slash from the base path in most cases, but not if
+ // we remove the entire base path).
+ String insert = "";
+
+ /// Remove segments from the base path.
+ /// Start with the segment trailing the last slash,
+ /// then remove segments for each leading "../" segment
+ /// from the reference path, or as many of them as are available.
+ while (baseEnd > baseStart) {
+ baseEnd--;
+ int char = baseUri.codeUnitAt(baseEnd);
+ if (char == _SLASH) {
+ insert = "/";
+ if (backCount == 0) break;
+ backCount--;
+ }
+ }
+
+ if (baseEnd == baseStart && !base.hasScheme && !base.hasAbsolutePath) {
+ // If the base is *just* a relative path (no scheme or authority),
+ // then merging with another relative path doesn't follow the
+ // RFC-3986 behavior.
+ // Don't need to check `base.hasAuthority` since the base path is
+ // non-empty - if there is an authority, a non-empty path is absolute.
+
+ // We reached the start of the base path, and want to stay relative,
+ // so don't insert a slash.
+ insert = "";
+ // If we reached the start of the base path with more "../" left over
+ // in the reference path, include those segments in the result.
+ refStart -= backCount * 3;
+ }
+
+ var delta = baseEnd - refStart + insert.length;
+ var newUri = "${base._uri.substring(0, baseEnd)}$insert"
+ "${ref._uri.substring(refStart)}";
+
+ return _SimpleUri(
+ newUri,
+ base._schemeEnd,
+ base._hostStart,
+ base._portStart,
+ base._pathStart,
+ ref._queryStart + delta,
+ ref._fragmentStart + delta,
+ base._schemeCache);
+ }
+
+ String toFilePath({bool windows}) {
+ if (_schemeEnd >= 0 && !_isFile) {
+ throw UnsupportedError("Cannot extract a file path from a $scheme URI");
+ }
+ if (_queryStart < _uri.length) {
+ if (_queryStart < _fragmentStart) {
+ throw UnsupportedError(
+ "Cannot extract a file path from a URI with a query component");
+ }
+ throw UnsupportedError(
+ "Cannot extract a file path from a URI with a fragment component");
+ }
+ windows ??= _Uri._isWindows;
+ return windows ? _Uri._toWindowsFilePath(this) : _toFilePath();
+ }
+
+ String _toFilePath() {
+ if (_hostStart < _portStart) {
+ // Has authority and non-empty host.
+ throw UnsupportedError(
+ "Cannot extract a non-Windows file path from a file URI "
+ "with an authority");
+ }
+ return this.path;
+ }
+
+ UriData get data {
+ assert(scheme != "data");
+ return null;
+ }
+
+ int get hashCode => _hashCodeCache ??= _uri.hashCode;
+
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+ return other is Uri && _uri == other.toString();
+ }
+
+ Uri _toNonSimple() {
+ return _Uri._internal(
+ this.scheme,
+ this.userInfo,
+ this.hasAuthority ? this.host : null,
+ this.hasPort ? this.port : null,
+ this.path,
+ this.hasQuery ? this.query : null,
+ this.hasFragment ? this.fragment : null);
+ }
+
+ String toString() => _uri;
+}
+
+/// Special [_Uri] created from an existing [UriData].
+class _DataUri extends _Uri {
+ final UriData _data;
+
+ _DataUri(this._data, String path, String query)
+ : super._internal("data", null, null, null, path, query, null);
+
+ UriData get data => _data;
+}
+
+/// Checks whether [text] starts with "data:" at position [start].
+///
+/// The text must be long enough to allow reading five characters
+/// from the [start] position.
+///
+/// Returns an integer value which is zero if text starts with all-lowercase
+/// "data:" and 0x20 if the text starts with "data:" that isn't all lower-case.
+/// All other values means the text starts with some other character.
+int _startsWithData(String text, int start) {
+ // Multiply by 3 to avoid a non-colon character making delta be 0x20.
+ int delta = (text.codeUnitAt(start + 4) ^ _COLON) * 3;
+ delta |= text.codeUnitAt(start) ^ 0x64 /*d*/;
+ delta |= text.codeUnitAt(start + 1) ^ 0x61 /*a*/;
+ delta |= text.codeUnitAt(start + 2) ^ 0x74 /*t*/;
+ delta |= text.codeUnitAt(start + 3) ^ 0x61 /*a*/;
+ return delta;
+}
+
+/// Helper function returning the length of a string, or `0` for `null`.
+int _stringOrNullLength(String s) => (s == null) ? 0 : s.length;
diff --git a/sdk_nnbd/lib/developer/developer.dart b/sdk_nnbd/lib/developer/developer.dart
new file mode 100644
index 0000000..c446fdf
--- /dev/null
+++ b/sdk_nnbd/lib/developer/developer.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Interact with developer tools such as the debugger and inspector.
+///
+/// This library is platform dependent and has separate implementations for
+/// both web and the Dart VM. A specific platform may not support all
+/// operations.
+///
+/// To use this library in your code:
+///
+/// import 'dart:developer';
+///
+/// {@category Core}
+library dart.developer;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:isolate' show Isolate, RawReceivePort, SendPort;
+
+part 'extension.dart';
+part 'profiler.dart';
+part 'service.dart';
+part 'timeline.dart';
+
+/// If [when] is true, stop the program as if a breakpoint were hit at the
+/// following statement.
+///
+/// Returns the value of [when]. Some debuggers may display [message].
+///
+/// NOTE: When invoked, the isolate will not return until a debugger
+/// continues execution. When running in the Dart VM, the behaviour is the same
+/// regardless of whether or not a debugger is connected. When compiled to
+/// JavaScript, this uses the "debugger" statement, and behaves exactly as
+/// that does.
+external bool debugger({bool when: true, String message});
+
+/// Send a reference to [object] to any attached debuggers.
+///
+/// Debuggers may open an inspector on the object. Returns the argument.
+external Object inspect(Object object);
+
+/// Emit a log event.
+///
+/// This function was designed to map closely to the logging information
+/// collected by `package:logging`.
+///
+/// - [message] is the log message
+/// - [time] (optional) is the timestamp
+/// - [sequenceNumber] (optional) is a monotonically increasing sequence number
+/// - [level] (optional) is the severity level (a value between 0 and 2000); see
+/// the `package:logging` `Level` class for an overview of the possible values
+/// - [name] (optional) is the name of the source of the log message
+/// - [zone] (optional) the zone where the log was emitted
+/// - [error] (optional) an error object associated with this log event
+/// - [stackTrace] (optional) a stack trace associated with this log event
+external void log(
+ String message, {
+ DateTime time,
+ int sequenceNumber,
+ int level: 0,
+ String name: '',
+ Zone zone,
+ Object error,
+ StackTrace stackTrace,
+});
diff --git a/sdk_nnbd/lib/developer/developer_sources.gni b/sdk_nnbd/lib/developer/developer_sources.gni
new file mode 100644
index 0000000..df0dbc2
--- /dev/null
+++ b/sdk_nnbd/lib/developer/developer_sources.gni
@@ -0,0 +1,13 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+developer_sdk_sources = [
+ "developer.dart",
+
+ # The above file needs to be first if additional parts are added to the lib.
+ "extension.dart",
+ "profiler.dart",
+ "service.dart",
+ "timeline.dart",
+]
diff --git a/sdk_nnbd/lib/developer/extension.dart b/sdk_nnbd/lib/developer/extension.dart
new file mode 100644
index 0000000..3cc4ede
--- /dev/null
+++ b/sdk_nnbd/lib/developer/extension.dart
@@ -0,0 +1,161 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.developer;
+
+/// A response to a service protocol extension RPC.
+///
+/// If the RPC was successful, use [ServiceExtensionResponse.result], otherwise
+/// use [ServiceExtensionResponse.error].
+class ServiceExtensionResponse {
+ /// The result of a successful service protocol extension RPC.
+ final String result;
+
+ /// The error code associated with a failed service protocol extension RPC.
+ final int errorCode;
+
+ /// The details of a failed service protocol extension RPC.
+ final String errorDetail;
+
+ /// Creates a successful response to a service protocol extension RPC.
+ ///
+ /// Requires [result] to be a JSON object encoded as a string. When forming
+ /// the JSON-RPC message [result] will be inlined directly.
+ ServiceExtensionResponse.result(String result)
+ : result = result,
+ errorCode = null,
+ errorDetail = null {
+ ArgumentError.checkNotNull(result, "result");
+ }
+
+ /// Creates an error response to a service protocol extension RPC.
+ ///
+ /// Requires [errorCode] to be [invalidParams] or between [extensionErrorMin]
+ /// and [extensionErrorMax]. Requires [errorDetail] to be a JSON object
+ /// encoded as a string. When forming the JSON-RPC message [errorDetail] will
+ /// be inlined directly.
+ ServiceExtensionResponse.error(int errorCode, String errorDetail)
+ : result = null,
+ errorCode = errorCode,
+ errorDetail = errorDetail {
+ _validateErrorCode(errorCode);
+ ArgumentError.checkNotNull(errorDetail, "errorDetail");
+ }
+
+ /// Invalid method parameter(s) error code.
+ @deprecated
+ static const kInvalidParams = invalidParams;
+
+ /// Generic extension error code.
+ @deprecated
+ static const kExtensionError = extensionError;
+
+ /// Maximum extension provided error code.
+ @deprecated
+ static const kExtensionErrorMax = extensionErrorMax;
+
+ /// Minimum extension provided error code.
+ @deprecated
+ static const kExtensionErrorMin = extensionErrorMin;
+
+ /// Invalid method parameter(s) error code.
+ static const invalidParams = -32602;
+
+ /// Generic extension error code.
+ static const extensionError = -32000;
+
+ /// Maximum extension provided error code.
+ static const extensionErrorMax = -32000;
+
+ /// Minimum extension provided error code.
+ static const extensionErrorMin = -32016;
+
+ static String _errorCodeMessage(int errorCode) {
+ _validateErrorCode(errorCode);
+ if (errorCode == invalidParams) {
+ return "Invalid params";
+ }
+ return "Server error";
+ }
+
+ static _validateErrorCode(int errorCode) {
+ ArgumentError.checkNotNull(errorCode, "errorCode");
+ if (errorCode == invalidParams) return;
+ if ((errorCode >= extensionErrorMin) && (errorCode <= extensionErrorMax)) {
+ return;
+ }
+ throw new ArgumentError.value(errorCode, "errorCode", "Out of range");
+ }
+
+ /// Determines if this response represents an error.
+ bool isError() => (errorCode != null) && (errorDetail != null);
+
+ // ignore: unused_element, called from runtime/lib/developer.dart
+ String _toString() {
+ if (result != null) {
+ return result;
+ } else {
+ assert(errorCode != null);
+ assert(errorDetail != null);
+ return json.encode({
+ 'code': errorCode,
+ 'message': _errorCodeMessage(errorCode),
+ 'data': {'details': errorDetail}
+ });
+ }
+ }
+}
+
+/// A service protocol extension handler. Registered with [registerExtension].
+///
+/// Must complete to a [ServiceExtensionResponse]. [method] is the method name
+/// of the service protocol request, and [parameters] is a map holding the
+/// parameters to the service protocol request.
+///
+/// *NOTE*: all parameter names and values are encoded as strings.
+typedef Future<ServiceExtensionResponse> ServiceExtensionHandler(
+ String method, Map<String, String> parameters);
+
+/// Register a [ServiceExtensionHandler] that will be invoked in this isolate
+/// for [method]. *NOTE*: Service protocol extensions must be registered
+/// in each isolate.
+///
+/// *NOTE*: [method] must begin with 'ext.' and you should use the following
+/// structure to avoid conflicts with other packages: 'ext.package.command'.
+/// That is, immediately following the 'ext.' prefix, should be the registering
+/// package name followed by another period ('.') and then the command name.
+/// For example: 'ext.dart.io.getOpenFiles'.
+///
+/// Because service extensions are isolate specific, clients using extensions
+/// must always include an 'isolateId' parameter with each RPC.
+void registerExtension(String method, ServiceExtensionHandler handler) {
+ ArgumentError.checkNotNull(method, 'method');
+ if (!method.startsWith('ext.')) {
+ throw new ArgumentError.value(method, 'method', 'Must begin with ext.');
+ }
+ if (_lookupExtension(method) != null) {
+ throw new ArgumentError('Extension already registered: $method');
+ }
+ ArgumentError.checkNotNull(handler, 'handler');
+ _registerExtension(method, handler);
+}
+
+/// Post an event of [eventKind] with payload of [eventData] to the `Extension`
+/// event stream.
+void postEvent(String eventKind, Map eventData) {
+ ArgumentError.checkNotNull(eventKind, 'eventKind');
+ ArgumentError.checkNotNull(eventData, 'eventData');
+ String eventDataAsString = json.encode(eventData);
+ _postEvent(eventKind, eventDataAsString);
+}
+
+external void _postEvent(String eventKind, String eventData);
+
+// Both of these functions are written inside C++ to avoid updating the data
+// structures in Dart, getting an OOB, and observing stale state. Do not move
+// these into Dart code unless you can ensure that the operations will can be
+// done atomically. Native code lives in vm/isolate.cc-
+// LookupServiceExtensionHandler and RegisterServiceExtensionHandler.
+external ServiceExtensionHandler _lookupExtension(String method);
+external _registerExtension(String method, ServiceExtensionHandler handler);
diff --git a/sdk_nnbd/lib/developer/profiler.dart b/sdk_nnbd/lib/developer/profiler.dart
new file mode 100644
index 0000000..05a9211
--- /dev/null
+++ b/sdk_nnbd/lib/developer/profiler.dart
@@ -0,0 +1,149 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.developer;
+
+/// A UserTag can be used to group samples in the Observatory profiler.
+abstract class UserTag {
+ /// The maximum number of UserTag instances that can be created by a program.
+ static const MAX_USER_TAGS = 64;
+
+ external factory UserTag(String label);
+
+ /// Label of [this].
+ String get label;
+
+ /// Make [this] the current tag for the isolate. Returns the current tag
+ /// before setting.
+ UserTag makeCurrent();
+
+ /// The default [UserTag] with label 'Default'.
+ external static UserTag get defaultTag;
+}
+
+/// Returns the current [UserTag] for the isolate.
+external UserTag getCurrentTag();
+
+/// Abstract [Metric] class. Metric names must be unique, are hierarchical,
+/// and use periods as separators. For example, 'a.b.c'. Uniqueness is only
+/// enforced when a Metric is registered. The name of a metric cannot contain
+/// the slash ('/') character.
+abstract class Metric {
+ /// [name] of this metric.
+ final String name;
+
+ /// [description] of this metric.
+ final String description;
+
+ Metric(this.name, this.description) {
+ if ((name == 'vm') || name.contains('/')) {
+ throw new ArgumentError('Invalid Metric name.');
+ }
+ }
+
+ Map _toJSON();
+}
+
+/// A measured value with a min and max. Initial value is min. Value will
+/// be clamped to the interval [min, max].
+class Gauge extends Metric {
+ final double min;
+ final double max;
+
+ double _value;
+ double get value => _value;
+ set value(double v) {
+ if (v < min) {
+ v = min;
+ } else if (v > max) {
+ v = max;
+ }
+ _value = v;
+ }
+
+ Gauge(String name, String description, this.min, this.max)
+ : super(name, description) {
+ ArgumentError.checkNotNull(min, 'min');
+ ArgumentError.checkNotNull(max, 'max');
+ if (!(min < max)) throw new ArgumentError('min must be less than max');
+ _value = min;
+ }
+
+ Map _toJSON() {
+ var map = {
+ 'type': 'Gauge',
+ 'id': 'metrics/$name',
+ 'name': name,
+ 'description': description,
+ 'value': value,
+ 'min': min,
+ 'max': max,
+ };
+ return map;
+ }
+}
+
+/// A changing value. Initial value is 0.0.
+class Counter extends Metric {
+ Counter(String name, String description) : super(name, description);
+
+ double _value = 0.0;
+ double get value => _value;
+ set value(double v) {
+ _value = v;
+ }
+
+ Map _toJSON() {
+ var map = {
+ 'type': 'Counter',
+ 'id': 'metrics/$name',
+ 'name': name,
+ 'description': description,
+ 'value': value,
+ };
+ return map;
+ }
+}
+
+class Metrics {
+ static final Map<String, Metric> _metrics = new Map<String, Metric>();
+
+ /// Register [Metric]s to make them visible to Observatory.
+ static void register(Metric metric) {
+ ArgumentError.checkNotNull(metric, 'metric');
+ if (_metrics[metric.name] != null) {
+ throw new ArgumentError('Registered metrics have unique names');
+ }
+ _metrics[metric.name] = metric;
+ }
+
+ /// Deregister [Metric]s to make them not visible to Observatory.
+ static void deregister(Metric metric) {
+ ArgumentError.checkNotNull(metric, 'metric');
+ _metrics.remove(metric.name);
+ }
+
+ // ignore: unused_element, called from native code
+ static String _printMetric(String id) {
+ var metric = _metrics[id];
+ if (metric == null) {
+ return null;
+ }
+ return json.encode(metric._toJSON());
+ }
+
+ // ignore: unused_element, called from native code
+ @pragma("vm:entry-point", !const bool.fromEnvironment("dart.vm.product"))
+ static String _printMetrics() {
+ var metrics = [];
+ for (var metric in _metrics.values) {
+ metrics.add(metric._toJSON());
+ }
+ var map = {
+ 'type': 'MetricList',
+ 'metrics': metrics,
+ };
+ return json.encode(map);
+ }
+}
diff --git a/sdk_nnbd/lib/developer/service.dart b/sdk_nnbd/lib/developer/service.dart
new file mode 100644
index 0000000..a4d92b9
--- /dev/null
+++ b/sdk_nnbd/lib/developer/service.dart
@@ -0,0 +1,98 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.developer;
+
+/// Service protocol is the protocol that a client like the Observatory
+/// could use to access the services provided by the Dart VM for
+/// debugging and inspecting Dart programs. This class encapsulates the
+/// version number and Uri for accessing this service.
+class ServiceProtocolInfo {
+ /// The major version of the protocol. If the running Dart environment does
+ /// not support the service protocol, this is 0.
+ final int majorVersion = _getServiceMajorVersion();
+
+ /// The minor version of the protocol. If the running Dart environment does
+ /// not support the service protocol, this is 0.
+ final int minorVersion = _getServiceMinorVersion();
+
+ /// The Uri to access the service. If the web server is not running, this
+ /// will be null.
+ final Uri serverUri;
+
+ ServiceProtocolInfo(this.serverUri);
+
+ String toString() {
+ if (serverUri != null) {
+ return 'Dart VM Service Protocol v$majorVersion.$minorVersion '
+ 'listening on $serverUri';
+ } else {
+ return 'Dart VM Service Protocol v$majorVersion.$minorVersion';
+ }
+ }
+}
+
+/// Access information about the service protocol and control the web server
+/// that provides access to the services provided by the Dart VM for
+/// debugging and inspecting Dart programs.
+class Service {
+ /// Get information about the service protocol (version number and
+ /// Uri to access the service).
+ static Future<ServiceProtocolInfo> getInfo() async {
+ // Port to receive response from service isolate.
+ final RawReceivePort receivePort = new RawReceivePort();
+ final Completer<Uri> uriCompleter = new Completer<Uri>();
+ receivePort.handler = (Uri uri) => uriCompleter.complete(uri);
+ // Request the information from the service isolate.
+ _getServerInfo(receivePort.sendPort);
+ // Await the response from the service isolate.
+ Uri uri = await uriCompleter.future;
+ // Close the port.
+ receivePort.close();
+ return new ServiceProtocolInfo(uri);
+ }
+
+ /// Control the web server that the service protocol is accessed through.
+ /// The [enable] argument must be a boolean and is used as a toggle to
+ /// enable (true) or disable (false) the web server servicing requests.
+ static Future<ServiceProtocolInfo> controlWebServer(
+ {bool enable: false}) async {
+ ArgumentError.checkNotNull(enable, 'enable');
+ // Port to receive response from service isolate.
+ final RawReceivePort receivePort = new RawReceivePort();
+ final Completer<Uri> uriCompleter = new Completer<Uri>();
+ receivePort.handler = (Uri uri) => uriCompleter.complete(uri);
+ // Request the information from the service isolate.
+ _webServerControl(receivePort.sendPort, enable);
+ // Await the response from the service isolate.
+ Uri uri = await uriCompleter.future;
+ // Close the port.
+ receivePort.close();
+ return new ServiceProtocolInfo(uri);
+ }
+
+ /// Returns a [String] token representing the ID of [isolate].
+ ///
+ /// Returns null if the running Dart environment does not support the service
+ /// protocol.
+ static String getIsolateID(Isolate isolate) {
+ ArgumentError.checkNotNull(isolate, 'isolate');
+ return _getIsolateIDFromSendPort(isolate.controlPort);
+ }
+}
+
+/// [sendPort] will receive a Uri or null.
+external void _getServerInfo(SendPort sendPort);
+
+/// [sendPort] will receive a Uri or null.
+external void _webServerControl(SendPort sendPort, bool enable);
+
+/// Returns the major version of the service protocol.
+external int _getServiceMajorVersion();
+
+/// Returns the minor version of the service protocol.
+external int _getServiceMinorVersion();
+
+/// Returns the service id for the isolate that owns [sendPort].
+external String _getIsolateIDFromSendPort(SendPort sendPort);
diff --git a/sdk_nnbd/lib/developer/timeline.dart b/sdk_nnbd/lib/developer/timeline.dart
new file mode 100644
index 0000000..02f9c98
--- /dev/null
+++ b/sdk_nnbd/lib/developer/timeline.dart
@@ -0,0 +1,344 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.developer;
+
+const bool _hasTimeline =
+ const bool.fromEnvironment("dart.developer.timeline", defaultValue: true);
+
+/// A typedef for the function argument to [Timeline.timeSync].
+typedef TimelineSyncFunction<T> = T Function();
+
+// TODO: This typedef is not used.
+typedef Future TimelineAsyncFunction();
+
+/// A class to represent Flow events.
+///
+/// [Flow] objects are used to thread flow events between timeline slices,
+/// for example, those created with the [Timeline] class below. Adding
+/// [Flow] objects cause arrows to be drawn between slices in Chrome's trace
+/// viewer. The arrows start at e.g [Timeline] events that are passed a
+/// [Flow.begin] object, go through [Timeline] events that are passed a
+/// [Flow.step] object, and end at [Timeline] events that are passed a
+/// [Flow.end] object, all having the same [Flow.id]. For example:
+///
+/// ```dart
+/// var flow = Flow.begin();
+/// Timeline.timeSync('flow_test', () {
+/// doSomething();
+/// }, flow: flow);
+///
+/// Timeline.timeSync('flow_test', () {
+/// doSomething();
+/// }, flow: Flow.step(flow.id));
+///
+/// Timeline.timeSync('flow_test', () {
+/// doSomething();
+/// }, flow: Flow.end(flow.id));
+/// ```
+class Flow {
+ // These values must be kept in sync with the enum "EventType" in
+ // runtime/vm/timeline.h.
+ static const int _begin = 9;
+ static const int _step = 10;
+ static const int _end = 11;
+
+ final int _type;
+
+ /// The flow id of the flow event.
+ final int id;
+
+ Flow._(this._type, this.id);
+
+ /// A "begin" Flow event.
+ ///
+ /// When passed to a [Timeline] method, generates a "begin" Flow event.
+ /// If [id] is not provided, an id that conflicts with no other Dart-generated
+ /// flow id's will be generated.
+ static Flow begin({int id}) {
+ return new Flow._(_begin, id ?? _getNextAsyncId());
+ }
+
+ /// A "step" Flow event.
+ ///
+ /// When passed to a [Timeline] method, generates a "step" Flow event.
+ /// The [id] argument is required. It can come either from another [Flow]
+ /// event, or some id that comes from the environment.
+ static Flow step(int id) => new Flow._(_step, id);
+
+ /// An "end" Flow event.
+ ///
+ /// When passed to a [Timeline] method, generates a "end" Flow event.
+ /// The [id] argument is required. It can come either from another [Flow]
+ /// event, or some id that comes from the environment.
+ static Flow end(int id) => new Flow._(_end, id);
+}
+
+/// Add to the timeline.
+///
+/// [Timeline]'s methods add synchronous events to the timeline. When
+/// generating a timeline in Chrome's tracing format, using [Timeline] generates
+/// "Complete" events. [Timeline]'s [startSync] and [finishSync] can be used
+/// explicitly, or implicitly by wrapping a closure in [timeSync]. For example:
+///
+/// ```dart
+/// Timeline.startSync("Doing Something");
+/// doSomething();
+/// Timeline.finishSync();
+/// ```
+///
+/// Or:
+///
+/// ```dart
+/// Timeline.timeSync("Doing Something", () {
+/// doSomething();
+/// });
+/// ```
+class Timeline {
+ /// Start a synchronous operation labeled [name]. Optionally takes
+ /// a [Map] of [arguments]. This slice may also optionally be associated with
+ /// a [Flow] event. This operation must be finished before
+ /// returning to the event queue.
+ static void startSync(String name, {Map arguments, Flow flow}) {
+ if (!_hasTimeline) return;
+ ArgumentError.checkNotNull(name, 'name');
+ if (!_isDartStreamEnabled()) {
+ // Push a null onto the stack and return.
+ _stack.add(null);
+ return;
+ }
+ var block = new _SyncBlock._(name, _getTraceClock(), _getThreadCpuClock());
+ if (arguments != null) {
+ block._arguments = arguments;
+ }
+ if (flow != null) {
+ block.flow = flow;
+ }
+ _stack.add(block);
+ }
+
+ /// Finish the last synchronous operation that was started.
+ static void finishSync() {
+ if (!_hasTimeline) {
+ return;
+ }
+ if (_stack.length == 0) {
+ throw new StateError('Uneven calls to startSync and finishSync');
+ }
+ // Pop top item off of stack.
+ var block = _stack.removeLast();
+ if (block == null) {
+ // Dart stream was disabled when startSync was called.
+ return;
+ }
+ // Finish it.
+ block.finish();
+ }
+
+ /// Emit an instant event.
+ static void instantSync(String name, {Map arguments}) {
+ if (!_hasTimeline) return;
+ ArgumentError.checkNotNull(name, 'name');
+ if (!_isDartStreamEnabled()) {
+ // Stream is disabled.
+ return;
+ }
+ Map instantArguments;
+ if (arguments != null) {
+ instantArguments = new Map.from(arguments);
+ }
+ _reportInstantEvent(
+ _getTraceClock(), 'Dart', name, _argumentsAsJson(instantArguments));
+ }
+
+ /// A utility method to time a synchronous [function]. Internally calls
+ /// [function] bracketed by calls to [startSync] and [finishSync].
+ static T timeSync<T>(String name, TimelineSyncFunction<T> function,
+ {Map arguments, Flow flow}) {
+ startSync(name, arguments: arguments, flow: flow);
+ try {
+ return function();
+ } finally {
+ finishSync();
+ }
+ }
+
+ /// The current time stamp from the clock used by the timeline. Units are
+ /// microseconds.
+ ///
+ /// When run on the Dart VM, uses the same monotonic clock as the embedding
+ /// API's `Dart_TimelineGetMicros`.
+ static int get now => _getTraceClock();
+ static final List<_SyncBlock> _stack = new List<_SyncBlock>();
+}
+
+/// An asynchronous task on the timeline. An asynchronous task can have many
+/// (nested) synchronous operations. Synchronous operations can live longer than
+/// the current isolate event. To pass a [TimelineTask] to another isolate,
+/// you must first call [pass] to get the task id and then construct a new
+/// [TimelineTask] in the other isolate.
+class TimelineTask {
+ /// Create a task. The task ID will be set by the system.
+ TimelineTask() : _taskId = _getNextAsyncId() {}
+
+ /// Create a task with an explicit [taskId]. This is useful if you are
+ /// passing a task from one isolate to another.
+ TimelineTask.withTaskId(int taskId) : _taskId = taskId {
+ ArgumentError.checkNotNull(taskId, 'taskId');
+ }
+
+ /// Start a synchronous operation within this task named [name].
+ /// Optionally takes a [Map] of [arguments].
+ void start(String name, {Map arguments}) {
+ if (!_hasTimeline) return;
+ ArgumentError.checkNotNull(name, 'name');
+ var block = new _AsyncBlock._(name, _taskId);
+ _stack.add(block);
+ block._start(arguments);
+ }
+
+ /// Emit an instant event for this task.
+ /// Optionally takes a [Map] of [arguments].
+ void instant(String name, {Map arguments}) {
+ if (!_hasTimeline) return;
+ ArgumentError.checkNotNull(name, 'name');
+ Map instantArguments;
+ if (arguments != null) {
+ instantArguments = new Map.from(arguments);
+ }
+ _reportTaskEvent(_getTraceClock(), _taskId, 'n', 'Dart', name,
+ _argumentsAsJson(instantArguments));
+ }
+
+ /// Finish the last synchronous operation that was started.
+ /// Optionally takes a [Map] of [arguments].
+ void finish({Map arguments}) {
+ if (!_hasTimeline) {
+ return;
+ }
+ if (_stack.length == 0) {
+ throw new StateError('Uneven calls to start and finish');
+ }
+ // Pop top item off of stack.
+ var block = _stack.removeLast();
+ block._finish(arguments);
+ }
+
+ /// Retrieve the [TimelineTask]'s task id. Will throw an exception if the
+ /// stack is not empty.
+ int pass() {
+ if (_stack.length > 0) {
+ throw new StateError(
+ 'You cannot pass a TimelineTask without finishing all started '
+ 'operations');
+ }
+ int r = _taskId;
+ return r;
+ }
+
+ final int _taskId;
+ final List<_AsyncBlock> _stack = [];
+}
+
+/// An asynchronous block of time on the timeline. This block can be kept
+/// open across isolate messages.
+class _AsyncBlock {
+ /// The category this block belongs to.
+ final String category = 'Dart';
+
+ /// The name of this block.
+ final String name;
+
+ /// The asynchronous task id.
+ final int _taskId;
+
+ _AsyncBlock._(this.name, this._taskId);
+
+ // Emit the start event.
+ void _start(Map arguments) {
+ _reportTaskEvent(_getTraceClock(), _taskId, 'b', category, name,
+ _argumentsAsJson(arguments));
+ }
+
+ // Emit the finish event.
+ void _finish(Map arguments) {
+ _reportTaskEvent(_getTraceClock(), _taskId, 'e', category, name,
+ _argumentsAsJson(arguments));
+ }
+}
+
+/// A synchronous block of time on the timeline. This block should not be
+/// kept open across isolate messages.
+class _SyncBlock {
+ /// The category this block belongs to.
+ final String category = 'Dart';
+
+ /// The name of this block.
+ final String name;
+
+ /// An (optional) set of arguments which will be serialized to JSON and
+ /// associated with this block.
+ Map _arguments;
+ // The start time stamp.
+ final int _start;
+ // The start time stamp of the thread cpu clock.
+ final int _startCpu;
+
+ /// An (optional) flow event associated with this block.
+ Flow _flow;
+
+ _SyncBlock._(this.name, this._start, this._startCpu);
+
+ /// Finish this block of time. At this point, this block can no longer be
+ /// used.
+ void finish() {
+ // Report event to runtime.
+ _reportCompleteEvent(
+ _start, _startCpu, category, name, _argumentsAsJson(_arguments));
+ if (_flow != null) {
+ _reportFlowEvent(_start, _startCpu, category, "${_flow.id}", _flow._type,
+ _flow.id, _argumentsAsJson(null));
+ }
+ }
+
+ void set flow(Flow f) {
+ _flow = f;
+ }
+}
+
+String _argumentsAsJson(Map arguments) {
+ if ((arguments == null) || (arguments.length == 0)) {
+ // Fast path no arguments. Avoid calling jsonEncode.
+ return '{}';
+ }
+ return json.encode(arguments);
+}
+
+/// Returns true if the Dart Timeline stream is enabled.
+external bool _isDartStreamEnabled();
+
+/// Returns the next async task id.
+external int _getNextAsyncId();
+
+/// Returns the current value from the trace clock.
+external int _getTraceClock();
+
+/// Returns the current value from the thread CPU usage clock.
+external int _getThreadCpuClock();
+
+/// Reports an event for a task.
+external void _reportTaskEvent(int start, int taskId, String phase,
+ String category, String name, String argumentsAsJson);
+
+/// Reports a complete synchronous event.
+external void _reportCompleteEvent(int start, int startCpu, String category,
+ String name, String argumentsAsJson);
+
+/// Reports a flow event.
+external void _reportFlowEvent(int start, int startCpu, String category,
+ String name, int type, int id, String argumentsAsJson);
+
+/// Reports an instant event.
+external void _reportInstantEvent(
+ int start, String category, String name, String argumentsAsJson);
diff --git a/sdk_nnbd/lib/ffi/annotations.dart b/sdk_nnbd/lib/ffi/annotations.dart
new file mode 100644
index 0000000..d246b56
--- /dev/null
+++ b/sdk_nnbd/lib/ffi/annotations.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.ffi;
+
+class DartRepresentationOf {
+ /// Represents the Dart type corresponding to a [NativeType].
+ ///
+ /// [Int8] -> [int]
+ /// [Int16] -> [int]
+ /// [Int32] -> [int]
+ /// [Int64] -> [int]
+ /// [Uint8] -> [int]
+ /// [Uint16] -> [int]
+ /// [Uint32] -> [int]
+ /// [Uint64] -> [int]
+ /// [IntPtr] -> [int]
+ /// [Double] -> [double]
+ /// [Float] -> [double]
+ /// [Pointer]<T> -> [Pointer]<T>
+ /// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
+ /// where DartRepresentationOf(Tn) -> Sn
+ /// T extends Struct<T> -> T
+ const DartRepresentationOf(String nativeType);
+}
+
+class Unsized {
+ const Unsized();
+}
+
+/// This [NativeType] does not have predefined size.
+///
+/// Unsized NativeTypes do not support [sizeOf] because their size is unknown.
+/// Consequently, [allocate], [Pointer.load], [Pointer.store], and
+/// [Pointer.elementAt] are not available.
+const unsized = const Unsized();
diff --git a/sdk_nnbd/lib/ffi/dynamic_library.dart b/sdk_nnbd/lib/ffi/dynamic_library.dart
new file mode 100644
index 0000000..ec68eeb
--- /dev/null
+++ b/sdk_nnbd/lib/ffi/dynamic_library.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.ffi;
+
+/// Represents a dynamically loaded C library.
+class DynamicLibrary {
+ /// Creates a dynamic library holding all global symbols.
+ ///
+ /// Any symbol in a library currently loaded with global visibility (including
+ /// the executable itself) may be resolved in this library.
+ ///
+ /// This feature is not available on Windows, instead an exception is thrown.
+ external factory DynamicLibrary.process();
+
+ /// Creates a dynamic library representing the running executable.
+ external factory DynamicLibrary.executable();
+
+ /// Loads a dynamic library file with local visibility.
+ ///
+ /// Throws an [ArgumentError] if loading the dynamic library fails.
+ external factory DynamicLibrary.open(String name);
+
+ /// Looks up a symbol in the [DynamicLibrary] and returns its address in
+ /// memory. Equivalent of dlsym.
+ ///
+ /// Throws an [ArgumentError] if it fails to lookup the symbol.
+ external Pointer<T> lookup<T extends NativeType>(String symbolName);
+
+ /// Helper that combines lookup and cast to a Dart function.
+ external F lookupFunction<T extends Function, F extends Function>(
+ String symbolName);
+
+ /// Dynamic libraries are equal if they load the same library.
+ external bool operator ==(other);
+
+ /// The hash code for a DynamicLibrary only depends on the loaded library
+ external int get hashCode;
+
+ /// The handle to the dynamic library.
+ external Pointer<Void> get handle;
+}
diff --git a/sdk_nnbd/lib/ffi/ffi.dart b/sdk_nnbd/lib/ffi/ffi.dart
new file mode 100644
index 0000000..a975a13
--- /dev/null
+++ b/sdk_nnbd/lib/ffi/ffi.dart
@@ -0,0 +1,144 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+/**
+ * Foreign Function Interface for interoperability with the C programming language.
+ *
+ * **NOTE**: Dart:FFI is in technical preview. The overall feature is incomplete,
+ * may contain issues, and breaking API changes are still expected.
+ *
+ * For further details, please see: https://dart.dev/server/c-interop
+ *
+ * {@category VM}
+ */
+library dart.ffi;
+
+import 'dart:typed_data' show TypedData;
+
+part "native_type.dart";
+part "annotations.dart";
+part "dynamic_library.dart";
+part "struct.dart";
+
+/// Number of bytes used by native type T.
+///
+/// Includes padding and alignment of structs.
+external int sizeOf<T extends NativeType>();
+
+/// Represents a pointer into the native C memory.
+final Pointer<Void> nullptr = Pointer.fromAddress(0);
+
+/// Represents a pointer into the native C memory. Cannot be extended.
+@pragma("vm:entry-point")
+class Pointer<T extends NativeType> extends NativeType {
+ /// Allocate [count] elements of type [T] on the native heap via malloc() and
+ /// return a pointer to the newly allocated memory.
+ ///
+ /// Note that the memory is uninitialized.
+ external factory Pointer.allocate({int count: 1});
+
+ /// Construction from raw integer.
+ external factory Pointer.fromAddress(int ptr);
+
+ /// Convert Dart function to a C function pointer, automatically marshalling
+ /// the arguments and return value
+ ///
+ /// If an exception is thrown while calling `f()`, the native function will
+ /// return `exceptionalReturn`, which must be assignable to return type of `f`.
+ ///
+ /// The returned function address can only be invoked on the mutator (main)
+ /// thread of the current isolate. It will abort the process if invoked on any
+ /// other thread.
+ ///
+ /// The pointer returned will remain alive for the duration of the current
+ /// isolate's lifetime. After the isolate it was created in is terminated,
+ /// invoking it from native code will cause undefined behavior.
+ ///
+ /// Does not accept dynamic invocations -- where the type of the receiver is
+ /// [dynamic].
+ external static Pointer<NativeFunction<T>> fromFunction<T extends Function>(
+ @DartRepresentationOf("T") Function f,
+ [Object exceptionalReturn]);
+
+ /// Store a Dart value into this location.
+ ///
+ /// The [value] is automatically marshalled into its native representation.
+ /// Note that ints which do not fit in [T] are truncated and sign extended,
+ /// and doubles stored into Pointer<[Float]> lose precision.
+ external void store(@DartRepresentationOf("T") Object value);
+
+ /// Load a Dart value from this location.
+ ///
+ /// The value is automatically unmarshalled from its native representation.
+ /// Loading a [Struct] reference returns a reference backed by native memory
+ /// (the same pointer as it's loaded from).
+ external R load<@DartRepresentationOf("T") R>();
+
+ /// Access to the raw pointer value.
+ /// On 32-bit systems, the upper 32-bits of the result are 0.
+ external int get address;
+
+ /// Pointer arithmetic (takes element size into account).
+ external Pointer<T> elementAt(int index);
+
+ /// Pointer arithmetic (byte offset).
+ // TODO(dacoharkes): remove this?
+ // https://github.com/dart-lang/sdk/issues/35883
+ external Pointer<T> offsetBy(int offsetInBytes);
+
+ /// Cast Pointer<T> to a Pointer<V>.
+ external Pointer<U> cast<U extends NativeType>();
+
+ /// Convert to Dart function, automatically marshalling the arguments
+ /// and return value.
+ ///
+ /// Can only be called on [Pointer]<[NativeFunction]>. Does not accept dynamic
+ /// invocations -- where the type of the receiver is [dynamic].
+ external R asFunction<@DartRepresentationOf("T") R extends Function>();
+
+ /// Free memory on the C heap pointed to by this pointer with free().
+ ///
+ /// Note that this zeros out the address.
+ external void free();
+
+ /// Creates an *external* typed data array backed by this pointer.
+ ///
+ /// The typed data array returned is only valid for as long as the backing
+ /// [Pointer]. Accessing any element of the type data array after this
+ /// [Pointer] has been [Pointer.free()]d will cause undefined behavior.
+ ///
+ /// Since [Pointer]s do not know their length, the size of the typed data is
+ /// controlled by `count`, in units of the size of the native type for this
+ /// [Pointer] (similarly to [Pointer.allocate]).
+ ///
+ /// The kind of TypedData produced depends on the native type:
+ ///
+ /// Pointer<Int8> -> Int8List
+ /// Pointer<Uint8> -> Uint8List
+ /// etc. up to Int64/Uint64
+ /// Pointer<IntPtr> -> Int32List/Int64List depending on platform word size
+ /// Pointer<Float> -> Float32List
+ /// Pointer<Double> -> Float64List
+ ///
+ /// Creation of a [Uint8ClampedList] is not supported. Creation of a typed
+ /// data from a [Pointer] to any other native type is not supported.
+ ///
+ /// The pointer must be aligned to a multiple of the native type's size.
+ //
+ // TODO(37773): Use extension methods to articulate more precise return types.
+ // We should still keep this member though as a generic way to access a
+ // Pointer of unknown type.
+ external TypedData asExternalTypedData({int count: 1});
+
+ /// Equality for Pointers only depends on their address.
+ bool operator ==(other) {
+ if (other == null) return false;
+ return address == other.address;
+ }
+
+ /// The hash code for a Pointer only depends on its address.
+ int get hashCode {
+ return address.hashCode;
+ }
+}
diff --git a/sdk_nnbd/lib/ffi/ffi_sources.gni b/sdk_nnbd/lib/ffi/ffi_sources.gni
new file mode 100644
index 0000000..d2bb279
--- /dev/null
+++ b/sdk_nnbd/lib/ffi/ffi_sources.gni
@@ -0,0 +1,13 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+ffi_sdk_sources = [
+ "ffi.dart",
+
+ # The above file needs to be first as it lists the parts below.
+ "annotations.dart",
+ "dynamic_library.dart",
+ "native_type.dart",
+ "struct.dart"
+]
diff --git a/sdk_nnbd/lib/ffi/native_type.dart b/sdk_nnbd/lib/ffi/native_type.dart
new file mode 100644
index 0000000..aa30e63
--- /dev/null
+++ b/sdk_nnbd/lib/ffi/native_type.dart
@@ -0,0 +1,131 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.ffi;
+
+/// [NativeType]'s subtypes represent a native type in C.
+///
+/// [NativeType]'s subtypes are not constructible in the Dart code and serve
+/// purely as markers in type signatures.
+abstract class NativeType {
+ const NativeType();
+}
+
+/// [_NativeInteger]'s subtypes represent a native integer in C.
+///
+/// [_NativeInteger]'s subtypes are not constructible in the Dart code and serve
+/// purely as markers in type signatures.
+class _NativeInteger extends NativeType {
+ const _NativeInteger();
+}
+
+/// [_NativeDouble]'s subtypes represent a native float or double in C.
+///
+/// [_NativeDouble]'s subtypes are not constructible in the Dart code and serve
+/// purely as markers in type signatures.
+class _NativeDouble extends NativeType {
+ const _NativeDouble();
+}
+
+/// Represents a native signed 8 bit integer in C.
+///
+/// [Int8] is not constructible in the Dart code and serves purely as marker in
+/// type signatures.
+class Int8 extends _NativeInteger {
+ const Int8();
+}
+
+/// Represents a native signed 16 bit integer in C.
+///
+/// [Int16] is not constructible in the Dart code and serves purely as marker in
+/// type signatures.
+class Int16 extends _NativeInteger {
+ const Int16();
+}
+
+/// Represents a native signed 32 bit integer in C.
+///
+/// [Int32] is not constructible in the Dart code and serves purely as marker in
+/// type signatures.
+class Int32 extends _NativeInteger {
+ const Int32();
+}
+
+/// Represents a native signed 64 bit integer in C.
+///
+/// [Int64] is not constructible in the Dart code and serves purely as marker in
+/// type signatures.
+class Int64 extends _NativeInteger {
+ const Int64();
+}
+
+/// Represents a native unsigned 8 bit integer in C.
+///
+/// [Uint8] is not constructible in the Dart code and serves purely as marker in
+/// type signatures.
+class Uint8 extends _NativeInteger {
+ const Uint8();
+}
+
+/// Represents a native unsigned 16 bit integer in C.
+///
+/// [Uint16] is not constructible in the Dart code and serves purely as marker
+/// in type signatures.
+class Uint16 extends _NativeInteger {
+ const Uint16();
+}
+
+/// Represents a native unsigned 32 bit integer in C.
+///
+/// [Uint32] is not constructible in the Dart code and serves purely as marker
+/// in type signatures.
+class Uint32 extends _NativeInteger {
+ const Uint32();
+}
+
+/// Represents a native unsigned 64 bit integer in C.
+///
+/// [Uint64] is not constructible in the Dart code and serves purely as marker
+/// in type signatures.
+class Uint64 extends _NativeInteger {
+ const Uint64();
+}
+
+/// Represents a native pointer-sized integer in C.
+///
+/// [IntPtr] is not constructible in the Dart code and serves purely as marker
+/// in type signatures.
+class IntPtr extends _NativeInteger {
+ const IntPtr();
+}
+
+/// Represents a native 32 bit float in C.
+///
+/// [Float] is not constructible in the Dart code and serves purely as marker
+/// in type signatures.
+class Float extends _NativeDouble {
+ const Float();
+}
+
+/// Represents a native 64 bit double in C.
+///
+/// [Double] is not constructible in the Dart code and serves purely as marker
+/// in type signatures.
+class Double extends _NativeDouble {
+ const Double();
+}
+
+/// Represents a void type in C.
+///
+/// [Void] is not constructible in the Dart code and serves purely as marker in
+/// type signatures.
+@unsized
+abstract class Void extends NativeType {}
+
+/// Represents a function type in C.
+///
+/// [NativeFunction] is not constructible in the Dart code and serves purely as
+/// marker in type signatures.
+@unsized
+abstract class NativeFunction<T extends Function> extends NativeType {}
diff --git a/sdk_nnbd/lib/ffi/struct.dart b/sdk_nnbd/lib/ffi/struct.dart
new file mode 100644
index 0000000..23124eb
--- /dev/null
+++ b/sdk_nnbd/lib/ffi/struct.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.ffi;
+
+/// This class is extended to define structs.
+///
+/// Fields in a struct, annotated with a subtype of [NativeType], are
+/// automatically transformed into wrappers to access the fields of the struct
+/// in native memory.
+///
+/// All fields in a struct must either have a type which extends [NativeType] or
+/// else have an annotation indicating the corresponding native type (e.g.
+/// "@Int32()" for "int").
+///
+/// Instances of a subclass of [Struct] have reference semantics and are backed
+/// by native memory. The may allocated via [Pointer.allocate] or loaded from a
+/// [Pointer], but not by a generative constructor.
+abstract class Struct<S extends NativeType> extends NativeType {
+ /// Returns the address backing the reference.
+ final Pointer<S> addressOf;
+
+ Struct() : addressOf = null;
+ Struct.fromPointer(this.addressOf);
+}
diff --git a/sdk_nnbd/lib/html/dart2js/html_dart2js.dart b/sdk_nnbd/lib/html/dart2js/html_dart2js.dart
new file mode 100644
index 0000000..303ec9e
--- /dev/null
+++ b/sdk_nnbd/lib/html/dart2js/html_dart2js.dart
@@ -0,0 +1,39523 @@
+/**
+ * HTML elements and other resources for web-based applications that need to
+ * interact with the browser and the DOM (Document Object Model).
+ *
+ * This library includes DOM element types, CSS styling, local storage,
+ * media, speech, events, and more.
+ * To get started,
+ * check out the [Element] class, the base class for many of the HTML
+ * DOM types.
+ *
+ * For information on writing web apps with Dart, see https://webdev.dartlang.org.
+ *
+ * {@category Web}
+ */
+library dart.dom.html;
+
+import 'dart:async';
+import 'dart:collection' hide LinkedList, LinkedListEntry;
+import 'dart:_internal' hide Symbol;
+import 'dart:html_common';
+import 'dart:indexed_db';
+import "dart:convert";
+import 'dart:math';
+import 'dart:_native_typed_data';
+import 'dart:typed_data';
+import 'dart:svg' as svg;
+import 'dart:svg' show Matrix;
+import 'dart:svg' show SvgSvgElement;
+import 'dart:web_audio' as web_audio;
+import 'dart:web_audio' show AudioBuffer, AudioTrack, AudioTrackList;
+import 'dart:web_gl' as gl;
+import 'dart:web_gl' show RenderingContext, RenderingContext2;
+import 'dart:web_sql';
+import 'dart:_foreign_helper' show JS, JS_INTERCEPTOR_CONSTANT;
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:html library.
+
+// Not actually used, but imported since dart:html can generate these objects.
+import 'dart:_js_helper'
+ show
+ convertDartClosureToJS,
+ Creates,
+ JavaScriptIndexingBehavior,
+ JSName,
+ Native,
+ Returns,
+ ForceInline,
+ findDispatchTagForInterceptorClass,
+ setNativeSubclassDispatchRecord,
+ makeLeafDispatchRecord,
+ registerGlobalObject,
+ applyExtension;
+import 'dart:_interceptors'
+ show
+ Interceptor,
+ JavaScriptFunction,
+ JSExtendableArray,
+ JSUInt31,
+ findInterceptorConstructorForType,
+ findConstructorForNativeSubclassType,
+ getNativeInterceptor,
+ setDispatchProperty;
+
+export 'dart:math' show Rectangle, Point;
+export 'dart:_internal' show HttpStatus;
+
+/**
+ * Top-level container for a web page, which is usually a browser tab or window.
+ *
+ * Each web page loaded in the browser has its own [Window], which is a
+ * container for the web page.
+ *
+ * If the web page has any `<iframe>` elements, then each `<iframe>` has its own
+ * [Window] object, which is accessible only to that `<iframe>`.
+ *
+ * See also:
+ *
+ * * [Window](https://developer.mozilla.org/en-US/docs/Web/API/window) from MDN.
+ */
+Window get window => JS('Window', 'window');
+
+/**
+ * Root node for all content in a web page.
+ */
+HtmlDocument get document =>
+ JS('returns:HtmlDocument;depends:none;effects:none;gvn:true', 'document');
+
+// Supoort to convert JS Promise to a Dart Future.
+Future<T> promiseToFuture<T>(jsPromise) {
+ var completer = new Completer<T>();
+
+ var thenSuccessCode = (promiseValue) => completer.complete(promiseValue);
+ var thenErrorCode = (promiseError) => completer.completeError(promiseError);
+
+ JS("", "#.then(#, #)", jsPromise, convertDartClosureToJS(thenSuccessCode, 1),
+ convertDartClosureToJS(thenErrorCode, 1));
+
+ return completer.future;
+}
+
+// Supoort to convert JS Promise to a Dart Future<Map<String, dynamic>>. Each property of the JS
+// object is added to the Map as a key of type String with a value of type dynamic.
+Future<Map<String, dynamic>> promiseToFutureAsMap(jsPromise) {
+ var completer = new Completer<Map<String, dynamic>>();
+
+ var thenSuccessCode = (promiseValue) =>
+ completer.complete(convertNativeToDart_Dictionary(promiseValue));
+ var thenErrorCode = (promiseError) => completer.completeError(promiseError);
+
+ JS("", "#.then(#, #)", jsPromise, convertDartClosureToJS(thenSuccessCode, 1),
+ convertDartClosureToJS(thenErrorCode, 1));
+
+ return completer.future;
+}
+
+// Workaround for tags like <cite> that lack their own Element subclass --
+// Dart issue 1990.
+@Native("HTMLElement")
+class HtmlElement extends Element implements NoncedElement {
+ factory HtmlElement() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ HtmlElement.created() : super.created();
+
+ // From NoncedElement
+ String nonce;
+}
+
+/**
+ * Emitted for any setlike IDL entry needs a callback signature.
+ * Today there is only one.
+ */
+typedef void FontFaceSetForEachCallback(
+ FontFace fontFace, FontFace fontFaceAgain, FontFaceSet set);
+
+WorkerGlobalScope get _workerSelf => JS('WorkerGlobalScope', 'self');
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AbortPaymentEvent")
+class AbortPaymentEvent extends ExtendableEvent {
+ // To suppress missing implicit constructor warnings.
+ factory AbortPaymentEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AbortPaymentEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return AbortPaymentEvent._create_1(type, eventInitDict_1);
+ }
+ static AbortPaymentEvent _create_1(type, eventInitDict) => JS(
+ 'AbortPaymentEvent', 'new AbortPaymentEvent(#,#)', type, eventInitDict);
+
+ void respondWith(Future paymentAbortedResponse) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AbsoluteOrientationSensor")
+class AbsoluteOrientationSensor extends OrientationSensor {
+ // To suppress missing implicit constructor warnings.
+ factory AbsoluteOrientationSensor._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AbsoluteOrientationSensor([Map sensorOptions]) {
+ if (sensorOptions != null) {
+ var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+ return AbsoluteOrientationSensor._create_1(sensorOptions_1);
+ }
+ return AbsoluteOrientationSensor._create_2();
+ }
+ static AbsoluteOrientationSensor _create_1(sensorOptions) => JS(
+ 'AbsoluteOrientationSensor',
+ 'new AbsoluteOrientationSensor(#)',
+ sensorOptions);
+ static AbsoluteOrientationSensor _create_2() =>
+ JS('AbsoluteOrientationSensor', 'new AbsoluteOrientationSensor()');
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class AbstractWorker extends Interceptor implements EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory AbstractWorker._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [AbstractWorker].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /// Stream of `error` events handled by this [AbstractWorker].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Accelerometer")
+class Accelerometer extends Sensor {
+ // To suppress missing implicit constructor warnings.
+ factory Accelerometer._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory Accelerometer([Map sensorOptions]) {
+ if (sensorOptions != null) {
+ var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+ return Accelerometer._create_1(sensorOptions_1);
+ }
+ return Accelerometer._create_2();
+ }
+ static Accelerometer _create_1(sensorOptions) =>
+ JS('Accelerometer', 'new Accelerometer(#)', sensorOptions);
+ static Accelerometer _create_2() =>
+ JS('Accelerometer', 'new Accelerometer()');
+
+ final num x;
+
+ final num y;
+
+ final num z;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AccessibleNode")
+class AccessibleNode extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory AccessibleNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> accessibleClickEvent =
+ const EventStreamProvider<Event>('accessibleclick');
+
+ static const EventStreamProvider<Event> accessibleContextMenuEvent =
+ const EventStreamProvider<Event>('accessiblecontextmenu');
+
+ static const EventStreamProvider<Event> accessibleDecrementEvent =
+ const EventStreamProvider<Event>('accessibledecrement');
+
+ static const EventStreamProvider<Event> accessibleFocusEvent =
+ const EventStreamProvider<Event>('accessiblefocus');
+
+ static const EventStreamProvider<Event> accessibleIncrementEvent =
+ const EventStreamProvider<Event>('accessibleincrement');
+
+ static const EventStreamProvider<Event> accessibleScrollIntoViewEvent =
+ const EventStreamProvider<Event>('accessiblescrollintoview');
+
+ factory AccessibleNode() {
+ return AccessibleNode._create_1();
+ }
+ static AccessibleNode _create_1() =>
+ JS('AccessibleNode', 'new AccessibleNode()');
+
+ AccessibleNode activeDescendant;
+
+ bool atomic;
+
+ String autocomplete;
+
+ bool busy;
+
+ String checked;
+
+ int colCount;
+
+ int colIndex;
+
+ int colSpan;
+
+ AccessibleNodeList controls;
+
+ String current;
+
+ AccessibleNodeList describedBy;
+
+ AccessibleNode details;
+
+ bool disabled;
+
+ AccessibleNode errorMessage;
+
+ bool expanded;
+
+ AccessibleNodeList flowTo;
+
+ String hasPopUp;
+
+ bool hidden;
+
+ String invalid;
+
+ String keyShortcuts;
+
+ String label;
+
+ AccessibleNodeList labeledBy;
+
+ int level;
+
+ String live;
+
+ bool modal;
+
+ bool multiline;
+
+ bool multiselectable;
+
+ String orientation;
+
+ AccessibleNodeList owns;
+
+ String placeholder;
+
+ int posInSet;
+
+ String pressed;
+
+ bool readOnly;
+
+ String relevant;
+
+ bool required;
+
+ String role;
+
+ String roleDescription;
+
+ int rowCount;
+
+ int rowIndex;
+
+ int rowSpan;
+
+ bool selected;
+
+ int setSize;
+
+ String sort;
+
+ num valueMax;
+
+ num valueMin;
+
+ num valueNow;
+
+ String valueText;
+
+ void appendChild(AccessibleNode child) native;
+
+ Stream<Event> get onAccessibleClick => accessibleClickEvent.forTarget(this);
+
+ Stream<Event> get onAccessibleContextMenu =>
+ accessibleContextMenuEvent.forTarget(this);
+
+ Stream<Event> get onAccessibleDecrement =>
+ accessibleDecrementEvent.forTarget(this);
+
+ Stream<Event> get onAccessibleFocus => accessibleFocusEvent.forTarget(this);
+
+ Stream<Event> get onAccessibleIncrement =>
+ accessibleIncrementEvent.forTarget(this);
+
+ Stream<Event> get onAccessibleScrollIntoView =>
+ accessibleScrollIntoViewEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AccessibleNodeList")
+class AccessibleNodeList extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AccessibleNodeList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AccessibleNodeList([List<AccessibleNode> nodes]) {
+ if (nodes != null) {
+ return AccessibleNodeList._create_1(nodes);
+ }
+ return AccessibleNodeList._create_2();
+ }
+ static AccessibleNodeList _create_1(nodes) =>
+ JS('AccessibleNodeList', 'new AccessibleNodeList(#)', nodes);
+ static AccessibleNodeList _create_2() =>
+ JS('AccessibleNodeList', 'new AccessibleNodeList()');
+
+ int length;
+
+ void __setter__(int index, AccessibleNode node) native;
+
+ void add(AccessibleNode node, AccessibleNode before) native;
+
+ AccessibleNode item(int index) native;
+
+ void remove(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AmbientLightSensor")
+class AmbientLightSensor extends Sensor {
+ // To suppress missing implicit constructor warnings.
+ factory AmbientLightSensor._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AmbientLightSensor([Map sensorOptions]) {
+ if (sensorOptions != null) {
+ var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+ return AmbientLightSensor._create_1(sensorOptions_1);
+ }
+ return AmbientLightSensor._create_2();
+ }
+ static AmbientLightSensor _create_1(sensorOptions) =>
+ JS('AmbientLightSensor', 'new AmbientLightSensor(#)', sensorOptions);
+ static AmbientLightSensor _create_2() =>
+ JS('AmbientLightSensor', 'new AmbientLightSensor()');
+
+ final num illuminance;
+}
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLAnchorElement")
+class AnchorElement extends HtmlElement implements HtmlHyperlinkElementUtils {
+ // To suppress missing implicit constructor warnings.
+ factory AnchorElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AnchorElement({String href}) {
+ AnchorElement e = JS('returns:AnchorElement;creates:AnchorElement;new:true',
+ '#.createElement(#)', document, "a");
+ if (href != null) e.href = href;
+ return e;
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ AnchorElement.created() : super.created();
+
+ String download;
+
+ String hreflang;
+
+ String referrerPolicy;
+
+ String rel;
+
+ String target;
+
+ String type;
+
+ // From HTMLHyperlinkElementUtils
+
+ String hash;
+
+ String host;
+
+ String hostname;
+
+ String href;
+
+ final String origin;
+
+ String password;
+
+ String pathname;
+
+ String port;
+
+ String protocol;
+
+ String search;
+
+ String username;
+
+ String toString() => JS('String', 'String(#)', this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Animation")
+class Animation extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory Animation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> cancelEvent =
+ const EventStreamProvider<Event>('cancel');
+
+ static const EventStreamProvider<Event> finishEvent =
+ const EventStreamProvider<Event>('finish');
+
+ factory Animation(
+ [AnimationEffectReadOnly effect, AnimationTimeline timeline]) {
+ if (timeline != null) {
+ return Animation._create_1(effect, timeline);
+ }
+ if (effect != null) {
+ return Animation._create_2(effect);
+ }
+ return Animation._create_3();
+ }
+ static Animation _create_1(effect, timeline) =>
+ JS('Animation', 'new Animation(#,#)', effect, timeline);
+ static Animation _create_2(effect) =>
+ JS('Animation', 'new Animation(#)', effect);
+ static Animation _create_3() => JS('Animation', 'new Animation()');
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => JS('bool', '!!(document.body.animate)');
+
+ num currentTime;
+
+ AnimationEffectReadOnly effect;
+
+ Future<Animation> get finished =>
+ promiseToFuture<Animation>(JS("", "#.finished", this));
+
+ String id;
+
+ final String playState;
+
+ num playbackRate;
+
+ Future<Animation> get ready =>
+ promiseToFuture<Animation>(JS("", "#.ready", this));
+
+ num startTime;
+
+ final AnimationTimeline timeline;
+
+ void cancel() native;
+
+ void finish() native;
+
+ void pause() native;
+
+ void play() native;
+
+ void reverse() native;
+
+ Stream<Event> get onCancel => cancelEvent.forTarget(this);
+
+ Stream<Event> get onFinish => finishEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationEffectReadOnly")
+class AnimationEffectReadOnly extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimationEffectReadOnly._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final AnimationEffectTimingReadOnly timing;
+
+ Map getComputedTiming() {
+ return convertNativeToDart_Dictionary(_getComputedTiming_1());
+ }
+
+ @JSName('getComputedTiming')
+ _getComputedTiming_1() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationEffectTiming")
+class AnimationEffectTiming extends AnimationEffectTimingReadOnly {
+ // To suppress missing implicit constructor warnings.
+ factory AnimationEffectTiming._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ // Shadowing definition.
+ num get delay => JS("num", "#.delay", this);
+
+ set delay(num value) {
+ JS("void", "#.delay = #", this, value);
+ }
+
+ // Shadowing definition.
+ String get direction => JS("String", "#.direction", this);
+
+ set direction(String value) {
+ JS("void", "#.direction = #", this, value);
+ }
+
+ // Shadowing definition.
+ Object get duration => JS("Object", "#.duration", this);
+
+ set duration(Object value) {
+ JS("void", "#.duration = #", this, value);
+ }
+
+ // Shadowing definition.
+ String get easing => JS("String", "#.easing", this);
+
+ set easing(String value) {
+ JS("void", "#.easing = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get endDelay => JS("num", "#.endDelay", this);
+
+ set endDelay(num value) {
+ JS("void", "#.endDelay = #", this, value);
+ }
+
+ // Shadowing definition.
+ String get fill => JS("String", "#.fill", this);
+
+ set fill(String value) {
+ JS("void", "#.fill = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get iterationStart => JS("num", "#.iterationStart", this);
+
+ set iterationStart(num value) {
+ JS("void", "#.iterationStart = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get iterations => JS("num", "#.iterations", this);
+
+ set iterations(num value) {
+ JS("void", "#.iterations = #", this, value);
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationEffectTimingReadOnly")
+class AnimationEffectTimingReadOnly extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimationEffectTimingReadOnly._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num delay;
+
+ final String direction;
+
+ final Object duration;
+
+ final String easing;
+
+ final num endDelay;
+
+ final String fill;
+
+ final num iterationStart;
+
+ final num iterations;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationEvent")
+class AnimationEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory AnimationEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AnimationEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return AnimationEvent._create_1(type, eventInitDict_1);
+ }
+ return AnimationEvent._create_2(type);
+ }
+ static AnimationEvent _create_1(type, eventInitDict) =>
+ JS('AnimationEvent', 'new AnimationEvent(#,#)', type, eventInitDict);
+ static AnimationEvent _create_2(type) =>
+ JS('AnimationEvent', 'new AnimationEvent(#)', type);
+
+ final String animationName;
+
+ final num elapsedTime;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationPlaybackEvent")
+class AnimationPlaybackEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory AnimationPlaybackEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AnimationPlaybackEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return AnimationPlaybackEvent._create_1(type, eventInitDict_1);
+ }
+ return AnimationPlaybackEvent._create_2(type);
+ }
+ static AnimationPlaybackEvent _create_1(type, eventInitDict) => JS(
+ 'AnimationPlaybackEvent',
+ 'new AnimationPlaybackEvent(#,#)',
+ type,
+ eventInitDict);
+ static AnimationPlaybackEvent _create_2(type) =>
+ JS('AnimationPlaybackEvent', 'new AnimationPlaybackEvent(#)', type);
+
+ final num currentTime;
+
+ final num timelineTime;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationTimeline")
+class AnimationTimeline extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimationTimeline._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num currentTime;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnimationWorkletGlobalScope")
+class AnimationWorkletGlobalScope extends WorkletGlobalScope {
+ // To suppress missing implicit constructor warnings.
+ factory AnimationWorkletGlobalScope._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void registerAnimator(String name, Object animatorConstructor) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * ApplicationCache is accessed via [Window.applicationCache].
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.OPERA)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("ApplicationCache,DOMApplicationCache,OfflineResourceList")
+class ApplicationCache extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory ApplicationCache._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `cached` events to event
+ * handlers that are not necessarily instances of [ApplicationCache].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> cachedEvent =
+ const EventStreamProvider<Event>('cached');
+
+ /**
+ * Static factory designed to expose `checking` events to event
+ * handlers that are not necessarily instances of [ApplicationCache].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> checkingEvent =
+ const EventStreamProvider<Event>('checking');
+
+ /**
+ * Static factory designed to expose `downloading` events to event
+ * handlers that are not necessarily instances of [ApplicationCache].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> downloadingEvent =
+ const EventStreamProvider<Event>('downloading');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [ApplicationCache].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /**
+ * Static factory designed to expose `noupdate` events to event
+ * handlers that are not necessarily instances of [ApplicationCache].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> noUpdateEvent =
+ const EventStreamProvider<Event>('noupdate');
+
+ /**
+ * Static factory designed to expose `obsolete` events to event
+ * handlers that are not necessarily instances of [ApplicationCache].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> obsoleteEvent =
+ const EventStreamProvider<Event>('obsolete');
+
+ /**
+ * Static factory designed to expose `progress` events to event
+ * handlers that are not necessarily instances of [ApplicationCache].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> progressEvent =
+ const EventStreamProvider<ProgressEvent>('progress');
+
+ /**
+ * Static factory designed to expose `updateready` events to event
+ * handlers that are not necessarily instances of [ApplicationCache].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> updateReadyEvent =
+ const EventStreamProvider<Event>('updateready');
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => JS('bool', '!!(window.applicationCache)');
+
+ static const int CHECKING = 2;
+
+ static const int DOWNLOADING = 3;
+
+ static const int IDLE = 1;
+
+ static const int OBSOLETE = 5;
+
+ static const int UNCACHED = 0;
+
+ static const int UPDATEREADY = 4;
+
+ final int status;
+
+ void abort() native;
+
+ void swapCache() native;
+
+ void update() native;
+
+ /// Stream of `cached` events handled by this [ApplicationCache].
+ Stream<Event> get onCached => cachedEvent.forTarget(this);
+
+ /// Stream of `checking` events handled by this [ApplicationCache].
+ Stream<Event> get onChecking => checkingEvent.forTarget(this);
+
+ /// Stream of `downloading` events handled by this [ApplicationCache].
+ Stream<Event> get onDownloading => downloadingEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [ApplicationCache].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `noupdate` events handled by this [ApplicationCache].
+ Stream<Event> get onNoUpdate => noUpdateEvent.forTarget(this);
+
+ /// Stream of `obsolete` events handled by this [ApplicationCache].
+ Stream<Event> get onObsolete => obsoleteEvent.forTarget(this);
+
+ /// Stream of `progress` events handled by this [ApplicationCache].
+ Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
+
+ /// Stream of `updateready` events handled by this [ApplicationCache].
+ Stream<Event> get onUpdateReady => updateReadyEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ApplicationCacheErrorEvent")
+class ApplicationCacheErrorEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory ApplicationCacheErrorEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ApplicationCacheErrorEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return ApplicationCacheErrorEvent._create_1(type, eventInitDict_1);
+ }
+ return ApplicationCacheErrorEvent._create_2(type);
+ }
+ static ApplicationCacheErrorEvent _create_1(type, eventInitDict) => JS(
+ 'ApplicationCacheErrorEvent',
+ 'new ApplicationCacheErrorEvent(#,#)',
+ type,
+ eventInitDict);
+ static ApplicationCacheErrorEvent _create_2(type) => JS(
+ 'ApplicationCacheErrorEvent', 'new ApplicationCacheErrorEvent(#)', type);
+
+ final String message;
+
+ final String reason;
+
+ final int status;
+
+ final String url;
+}
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * DOM Area Element, which links regions of an image map with a hyperlink.
+ *
+ * The element can also define an uninteractive region of the map.
+ *
+ * See also:
+ *
+ * * [`<area>`](https://developer.mozilla.org/en-US/docs/HTML/Element/area)
+ * on MDN.
+ */
+@Native("HTMLAreaElement")
+class AreaElement extends HtmlElement implements HtmlHyperlinkElementUtils {
+ // To suppress missing implicit constructor warnings.
+ factory AreaElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AreaElement() => JS(
+ 'returns:AreaElement;creates:AreaElement;new:true',
+ '#.createElement(#)',
+ document,
+ "area");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ AreaElement.created() : super.created();
+
+ String alt;
+
+ String coords;
+
+ String download;
+
+ String referrerPolicy;
+
+ String rel;
+
+ String shape;
+
+ String target;
+
+ // From HTMLHyperlinkElementUtils
+
+ String hash;
+
+ String host;
+
+ String hostname;
+
+ String href;
+
+ final String origin;
+
+ String password;
+
+ String pathname;
+
+ String port;
+
+ String protocol;
+
+ String search;
+
+ String username;
+
+ String toString() => JS('String', 'String(#)', this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLAudioElement")
+class AudioElement extends MediaElement {
+ factory AudioElement._([String src]) {
+ if (src != null) {
+ return AudioElement._create_1(src);
+ }
+ return AudioElement._create_2();
+ }
+ static AudioElement _create_1(src) => JS('AudioElement', 'new Audio(#)', src);
+ static AudioElement _create_2() => JS('AudioElement', 'new Audio()');
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ AudioElement.created() : super.created();
+
+ factory AudioElement([String src]) => new AudioElement._(src);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AuthenticatorAssertionResponse")
+class AuthenticatorAssertionResponse extends AuthenticatorResponse {
+ // To suppress missing implicit constructor warnings.
+ factory AuthenticatorAssertionResponse._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final ByteBuffer authenticatorData;
+
+ final ByteBuffer signature;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AuthenticatorAttestationResponse")
+class AuthenticatorAttestationResponse extends AuthenticatorResponse {
+ // To suppress missing implicit constructor warnings.
+ factory AuthenticatorAttestationResponse._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final ByteBuffer attestationObject;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AuthenticatorResponse")
+class AuthenticatorResponse extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AuthenticatorResponse._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('clientDataJSON')
+ final ByteBuffer clientDataJson;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLBRElement")
+class BRElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory BRElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory BRElement() => JS('returns:BRElement;creates:BRElement;new:true',
+ '#.createElement(#)', document, "br");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ BRElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchClickEvent")
+class BackgroundFetchClickEvent extends BackgroundFetchEvent {
+ // To suppress missing implicit constructor warnings.
+ factory BackgroundFetchClickEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory BackgroundFetchClickEvent(String type, Map init) {
+ var init_1 = convertDartToNative_Dictionary(init);
+ return BackgroundFetchClickEvent._create_1(type, init_1);
+ }
+ static BackgroundFetchClickEvent _create_1(type, init) => JS(
+ 'BackgroundFetchClickEvent',
+ 'new BackgroundFetchClickEvent(#,#)',
+ type,
+ init);
+
+ final String state;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchEvent")
+class BackgroundFetchEvent extends ExtendableEvent {
+ // To suppress missing implicit constructor warnings.
+ factory BackgroundFetchEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory BackgroundFetchEvent(String type, Map init) {
+ var init_1 = convertDartToNative_Dictionary(init);
+ return BackgroundFetchEvent._create_1(type, init_1);
+ }
+ static BackgroundFetchEvent _create_1(type, init) =>
+ JS('BackgroundFetchEvent', 'new BackgroundFetchEvent(#,#)', type, init);
+
+ final String id;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchFailEvent")
+class BackgroundFetchFailEvent extends BackgroundFetchEvent {
+ // To suppress missing implicit constructor warnings.
+ factory BackgroundFetchFailEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory BackgroundFetchFailEvent(String type, Map init) {
+ var init_1 = convertDartToNative_Dictionary(init);
+ return BackgroundFetchFailEvent._create_1(type, init_1);
+ }
+ static BackgroundFetchFailEvent _create_1(type, init) => JS(
+ 'BackgroundFetchFailEvent',
+ 'new BackgroundFetchFailEvent(#,#)',
+ type,
+ init);
+
+ final List<BackgroundFetchSettledFetch> fetches;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchFetch")
+class BackgroundFetchFetch extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory BackgroundFetchFetch._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final _Request request;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchManager")
+class BackgroundFetchManager extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory BackgroundFetchManager._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future<BackgroundFetchRegistration> fetch(String id, Object requests,
+ [Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture<BackgroundFetchRegistration>(
+ JS("", "#.fetch(#, #, #)", this, id, requests, options_dict));
+ }
+
+ Future<BackgroundFetchRegistration> get(String id) =>
+ promiseToFuture<BackgroundFetchRegistration>(
+ JS("", "#.get(#)", this, id));
+
+ Future<List<String>> getIds() =>
+ promiseToFuture<List<String>>(JS("", "#.getIds()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchRegistration")
+class BackgroundFetchRegistration extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory BackgroundFetchRegistration._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int downloadTotal;
+
+ final int downloaded;
+
+ final String id;
+
+ final String title;
+
+ final int totalDownloadSize;
+
+ final int uploadTotal;
+
+ final int uploaded;
+
+ Future<bool> abort() => promiseToFuture<bool>(JS("", "#.abort()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchSettledFetch")
+class BackgroundFetchSettledFetch extends BackgroundFetchFetch {
+ // To suppress missing implicit constructor warnings.
+ factory BackgroundFetchSettledFetch._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory BackgroundFetchSettledFetch(_Request request, _Response response) {
+ return BackgroundFetchSettledFetch._create_1(request, response);
+ }
+ static BackgroundFetchSettledFetch _create_1(request, response) => JS(
+ 'BackgroundFetchSettledFetch',
+ 'new BackgroundFetchSettledFetch(#,#)',
+ request,
+ response);
+
+ final _Response response;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BackgroundFetchedEvent")
+class BackgroundFetchedEvent extends BackgroundFetchEvent {
+ // To suppress missing implicit constructor warnings.
+ factory BackgroundFetchedEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory BackgroundFetchedEvent(String type, Map init) {
+ var init_1 = convertDartToNative_Dictionary(init);
+ return BackgroundFetchedEvent._create_1(type, init_1);
+ }
+ static BackgroundFetchedEvent _create_1(type, init) => JS(
+ 'BackgroundFetchedEvent', 'new BackgroundFetchedEvent(#,#)', type, init);
+
+ final List<BackgroundFetchSettledFetch> fetches;
+
+ Future updateUI(String title) =>
+ promiseToFuture(JS("", "#.updateUI(#)", this, title));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#barprop
+@deprecated // standard
+@Native("BarProp")
+class BarProp extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory BarProp._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool visible;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BarcodeDetector")
+class BarcodeDetector extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory BarcodeDetector._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory BarcodeDetector() {
+ return BarcodeDetector._create_1();
+ }
+ static BarcodeDetector _create_1() =>
+ JS('BarcodeDetector', 'new BarcodeDetector()');
+
+ Future<List<DetectedBarcode>> detect(/*ImageBitmapSource*/ image) =>
+ promiseToFuture<List<DetectedBarcode>>(
+ JS("", "#.detect(#)", this, image));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLBaseElement")
+class BaseElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory BaseElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory BaseElement() => JS(
+ 'returns:BaseElement;creates:BaseElement;new:true',
+ '#.createElement(#)',
+ document,
+ "base");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ BaseElement.created() : super.created();
+
+ String href;
+
+ String target;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BatteryManager")
+class BatteryManager extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory BatteryManager._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool charging;
+
+ final num chargingTime;
+
+ final num dischargingTime;
+
+ final num level;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BeforeInstallPromptEvent")
+class BeforeInstallPromptEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory BeforeInstallPromptEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory BeforeInstallPromptEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return BeforeInstallPromptEvent._create_1(type, eventInitDict_1);
+ }
+ return BeforeInstallPromptEvent._create_2(type);
+ }
+ static BeforeInstallPromptEvent _create_1(type, eventInitDict) => JS(
+ 'BeforeInstallPromptEvent',
+ 'new BeforeInstallPromptEvent(#,#)',
+ type,
+ eventInitDict);
+ static BeforeInstallPromptEvent _create_2(type) =>
+ JS('BeforeInstallPromptEvent', 'new BeforeInstallPromptEvent(#)', type);
+
+ final List<String> platforms;
+
+ Future<Map<String, dynamic>> get userChoice =>
+ promiseToFutureAsMap(JS("", "#.userChoice", this));
+
+ Future prompt() => promiseToFuture(JS("", "#.prompt()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BeforeUnloadEvent")
+class BeforeUnloadEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory BeforeUnloadEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ // Shadowing definition.
+ String get returnValue => JS("String", "#.returnValue", this);
+
+ set returnValue(String value) {
+ JS("void", "#.returnValue = #", this, value);
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Blob")
+class Blob extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Blob._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int size;
+
+ final String type;
+
+ Blob slice([int start, int end, String contentType]) native;
+
+ factory Blob(List blobParts, [String type, String endings]) {
+ // TODO: validate that blobParts is a JS Array and convert if not.
+ // TODO: any coercions on the elements of blobParts, e.g. coerce a typed
+ // array to ArrayBuffer if it is a total view.
+ if (type == null && endings == null) {
+ return _create_1(blobParts);
+ }
+ var bag = _create_bag();
+ if (type != null) _bag_set(bag, 'type', type);
+ if (endings != null) _bag_set(bag, 'endings', endings);
+ return _create_2(blobParts, bag);
+ }
+
+ static _create_1(parts) => JS('Blob', 'new self.Blob(#)', parts);
+ static _create_2(parts, bag) => JS('Blob', 'new self.Blob(#, #)', parts, bag);
+
+ static _create_bag() => JS('var', '{}');
+ static _bag_set(bag, key, value) {
+ JS('void', '#[#] = #', bag, key, value);
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void BlobCallback(Blob blob);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BlobEvent")
+class BlobEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory BlobEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory BlobEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return BlobEvent._create_1(type, eventInitDict_1);
+ }
+ static BlobEvent _create_1(type, eventInitDict) =>
+ JS('BlobEvent', 'new BlobEvent(#,#)', type, eventInitDict);
+
+ final Blob data;
+
+ final num timecode;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothRemoteGATTDescriptor")
+class BluetoothRemoteGattDescriptor extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory BluetoothRemoteGattDescriptor._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final _BluetoothRemoteGATTCharacteristic characteristic;
+
+ final String uuid;
+
+ final ByteData value;
+
+ Future readValue() => promiseToFuture(JS("", "#.readValue()", this));
+
+ Future writeValue(/*BufferSource*/ value) =>
+ promiseToFuture(JS("", "#.writeValue(#)", this, value));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Body")
+class Body extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Body._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool bodyUsed;
+
+ Future arrayBuffer() => promiseToFuture(JS("", "#.arrayBuffer()", this));
+
+ Future<Blob> blob() => promiseToFuture<Blob>(JS("", "#.blob()", this));
+
+ Future<FormData> formData() =>
+ promiseToFuture<FormData>(JS("", "#.formData()", this));
+
+ Future json() => promiseToFuture(JS("", "#.json()", this));
+
+ Future<String> text() => promiseToFuture<String>(JS("", "#.text()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLBodyElement")
+class BodyElement extends HtmlElement implements WindowEventHandlers {
+ // To suppress missing implicit constructor warnings.
+ factory BodyElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `blur` events to event
+ * handlers that are not necessarily instances of [BodyElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> blurEvent =
+ const EventStreamProvider<Event>('blur');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [BodyElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /**
+ * Static factory designed to expose `focus` events to event
+ * handlers that are not necessarily instances of [BodyElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> focusEvent =
+ const EventStreamProvider<Event>('focus');
+
+ /**
+ * Static factory designed to expose `hashchange` events to event
+ * handlers that are not necessarily instances of [BodyElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> hashChangeEvent =
+ const EventStreamProvider<Event>('hashchange');
+
+ /**
+ * Static factory designed to expose `load` events to event
+ * handlers that are not necessarily instances of [BodyElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> loadEvent =
+ const EventStreamProvider<Event>('load');
+
+ /**
+ * Static factory designed to expose `message` events to event
+ * handlers that are not necessarily instances of [BodyElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ /**
+ * Static factory designed to expose `offline` events to event
+ * handlers that are not necessarily instances of [BodyElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> offlineEvent =
+ const EventStreamProvider<Event>('offline');
+
+ /**
+ * Static factory designed to expose `online` events to event
+ * handlers that are not necessarily instances of [BodyElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> onlineEvent =
+ const EventStreamProvider<Event>('online');
+
+ /**
+ * Static factory designed to expose `popstate` events to event
+ * handlers that are not necessarily instances of [BodyElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<PopStateEvent> popStateEvent =
+ const EventStreamProvider<PopStateEvent>('popstate');
+
+ /**
+ * Static factory designed to expose `resize` events to event
+ * handlers that are not necessarily instances of [BodyElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> resizeEvent =
+ const EventStreamProvider<Event>('resize');
+
+ static const EventStreamProvider<Event> scrollEvent =
+ const EventStreamProvider<Event>('scroll');
+
+ /**
+ * Static factory designed to expose `storage` events to event
+ * handlers that are not necessarily instances of [BodyElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<StorageEvent> storageEvent =
+ const EventStreamProvider<StorageEvent>('storage');
+
+ /**
+ * Static factory designed to expose `unload` events to event
+ * handlers that are not necessarily instances of [BodyElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> unloadEvent =
+ const EventStreamProvider<Event>('unload');
+
+ factory BodyElement() => JS(
+ 'returns:BodyElement;creates:BodyElement;new:true',
+ '#.createElement(#)',
+ document,
+ "body");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ BodyElement.created() : super.created();
+
+ /// Stream of `blur` events handled by this [BodyElement].
+ ElementStream<Event> get onBlur => blurEvent.forElement(this);
+
+ /// Stream of `error` events handled by this [BodyElement].
+ ElementStream<Event> get onError => errorEvent.forElement(this);
+
+ /// Stream of `focus` events handled by this [BodyElement].
+ ElementStream<Event> get onFocus => focusEvent.forElement(this);
+
+ /// Stream of `hashchange` events handled by this [BodyElement].
+ ElementStream<Event> get onHashChange => hashChangeEvent.forElement(this);
+
+ /// Stream of `load` events handled by this [BodyElement].
+ ElementStream<Event> get onLoad => loadEvent.forElement(this);
+
+ /// Stream of `message` events handled by this [BodyElement].
+ ElementStream<MessageEvent> get onMessage => messageEvent.forElement(this);
+
+ /// Stream of `offline` events handled by this [BodyElement].
+ ElementStream<Event> get onOffline => offlineEvent.forElement(this);
+
+ /// Stream of `online` events handled by this [BodyElement].
+ ElementStream<Event> get onOnline => onlineEvent.forElement(this);
+
+ /// Stream of `popstate` events handled by this [BodyElement].
+ ElementStream<PopStateEvent> get onPopState => popStateEvent.forElement(this);
+
+ /// Stream of `resize` events handled by this [BodyElement].
+ ElementStream<Event> get onResize => resizeEvent.forElement(this);
+
+ ElementStream<Event> get onScroll => scrollEvent.forElement(this);
+
+ /// Stream of `storage` events handled by this [BodyElement].
+ ElementStream<StorageEvent> get onStorage => storageEvent.forElement(this);
+
+ /// Stream of `unload` events handled by this [BodyElement].
+ ElementStream<Event> get onUnload => unloadEvent.forElement(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BroadcastChannel")
+class BroadcastChannel extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory BroadcastChannel._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ factory BroadcastChannel(String name) {
+ return BroadcastChannel._create_1(name);
+ }
+ static BroadcastChannel _create_1(name) =>
+ JS('BroadcastChannel', 'new BroadcastChannel(#)', name);
+
+ final String name;
+
+ void close() native;
+
+ void postMessage(Object message) native;
+
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BudgetState")
+class BudgetState extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory BudgetState._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num budgetAt;
+
+ final int time;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLButtonElement")
+class ButtonElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory ButtonElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ButtonElement() => JS(
+ 'returns:ButtonElement;creates:ButtonElement;new:true',
+ '#.createElement(#)',
+ document,
+ "button");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ButtonElement.created() : super.created();
+
+ bool autofocus;
+
+ bool disabled;
+
+ final FormElement form;
+
+ String formAction;
+
+ String formEnctype;
+
+ String formMethod;
+
+ bool formNoValidate;
+
+ String formTarget;
+
+ @Unstable()
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ final List<Node> labels;
+
+ String name;
+
+ String type;
+
+ final String validationMessage;
+
+ final ValidityState validity;
+
+ String value;
+
+ final bool willValidate;
+
+ bool checkValidity() native;
+
+ bool reportValidity() native;
+
+ void setCustomValidity(String error) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://dom.spec.whatwg.org/#cdatasection
+@deprecated // deprecated
+@Native("CDATASection")
+class CDataSection extends Text {
+ // To suppress missing implicit constructor warnings.
+ factory CDataSection._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CacheStorage")
+class CacheStorage extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CacheStorage._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future delete(String cacheName) =>
+ promiseToFuture(JS("", "#.delete(#)", this, cacheName));
+
+ Future has(String cacheName) =>
+ promiseToFuture(JS("", "#.has(#)", this, cacheName));
+
+ Future keys() => promiseToFuture(JS("", "#.keys()", this));
+
+ Future match(/*RequestInfo*/ request, [Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture(
+ JS("", "#.match(#, #)", this, request, options_dict));
+ }
+
+ Future open(String cacheName) =>
+ promiseToFuture(JS("", "#.open(#)", this, cacheName));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CanMakePaymentEvent")
+class CanMakePaymentEvent extends ExtendableEvent {
+ // To suppress missing implicit constructor warnings.
+ factory CanMakePaymentEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CanMakePaymentEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return CanMakePaymentEvent._create_1(type, eventInitDict_1);
+ }
+ static CanMakePaymentEvent _create_1(type, eventInitDict) => JS(
+ 'CanMakePaymentEvent',
+ 'new CanMakePaymentEvent(#,#)',
+ type,
+ eventInitDict);
+
+ final List methodData;
+
+ final List modifiers;
+
+ final String paymentRequestOrigin;
+
+ final String topLevelOrigin;
+
+ void respondWith(Future canMakePaymentResponse) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CanvasCaptureMediaStreamTrack")
+class CanvasCaptureMediaStreamTrack extends MediaStreamTrack {
+ // To suppress missing implicit constructor warnings.
+ factory CanvasCaptureMediaStreamTrack._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final CanvasElement canvas;
+
+ void requestFrame() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLCanvasElement")
+class CanvasElement extends HtmlElement implements CanvasImageSource {
+ // To suppress missing implicit constructor warnings.
+ factory CanvasElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `webglcontextlost` events to event
+ * handlers that are not necessarily instances of [CanvasElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<gl.ContextEvent> webGlContextLostEvent =
+ const EventStreamProvider<gl.ContextEvent>('webglcontextlost');
+
+ /**
+ * Static factory designed to expose `webglcontextrestored` events to event
+ * handlers that are not necessarily instances of [CanvasElement].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<gl.ContextEvent> webGlContextRestoredEvent =
+ const EventStreamProvider<gl.ContextEvent>('webglcontextrestored');
+
+ factory CanvasElement({int width, int height}) {
+ CanvasElement e = JS('returns:CanvasElement;creates:CanvasElement;new:true',
+ '#.createElement(#)', document, "canvas");
+ if (width != null) e.width = width;
+ if (height != null) e.height = height;
+ return e;
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ CanvasElement.created() : super.created();
+
+ /// The height of this canvas element in CSS pixels.
+ int height;
+
+ /// The width of this canvas element in CSS pixels.
+ int width;
+
+ MediaStream captureStream([num frameRate]) native;
+
+ @Creates('CanvasRenderingContext2D|RenderingContext|RenderingContext2')
+ @Returns('CanvasRenderingContext2D|RenderingContext|RenderingContext2|Null')
+ Object getContext(String contextId, [Map attributes]) {
+ if (attributes != null) {
+ var attributes_1 = convertDartToNative_Dictionary(attributes);
+ return _getContext_1(contextId, attributes_1);
+ }
+ return _getContext_2(contextId);
+ }
+
+ @JSName('getContext')
+ @Creates('CanvasRenderingContext2D|RenderingContext|RenderingContext2')
+ @Returns('CanvasRenderingContext2D|RenderingContext|RenderingContext2|Null')
+ Object _getContext_1(contextId, attributes) native;
+ @JSName('getContext')
+ @Creates('CanvasRenderingContext2D|RenderingContext|RenderingContext2')
+ @Returns('CanvasRenderingContext2D|RenderingContext|RenderingContext2|Null')
+ Object _getContext_2(contextId) native;
+
+ @JSName('toDataURL')
+ String _toDataUrl(String type, [arguments_OR_quality]) native;
+
+ OffscreenCanvas transferControlToOffscreen() native;
+
+ /// Stream of `webglcontextlost` events handled by this [CanvasElement].
+ ElementStream<gl.ContextEvent> get onWebGlContextLost =>
+ webGlContextLostEvent.forElement(this);
+
+ /// Stream of `webglcontextrestored` events handled by this [CanvasElement].
+ ElementStream<gl.ContextEvent> get onWebGlContextRestored =>
+ webGlContextRestoredEvent.forElement(this);
+
+ /** An API for drawing on this canvas. */
+ CanvasRenderingContext2D get context2D =>
+ JS('Null|CanvasRenderingContext2D', '#.getContext(#)', this, '2d');
+
+ /**
+ * Returns a new Web GL context for this canvas.
+ *
+ * ## Other resources
+ *
+ * * [WebGL fundamentals](http://www.html5rocks.com/en/tutorials/webgl/webgl_fundamentals/)
+ * from HTML5Rocks.
+ * * [WebGL homepage](http://get.webgl.org/).
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ gl.RenderingContext getContext3d(
+ {alpha: true,
+ depth: true,
+ stencil: false,
+ antialias: true,
+ premultipliedAlpha: true,
+ preserveDrawingBuffer: false}) {
+ var options = {
+ 'alpha': alpha,
+ 'depth': depth,
+ 'stencil': stencil,
+ 'antialias': antialias,
+ 'premultipliedAlpha': premultipliedAlpha,
+ 'preserveDrawingBuffer': preserveDrawingBuffer,
+ };
+ var context = getContext('webgl', options);
+ if (context == null) {
+ context = getContext('experimental-webgl', options);
+ }
+ return context;
+ }
+
+ /**
+ * Returns a data URI containing a representation of the image in the
+ * format specified by type (defaults to 'image/png').
+ *
+ * Data Uri format is as follow
+ * `data:[<MIME-type>][;charset=<encoding>][;base64],<data>`
+ *
+ * Optional parameter [quality] in the range of 0.0 and 1.0 can be used when
+ * requesting [type] 'image/jpeg' or 'image/webp'. If [quality] is not passed
+ * the default value is used. Note: the default value varies by browser.
+ *
+ * If the height or width of this canvas element is 0, then 'data:' is
+ * returned, representing no data.
+ *
+ * If the type requested is not 'image/png', and the returned value is
+ * 'data:image/png', then the requested type is not supported.
+ *
+ * Example usage:
+ *
+ * CanvasElement canvas = new CanvasElement();
+ * var ctx = canvas.context2D
+ * ..fillStyle = "rgb(200,0,0)"
+ * ..fillRect(10, 10, 55, 50);
+ * var dataUrl = canvas.toDataUrl("image/jpeg", 0.95);
+ * // The Data Uri would look similar to
+ * // 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
+ * // AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
+ * // 9TXL0Y4OHwAAAABJRU5ErkJggg=='
+ * //Create a new image element from the data URI.
+ * var img = new ImageElement();
+ * img.src = dataUrl;
+ * document.body.children.add(img);
+ *
+ * See also:
+ *
+ * * [Data URI Scheme](http://en.wikipedia.org/wiki/Data_URI_scheme) from Wikipedia.
+ *
+ * * [HTMLCanvasElement](https://developer.mozilla.org/en-US/docs/DOM/HTMLCanvasElement) from MDN.
+ *
+ * * [toDataUrl](http://dev.w3.org/html5/spec/the-canvas-element.html#dom-canvas-todataurl) from W3C.
+ */
+ String toDataUrl([String type = 'image/png', num quality]) =>
+ _toDataUrl(type, quality);
+
+ @JSName('toBlob')
+ void _toBlob(BlobCallback callback, String type, [Object arguments]) native;
+
+ Future<Blob> toBlob(String type, [Object arguments]) {
+ var completer = new Completer<Blob>();
+ _toBlob((value) {
+ completer.complete(value);
+ }, type, arguments);
+ return completer.future;
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An opaque canvas object representing a gradient.
+ *
+ * Created by calling [createLinearGradient] or [createRadialGradient] on a
+ * [CanvasRenderingContext2D] object.
+ *
+ * Example usage:
+ *
+ * var canvas = new CanvasElement(width: 600, height: 600);
+ * var ctx = canvas.context2D;
+ * ctx.clearRect(0, 0, 600, 600);
+ * ctx.save();
+ * // Create radial gradient.
+ * CanvasGradient gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, 600);
+ * gradient.addColorStop(0, '#000');
+ * gradient.addColorStop(1, 'rgb(255, 255, 255)');
+ * // Assign gradients to fill.
+ * ctx.fillStyle = gradient;
+ * // Draw a rectangle with a gradient fill.
+ * ctx.fillRect(0, 0, 600, 600);
+ * ctx.save();
+ * document.body.children.add(canvas);
+ *
+ * See also:
+ *
+ * * [CanvasGradient](https://developer.mozilla.org/en-US/docs/DOM/CanvasGradient) from MDN.
+ * * [CanvasGradient](https://html.spec.whatwg.org/multipage/scripting.html#canvasgradient)
+ * from WHATWG.
+ * * [CanvasGradient](http://www.w3.org/TR/2010/WD-2dcontext-20100304/#canvasgradient) from W3C.
+ */
+@Native("CanvasGradient")
+class CanvasGradient extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CanvasGradient._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Adds a color stop to this gradient at the offset.
+ *
+ * The [offset] can range between 0.0 and 1.0.
+ *
+ * See also:
+ *
+ * * [Multiple Color Stops](https://developer.mozilla.org/en-US/docs/CSS/linear-gradient#Gradient_with_multiple_color_stops) from MDN.
+ */
+ void addColorStop(num offset, String color) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An opaque object representing a pattern of image, canvas, or video.
+ *
+ * Created by calling [createPattern] on a [CanvasRenderingContext2D] object.
+ *
+ * Example usage:
+ *
+ * var canvas = new CanvasElement(width: 600, height: 600);
+ * var ctx = canvas.context2D;
+ * var img = new ImageElement();
+ * // Image src needs to be loaded before pattern is applied.
+ * img.onLoad.listen((event) {
+ * // When the image is loaded, create a pattern
+ * // from the ImageElement.
+ * CanvasPattern pattern = ctx.createPattern(img, 'repeat');
+ * ctx.rect(0, 0, canvas.width, canvas.height);
+ * ctx.fillStyle = pattern;
+ * ctx.fill();
+ * });
+ * img.src = "images/foo.jpg";
+ * document.body.children.add(canvas);
+ *
+ * See also:
+ * * [CanvasPattern](https://developer.mozilla.org/en-US/docs/DOM/CanvasPattern) from MDN.
+ * * [CanvasPattern](https://html.spec.whatwg.org/multipage/scripting.html#canvaspattern)
+ * from WHATWG.
+ * * [CanvasPattern](http://www.w3.org/TR/2010/WD-2dcontext-20100304/#canvaspattern) from W3C.
+ */
+@Native("CanvasPattern")
+class CanvasPattern extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CanvasPattern._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void setTransform(Matrix transform) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class CanvasRenderingContext {
+ CanvasElement get canvas;
+}
+
+@Native("CanvasRenderingContext2D")
+class CanvasRenderingContext2D extends Interceptor
+ implements CanvasRenderingContext {
+ // To suppress missing implicit constructor warnings.
+ factory CanvasRenderingContext2D._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final CanvasElement canvas;
+
+ Matrix currentTransform;
+
+ String direction;
+
+ @Creates('String|CanvasGradient|CanvasPattern')
+ @Returns('String|CanvasGradient|CanvasPattern')
+ Object fillStyle;
+
+ String filter;
+
+ String font;
+
+ num globalAlpha;
+
+ String globalCompositeOperation;
+
+ /**
+ * Whether images and patterns on this canvas will be smoothed when this
+ * canvas is scaled.
+ *
+ * ## Other resources
+ *
+ * * [Image
+ * smoothing](https://html.spec.whatwg.org/multipage/scripting.html#image-smoothing)
+ * from WHATWG.
+ */
+ bool imageSmoothingEnabled;
+
+ String imageSmoothingQuality;
+
+ String lineCap;
+
+ String lineJoin;
+
+ num lineWidth;
+
+ num miterLimit;
+
+ num shadowBlur;
+
+ String shadowColor;
+
+ num shadowOffsetX;
+
+ num shadowOffsetY;
+
+ @Creates('String|CanvasGradient|CanvasPattern')
+ @Returns('String|CanvasGradient|CanvasPattern')
+ Object strokeStyle;
+
+ String textAlign;
+
+ String textBaseline;
+
+ void addHitRegion([Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ _addHitRegion_1(options_1);
+ return;
+ }
+ _addHitRegion_2();
+ return;
+ }
+
+ @JSName('addHitRegion')
+ void _addHitRegion_1(options) native;
+ @JSName('addHitRegion')
+ void _addHitRegion_2() native;
+
+ void beginPath() native;
+
+ void clearHitRegions() native;
+
+ void clearRect(num x, num y, num width, num height) native;
+
+ void clip([path_OR_winding, String winding]) native;
+
+ @Creates('ImageData|=Object')
+ ImageData createImageData(data_OR_imagedata_OR_sw,
+ [int sh_OR_sw,
+ imageDataColorSettings_OR_sh,
+ Map imageDataColorSettings]) {
+ if ((data_OR_imagedata_OR_sw is ImageData) &&
+ sh_OR_sw == null &&
+ imageDataColorSettings_OR_sh == null &&
+ imageDataColorSettings == null) {
+ var imagedata_1 = convertDartToNative_ImageData(data_OR_imagedata_OR_sw);
+ return convertNativeToDart_ImageData(_createImageData_1(imagedata_1));
+ }
+ if (sh_OR_sw != null &&
+ (data_OR_imagedata_OR_sw is int) &&
+ imageDataColorSettings_OR_sh == null &&
+ imageDataColorSettings == null) {
+ return convertNativeToDart_ImageData(
+ _createImageData_2(data_OR_imagedata_OR_sw, sh_OR_sw));
+ }
+ if ((imageDataColorSettings_OR_sh is Map) &&
+ sh_OR_sw != null &&
+ (data_OR_imagedata_OR_sw is int) &&
+ imageDataColorSettings == null) {
+ var imageDataColorSettings_1 =
+ convertDartToNative_Dictionary(imageDataColorSettings_OR_sh);
+ return convertNativeToDart_ImageData(_createImageData_3(
+ data_OR_imagedata_OR_sw, sh_OR_sw, imageDataColorSettings_1));
+ }
+ if ((imageDataColorSettings_OR_sh is int) &&
+ sh_OR_sw != null &&
+ data_OR_imagedata_OR_sw != null &&
+ imageDataColorSettings == null) {
+ return convertNativeToDart_ImageData(_createImageData_4(
+ data_OR_imagedata_OR_sw, sh_OR_sw, imageDataColorSettings_OR_sh));
+ }
+ if (imageDataColorSettings != null &&
+ (imageDataColorSettings_OR_sh is int) &&
+ sh_OR_sw != null &&
+ data_OR_imagedata_OR_sw != null) {
+ var imageDataColorSettings_1 =
+ convertDartToNative_Dictionary(imageDataColorSettings);
+ return convertNativeToDart_ImageData(_createImageData_5(
+ data_OR_imagedata_OR_sw,
+ sh_OR_sw,
+ imageDataColorSettings_OR_sh,
+ imageDataColorSettings_1));
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('createImageData')
+ @Creates('ImageData|=Object')
+ _createImageData_1(imagedata) native;
+ @JSName('createImageData')
+ @Creates('ImageData|=Object')
+ _createImageData_2(int sw, sh) native;
+ @JSName('createImageData')
+ @Creates('ImageData|=Object')
+ _createImageData_3(int sw, sh, imageDataColorSettings) native;
+ @JSName('createImageData')
+ @Creates('ImageData|=Object')
+ _createImageData_4(data, sw, int sh) native;
+ @JSName('createImageData')
+ @Creates('ImageData|=Object')
+ _createImageData_5(data, sw, int sh, imageDataColorSettings) native;
+
+ CanvasGradient createLinearGradient(num x0, num y0, num x1, num y1) native;
+
+ CanvasPattern createPattern(Object image, String repetitionType) native;
+
+ CanvasGradient createRadialGradient(
+ num x0, num y0, num r0, num x1, num y1, num r1) native;
+
+ void drawFocusIfNeeded(element_OR_path, [Element element]) native;
+
+ void fill([path_OR_winding, String winding]) native;
+
+ void fillRect(num x, num y, num width, num height) native;
+
+ Map getContextAttributes() {
+ return convertNativeToDart_Dictionary(_getContextAttributes_1());
+ }
+
+ @JSName('getContextAttributes')
+ _getContextAttributes_1() native;
+
+ @Creates('ImageData|=Object')
+ ImageData getImageData(int sx, int sy, int sw, int sh) {
+ return convertNativeToDart_ImageData(_getImageData_1(sx, sy, sw, sh));
+ }
+
+ @JSName('getImageData')
+ @Creates('ImageData|=Object')
+ _getImageData_1(sx, sy, sw, sh) native;
+
+ @JSName('getLineDash')
+ List<num> _getLineDash() native;
+
+ bool isContextLost() native;
+
+ bool isPointInPath(path_OR_x, num x_OR_y, [winding_OR_y, String winding])
+ native;
+
+ bool isPointInStroke(path_OR_x, num x_OR_y, [num y]) native;
+
+ TextMetrics measureText(String text) native;
+
+ void putImageData(ImageData imagedata, int dx, int dy,
+ [int dirtyX, int dirtyY, int dirtyWidth, int dirtyHeight]) {
+ if (dirtyX == null &&
+ dirtyY == null &&
+ dirtyWidth == null &&
+ dirtyHeight == null) {
+ var imagedata_1 = convertDartToNative_ImageData(imagedata);
+ _putImageData_1(imagedata_1, dx, dy);
+ return;
+ }
+ if (dirtyHeight != null &&
+ dirtyWidth != null &&
+ dirtyY != null &&
+ dirtyX != null) {
+ var imagedata_1 = convertDartToNative_ImageData(imagedata);
+ _putImageData_2(
+ imagedata_1, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('putImageData')
+ void _putImageData_1(imagedata, dx, dy) native;
+ @JSName('putImageData')
+ void _putImageData_2(
+ imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) native;
+
+ void removeHitRegion(String id) native;
+
+ void resetTransform() native;
+
+ void restore() native;
+
+ void rotate(num angle) native;
+
+ void save() native;
+
+ void scale(num x, num y) native;
+
+ void scrollPathIntoView([Path2D path]) native;
+
+ void setTransform(num a, num b, num c, num d, num e, num f) native;
+
+ void stroke([Path2D path]) native;
+
+ void strokeRect(num x, num y, num width, num height) native;
+
+ void strokeText(String text, num x, num y, [num maxWidth]) native;
+
+ void transform(num a, num b, num c, num d, num e, num f) native;
+
+ void translate(num x, num y) native;
+
+ // From CanvasPath
+
+ @JSName('arc')
+ void _arc(num x, num y, num radius, num startAngle, num endAngle,
+ bool anticlockwise) native;
+
+ void arcTo(num x1, num y1, num x2, num y2, num radius) native;
+
+ void bezierCurveTo(num cp1x, num cp1y, num cp2x, num cp2y, num x, num y)
+ native;
+
+ void closePath() native;
+
+ void ellipse(num x, num y, num radiusX, num radiusY, num rotation,
+ num startAngle, num endAngle, bool anticlockwise) native;
+
+ void lineTo(num x, num y) native;
+
+ void moveTo(num x, num y) native;
+
+ void quadraticCurveTo(num cpx, num cpy, num x, num y) native;
+
+ void rect(num x, num y, num width, num height) native;
+
+ ImageData createImageDataFromImageData(ImageData imagedata) =>
+ JS('ImageData', '#.createImageData(#)', this, imagedata);
+
+ /**
+ * Sets the color used inside shapes.
+ * [r], [g], [b] are 0-255, [a] is 0-1.
+ */
+ void setFillColorRgb(int r, int g, int b, [num a = 1]) {
+ this.fillStyle = 'rgba($r, $g, $b, $a)';
+ }
+
+ /**
+ * Sets the color used inside shapes.
+ * [h] is in degrees, 0-360.
+ * [s], [l] are in percent, 0-100.
+ * [a] is 0-1.
+ */
+ void setFillColorHsl(int h, num s, num l, [num a = 1]) {
+ this.fillStyle = 'hsla($h, $s%, $l%, $a)';
+ }
+
+ /**
+ * Sets the color used for stroking shapes.
+ * [r], [g], [b] are 0-255, [a] is 0-1.
+ */
+ void setStrokeColorRgb(int r, int g, int b, [num a = 1]) {
+ this.strokeStyle = 'rgba($r, $g, $b, $a)';
+ }
+
+ /**
+ * Sets the color used for stroking shapes.
+ * [h] is in degrees, 0-360.
+ * [s], [l] are in percent, 0-100.
+ * [a] is 0-1.
+ */
+ void setStrokeColorHsl(int h, num s, num l, [num a = 1]) {
+ this.strokeStyle = 'hsla($h, $s%, $l%, $a)';
+ }
+
+ void arc(num x, num y, num radius, num startAngle, num endAngle,
+ [bool anticlockwise = false]) {
+ // TODO(terry): This should not be needed: dartbug.com/20939.
+ JS('void', '#.arc(#, #, #, #, #, #)', this, x, y, radius, startAngle,
+ endAngle, anticlockwise);
+ }
+
+ CanvasPattern createPatternFromImage(
+ ImageElement image, String repetitionType) =>
+ JS('CanvasPattern', '#.createPattern(#, #)', this, image, repetitionType);
+
+ /**
+ * Draws an image from a CanvasImageSource to an area of this canvas.
+ *
+ * The image will be drawn to an area of this canvas defined by
+ * [destRect]. [sourceRect] defines the region of the source image that is
+ * drawn.
+ * If [sourceRect] is not provided, then
+ * the entire rectangular image from [source] will be drawn to this context.
+ *
+ * If the image is larger than canvas
+ * will allow, the image will be clipped to fit the available space.
+ *
+ * CanvasElement canvas = new CanvasElement(width: 600, height: 600);
+ * CanvasRenderingContext2D ctx = canvas.context2D;
+ * ImageElement img = document.query('img');
+ * img.width = 100;
+ * img.height = 100;
+ *
+ * // Scale the image to 20x20.
+ * ctx.drawImageToRect(img, new Rectangle(50, 50, 20, 20));
+ *
+ * VideoElement video = document.query('video');
+ * video.width = 100;
+ * video.height = 100;
+ * // Take the middle 20x20 pixels from the video and stretch them.
+ * ctx.drawImageToRect(video, new Rectangle(50, 50, 100, 100),
+ * sourceRect: new Rectangle(40, 40, 20, 20));
+ *
+ * // Draw the top 100x20 pixels from the otherCanvas.
+ * CanvasElement otherCanvas = document.query('canvas');
+ * ctx.drawImageToRect(otherCanvas, new Rectangle(0, 0, 100, 20),
+ * sourceRect: new Rectangle(0, 0, 100, 20));
+ *
+ * See also:
+ *
+ * * [CanvasImageSource] for more information on what data is retrieved
+ * from [source].
+ * * [drawImage](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage)
+ * from the WHATWG.
+ */
+ void drawImageToRect(CanvasImageSource source, Rectangle destRect,
+ {Rectangle sourceRect}) {
+ if (sourceRect == null) {
+ drawImageScaled(
+ source, destRect.left, destRect.top, destRect.width, destRect.height);
+ } else {
+ drawImageScaledFromSource(
+ source,
+ sourceRect.left,
+ sourceRect.top,
+ sourceRect.width,
+ sourceRect.height,
+ destRect.left,
+ destRect.top,
+ destRect.width,
+ destRect.height);
+ }
+ }
+
+ /**
+ * Draws an image from a CanvasImageSource to this canvas.
+ *
+ * The entire image from [source] will be drawn to this context with its top
+ * left corner at the point ([destX], [destY]). If the image is
+ * larger than canvas will allow, the image will be clipped to fit the
+ * available space.
+ *
+ * CanvasElement canvas = new CanvasElement(width: 600, height: 600);
+ * CanvasRenderingContext2D ctx = canvas.context2D;
+ * ImageElement img = document.query('img');
+ *
+ * ctx.drawImage(img, 100, 100);
+ *
+ * VideoElement video = document.query('video');
+ * ctx.drawImage(video, 0, 0);
+ *
+ * CanvasElement otherCanvas = document.query('canvas');
+ * otherCanvas.width = 100;
+ * otherCanvas.height = 100;
+ * ctx.drawImage(otherCanvas, 590, 590); // will get clipped
+ *
+ * See also:
+ *
+ * * [CanvasImageSource] for more information on what data is retrieved
+ * from [source].
+ * * [drawImage](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage)
+ * from the WHATWG.
+ */
+ @JSName('drawImage')
+ void drawImage(CanvasImageSource source, num destX, num destY) native;
+
+ /**
+ * Draws an image from a CanvasImageSource to an area of this canvas.
+ *
+ * The image will be drawn to this context with its top left corner at the
+ * point ([destX], [destY]) and will be scaled to be [destWidth] wide and
+ * [destHeight] tall.
+ *
+ * If the image is larger than canvas
+ * will allow, the image will be clipped to fit the available space.
+ *
+ * CanvasElement canvas = new CanvasElement(width: 600, height: 600);
+ * CanvasRenderingContext2D ctx = canvas.context2D;
+ * ImageElement img = document.query('img');
+ * img.width = 100;
+ * img.height = 100;
+ *
+ * // Scale the image to 300x50 at the point (20, 20)
+ * ctx.drawImageScaled(img, 20, 20, 300, 50);
+ *
+ * See also:
+ *
+ * * [CanvasImageSource] for more information on what data is retrieved
+ * from [source].
+ * * [drawImage](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage)
+ * from the WHATWG.
+ */
+ @JSName('drawImage')
+ void drawImageScaled(CanvasImageSource source, num destX, num destY,
+ num destWidth, num destHeight) native;
+
+ /**
+ * Draws an image from a CanvasImageSource to an area of this canvas.
+ *
+ * The image is a region of [source] that is [sourceWidth] wide and
+ * [destHeight] tall with top left corner at ([sourceX], [sourceY]).
+ * The image will be drawn to this context with its top left corner at the
+ * point ([destX], [destY]) and will be scaled to be [destWidth] wide and
+ * [destHeight] tall.
+ *
+ * If the image is larger than canvas
+ * will allow, the image will be clipped to fit the available space.
+ *
+ * VideoElement video = document.query('video');
+ * video.width = 100;
+ * video.height = 100;
+ * // Take the middle 20x20 pixels from the video and stretch them.
+ * ctx.drawImageScaledFromSource(video, 40, 40, 20, 20, 50, 50, 100, 100);
+ *
+ * // Draw the top 100x20 pixels from the otherCanvas to this one.
+ * CanvasElement otherCanvas = document.query('canvas');
+ * ctx.drawImageScaledFromSource(otherCanvas, 0, 0, 100, 20, 0, 0, 100, 20);
+ *
+ * See also:
+ *
+ * * [CanvasImageSource] for more information on what data is retrieved
+ * from [source].
+ * * [drawImage](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage)
+ * from the WHATWG.
+ */
+ @JSName('drawImage')
+ void drawImageScaledFromSource(
+ CanvasImageSource source,
+ num sourceX,
+ num sourceY,
+ num sourceWidth,
+ num sourceHeight,
+ num destX,
+ num destY,
+ num destWidth,
+ num destHeight) native;
+
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @SupportedBrowser(SupportedBrowser.IE, '11')
+ @Unstable()
+ // TODO(14316): Firefox has this functionality with mozDashOffset, but it
+ // needs to be polyfilled.
+ num get lineDashOffset =>
+ JS('num', '#.lineDashOffset || #.webkitLineDashOffset', this, this);
+
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @SupportedBrowser(SupportedBrowser.IE, '11')
+ @Unstable()
+ // TODO(14316): Firefox has this functionality with mozDashOffset, but it
+ // needs to be polyfilled.
+ set lineDashOffset(num value) {
+ JS(
+ 'void',
+ 'typeof #.lineDashOffset != "undefined" ? #.lineDashOffset = # : '
+ '#.webkitLineDashOffset = #',
+ this,
+ this,
+ value,
+ this,
+ value);
+ }
+
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @SupportedBrowser(SupportedBrowser.IE, '11')
+ @Unstable()
+ List<num> getLineDash() {
+ // TODO(14316): Firefox has this functionality with mozDash, but it's a bit
+ // different.
+ if (JS('bool', '!!#.getLineDash', this)) {
+ return JS('List<num>', '#.getLineDash()', this);
+ } else if (JS('bool', '!!#.webkitLineDash', this)) {
+ return JS('List<num>', '#.webkitLineDash', this);
+ }
+ }
+
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @SupportedBrowser(SupportedBrowser.IE, '11')
+ @Unstable()
+ void setLineDash(List<num> dash) {
+ // TODO(14316): Firefox has this functionality with mozDash, but it's a bit
+ // different.
+ if (JS('bool', '!!#.setLineDash', this)) {
+ JS('void', '#.setLineDash(#)', this, dash);
+ } else if (JS('bool', '!!#.webkitLineDash', this)) {
+ JS('void', '#.webkitLineDash = #', this, dash);
+ }
+ }
+
+ /**
+ * Draws text to the canvas.
+ *
+ * The text is drawn starting at coordinates ([x], [y]).
+ * If [maxWidth] is provided and the [text] is computed to be wider than
+ * [maxWidth], then the drawn text is scaled down horizontally to fit.
+ *
+ * The text uses the current [CanvasRenderingContext2D.font] property for font
+ * options, such as typeface and size, and the current
+ * [CanvasRenderingContext2D.fillStyle] for style options such as color.
+ * The current [CanvasRenderingContext2D.textAlign] and
+ * [CanvasRenderingContext2D.textBaseLine] properties are also applied to the
+ * drawn text.
+ */
+ void fillText(String text, num x, num y, [num maxWidth]) {
+ if (maxWidth != null) {
+ JS('void', '#.fillText(#, #, #, #)', this, text, x, y, maxWidth);
+ } else {
+ JS('void', '#.fillText(#, #, #)', this, text, x, y);
+ }
+ }
+
+ /** Deprecated always returns 1.0 */
+ @deprecated
+ double get backingStorePixelRatio => 1.0;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CharacterData")
+class CharacterData extends Node
+ implements NonDocumentTypeChildNode, ChildNode {
+ // To suppress missing implicit constructor warnings.
+ factory CharacterData._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String data;
+
+ final int length;
+
+ void appendData(String data) native;
+
+ void deleteData(int offset, int count) native;
+
+ void insertData(int offset, String data) native;
+
+ void replaceData(int offset, int count, String data) native;
+
+ String substringData(int offset, int count) native;
+
+ // From ChildNode
+
+ void after(Object nodes) native;
+
+ void before(Object nodes) native;
+
+ // From NonDocumentTypeChildNode
+
+ final Element nextElementSibling;
+
+ final Element previousElementSibling;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class ChildNode extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ChildNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void after(Object nodes);
+
+ void before(Object nodes);
+
+ void remove();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Client")
+class Client extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Client._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String frameType;
+
+ final String id;
+
+ final String type;
+
+ final String url;
+
+ void postMessage(Object message, [List<Object> transfer]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Clients")
+class Clients extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Clients._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future claim() => promiseToFuture(JS("", "#.claim()", this));
+
+ Future get(String id) => promiseToFuture(JS("", "#.get(#)", this, id));
+
+ Future<List<Client>> matchAll([Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture<List<Client>>(
+ JS("", "#.matchAll(#)", this, options_dict));
+ }
+
+ Future<WindowClient> openWindow(String url) =>
+ promiseToFuture<WindowClient>(JS("", "#.openWindow(#)", this, url));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ClipboardEvent")
+class ClipboardEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory ClipboardEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ClipboardEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return ClipboardEvent._create_1(type, eventInitDict_1);
+ }
+ return ClipboardEvent._create_2(type);
+ }
+ static ClipboardEvent _create_1(type, eventInitDict) =>
+ JS('ClipboardEvent', 'new ClipboardEvent(#,#)', type, eventInitDict);
+ static ClipboardEvent _create_2(type) =>
+ JS('ClipboardEvent', 'new ClipboardEvent(#)', type);
+
+ final DataTransfer clipboardData;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CloseEvent")
+class CloseEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory CloseEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CloseEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return CloseEvent._create_1(type, eventInitDict_1);
+ }
+ return CloseEvent._create_2(type);
+ }
+ static CloseEvent _create_1(type, eventInitDict) =>
+ JS('CloseEvent', 'new CloseEvent(#,#)', type, eventInitDict);
+ static CloseEvent _create_2(type) =>
+ JS('CloseEvent', 'new CloseEvent(#)', type);
+
+ final int code;
+
+ final String reason;
+
+ final bool wasClean;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Comment")
+class Comment extends CharacterData {
+ factory Comment([String data]) {
+ return JS('returns:Comment;depends:none;effects:none;new:true',
+ '#.createComment(#)', document, data == null ? "" : data);
+ }
+ // To suppress missing implicit constructor warnings.
+ factory Comment._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("CompositionEvent")
+class CompositionEvent extends UIEvent {
+ factory CompositionEvent(String type,
+ {bool canBubble: false,
+ bool cancelable: false,
+ Window view,
+ String data,
+ String locale}) {
+ if (view == null) {
+ view = window;
+ }
+ CompositionEvent e = document._createEvent("CompositionEvent");
+
+ if (Device.isFirefox) {
+ // Firefox requires the locale parameter that isn't supported elsewhere.
+ JS('void', '#.initCompositionEvent(#, #, #, #, #, #)', e, type, canBubble,
+ cancelable, view, data, locale);
+ } else {
+ e._initCompositionEvent(type, canBubble, cancelable, view, data);
+ }
+
+ return e;
+ }
+
+ factory CompositionEvent._(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return CompositionEvent._create_1(type, eventInitDict_1);
+ }
+ return CompositionEvent._create_2(type);
+ }
+ static CompositionEvent _create_1(type, eventInitDict) =>
+ JS('CompositionEvent', 'new CompositionEvent(#,#)', type, eventInitDict);
+ static CompositionEvent _create_2(type) =>
+ JS('CompositionEvent', 'new CompositionEvent(#)', type);
+
+ final String data;
+
+ @JSName('initCompositionEvent')
+ void _initCompositionEvent(String type, bool bubbles, bool cancelable,
+ Window view, String data) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '26')
+@Native("HTMLContentElement")
+class ContentElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory ContentElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ContentElement() => document.createElement("content");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ContentElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Element.isTagSupported('content');
+
+ String select;
+
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ List<Node> getDistributedNodes() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CookieStore")
+class CookieStore extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CookieStore._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future getAll([Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture(JS("", "#.getAll(#)", this, options_dict));
+ }
+
+ Future set(String name, String value, [Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture(
+ JS("", "#.set(#, #, #)", this, name, value, options_dict));
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Coordinates")
+class Coordinates extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Coordinates._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num accuracy;
+
+ final num altitude;
+
+ final num altitudeAccuracy;
+
+ final num heading;
+
+ final num latitude;
+
+ final num longitude;
+
+ final num speed;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Credential")
+class Credential extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Credential._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String id;
+
+ final String type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CredentialUserData")
+class CredentialUserData extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CredentialUserData._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('iconURL')
+ final String iconUrl;
+
+ final String name;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CredentialsContainer")
+class CredentialsContainer extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CredentialsContainer._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future create([Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture(JS("", "#.create(#)", this, options_dict));
+ }
+
+ Future get([Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture(JS("", "#.get(#)", this, options_dict));
+ }
+
+ Future preventSilentAccess() =>
+ promiseToFuture(JS("", "#.preventSilentAccess()", this));
+
+ Future requireUserMediation() =>
+ promiseToFuture(JS("", "#.requireUserMediation()", this));
+
+ Future store(Credential credential) =>
+ promiseToFuture(JS("", "#.store(#)", this, credential));
+}
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("Crypto")
+class Crypto extends Interceptor {
+ TypedData getRandomValues(TypedData array) {
+ return _getRandomValues(array);
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory Crypto._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ JS('bool', '!!(window.crypto && window.crypto.getRandomValues)');
+
+ final _SubtleCrypto subtle;
+
+ @JSName('getRandomValues')
+ @Creates('TypedData')
+ @Returns('TypedData|Null')
+ TypedData _getRandomValues(TypedData array) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CryptoKey")
+class CryptoKey extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CryptoKey._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @Creates('Null')
+ final Object algorithm;
+
+ final bool extractable;
+
+ final String type;
+
+ final Object usages;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSS")
+class Css extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Css._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static final _Worklet paintWorklet;
+
+ static CssUnitValue Hz(num value) native;
+
+ static CssUnitValue ch(num value) native;
+
+ static CssUnitValue cm(num value) native;
+
+ static CssUnitValue deg(num value) native;
+
+ static CssUnitValue dpcm(num value) native;
+
+ static CssUnitValue dpi(num value) native;
+
+ static CssUnitValue dppx(num value) native;
+
+ static CssUnitValue em(num value) native;
+
+ static String escape(String ident) native;
+
+ static CssUnitValue ex(num value) native;
+
+ static CssUnitValue fr(num value) native;
+
+ static CssUnitValue grad(num value) native;
+
+ @JSName('in')
+ static CssUnitValue inch(num value) native;
+
+ static CssUnitValue kHz(num value) native;
+
+ static CssUnitValue mm(num value) native;
+
+ static CssUnitValue ms(num value) native;
+
+ static CssUnitValue number(num value) native;
+
+ static CssUnitValue pc(num value) native;
+
+ static CssUnitValue percent(num value) native;
+
+ static CssUnitValue pt(num value) native;
+
+ static CssUnitValue px(num value) native;
+
+ static CssUnitValue rad(num value) native;
+
+ static void registerProperty(Map descriptor) {
+ var descriptor_1 = convertDartToNative_Dictionary(descriptor);
+ _registerProperty_1(descriptor_1);
+ return;
+ }
+
+ @JSName('registerProperty')
+ static void _registerProperty_1(descriptor) native;
+
+ static CssUnitValue rem(num value) native;
+
+ static CssUnitValue s(num value) native;
+
+ static bool supports(String property, String value) native;
+
+ @JSName('supports')
+ static bool supportsCondition(String conditionText) native;
+
+ static CssUnitValue turn(num value) native;
+
+ static CssUnitValue vh(num value) native;
+
+ static CssUnitValue vmax(num value) native;
+
+ static CssUnitValue vmin(num value) native;
+
+ static CssUnitValue vw(num value) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSCharsetRule")
+class CssCharsetRule extends CssRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssCharsetRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String encoding;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSConditionRule")
+class CssConditionRule extends CssGroupingRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssConditionRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String conditionText;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSFontFaceRule")
+class CssFontFaceRule extends CssRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssFontFaceRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final CssStyleDeclaration style;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSGroupingRule")
+class CssGroupingRule extends CssRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssGroupingRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @Returns('_CssRuleList|Null')
+ @Creates('_CssRuleList')
+ final List<CssRule> cssRules;
+
+ void deleteRule(int index) native;
+
+ int insertRule(String rule, int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSImageValue")
+class CssImageValue extends CssResourceValue {
+ // To suppress missing implicit constructor warnings.
+ factory CssImageValue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num intrinsicHeight;
+
+ final num intrinsicRatio;
+
+ final num intrinsicWidth;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSImportRule")
+class CssImportRule extends CssRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssImportRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String href;
+
+ final MediaList media;
+
+ final CssStyleSheet styleSheet;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSKeyframeRule,MozCSSKeyframeRule,WebKitCSSKeyframeRule")
+class CssKeyframeRule extends CssRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssKeyframeRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String keyText;
+
+ final CssStyleDeclaration style;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSKeyframesRule,MozCSSKeyframesRule,WebKitCSSKeyframesRule")
+class CssKeyframesRule extends CssRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssKeyframesRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @Returns('_CssRuleList|Null')
+ @Creates('_CssRuleList')
+ final List<CssRule> cssRules;
+
+ String name;
+
+ CssKeyframeRule __getter__(int index) native;
+
+ void appendRule(String rule) native;
+
+ void deleteRule(String select) native;
+
+ CssKeyframeRule findRule(String select) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSKeywordValue")
+class CssKeywordValue extends CssStyleValue {
+ // To suppress missing implicit constructor warnings.
+ factory CssKeywordValue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CssKeywordValue(String keyword) {
+ return CssKeywordValue._create_1(keyword);
+ }
+ static CssKeywordValue _create_1(keyword) =>
+ JS('CssKeywordValue', 'new CSSKeywordValue(#)', keyword);
+
+ String value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSMatrixComponent")
+class CssMatrixComponent extends CssTransformComponent {
+ // To suppress missing implicit constructor warnings.
+ factory CssMatrixComponent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CssMatrixComponent(DomMatrixReadOnly matrix, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return CssMatrixComponent._create_1(matrix, options_1);
+ }
+ return CssMatrixComponent._create_2(matrix);
+ }
+ static CssMatrixComponent _create_1(matrix, options) =>
+ JS('CssMatrixComponent', 'new CSSMatrixComponent(#,#)', matrix, options);
+ static CssMatrixComponent _create_2(matrix) =>
+ JS('CssMatrixComponent', 'new CSSMatrixComponent(#)', matrix);
+
+ DomMatrix matrix;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSMediaRule")
+class CssMediaRule extends CssConditionRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssMediaRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final MediaList media;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSNamespaceRule")
+class CssNamespaceRule extends CssRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssNamespaceRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('namespaceURI')
+ final String namespaceUri;
+
+ final String prefix;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSNumericValue")
+class CssNumericValue extends CssStyleValue {
+ // To suppress missing implicit constructor warnings.
+ factory CssNumericValue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ CssNumericValue add(CssNumericValue value) native;
+
+ CssNumericValue div(num value) native;
+
+ CssNumericValue mul(num value) native;
+
+ static CssNumericValue parse(String cssText) native;
+
+ CssNumericValue sub(CssNumericValue value) native;
+
+ CssNumericValue to(String unit) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSPageRule")
+class CssPageRule extends CssRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssPageRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String selectorText;
+
+ final CssStyleDeclaration style;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSPerspective")
+class CssPerspective extends CssTransformComponent {
+ // To suppress missing implicit constructor warnings.
+ factory CssPerspective._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CssPerspective(CssNumericValue length) {
+ return CssPerspective._create_1(length);
+ }
+ static CssPerspective _create_1(length) =>
+ JS('CssPerspective', 'new CSSPerspective(#)', length);
+
+ CssNumericValue length;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSPositionValue")
+class CssPositionValue extends CssStyleValue {
+ // To suppress missing implicit constructor warnings.
+ factory CssPositionValue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CssPositionValue(CssNumericValue x, CssNumericValue y) {
+ return CssPositionValue._create_1(x, y);
+ }
+ static CssPositionValue _create_1(x, y) =>
+ JS('CssPositionValue', 'new CSSPositionValue(#,#)', x, y);
+
+ CssNumericValue x;
+
+ CssNumericValue y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSResourceValue")
+class CssResourceValue extends CssStyleValue {
+ // To suppress missing implicit constructor warnings.
+ factory CssResourceValue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String state;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSRotation")
+class CssRotation extends CssTransformComponent {
+ // To suppress missing implicit constructor warnings.
+ factory CssRotation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CssRotation(angleValue_OR_x, [num y, num z, CssNumericValue angle]) {
+ if ((angleValue_OR_x is CssNumericValue) &&
+ y == null &&
+ z == null &&
+ angle == null) {
+ return CssRotation._create_1(angleValue_OR_x);
+ }
+ if ((angle is CssNumericValue) &&
+ (z is num) &&
+ (y is num) &&
+ (angleValue_OR_x is num)) {
+ return CssRotation._create_2(angleValue_OR_x, y, z, angle);
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+ static CssRotation _create_1(angleValue_OR_x) =>
+ JS('CssRotation', 'new CSSRotation(#)', angleValue_OR_x);
+ static CssRotation _create_2(angleValue_OR_x, y, z, angle) => JS(
+ 'CssRotation', 'new CSSRotation(#,#,#,#)', angleValue_OR_x, y, z, angle);
+
+ CssNumericValue angle;
+
+ num x;
+
+ num y;
+
+ num z;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSRule")
+class CssRule extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CssRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int CHARSET_RULE = 2;
+
+ static const int FONT_FACE_RULE = 5;
+
+ static const int IMPORT_RULE = 3;
+
+ static const int KEYFRAMES_RULE = 7;
+
+ static const int KEYFRAME_RULE = 8;
+
+ static const int MEDIA_RULE = 4;
+
+ static const int NAMESPACE_RULE = 10;
+
+ static const int PAGE_RULE = 6;
+
+ static const int STYLE_RULE = 1;
+
+ static const int SUPPORTS_RULE = 12;
+
+ static const int VIEWPORT_RULE = 15;
+
+ String cssText;
+
+ final CssRule parentRule;
+
+ final CssStyleSheet parentStyleSheet;
+
+ final int type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSScale")
+class CssScale extends CssTransformComponent {
+ // To suppress missing implicit constructor warnings.
+ factory CssScale._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CssScale(num x, num y, [num z]) {
+ if ((y is num) && (x is num) && z == null) {
+ return CssScale._create_1(x, y);
+ }
+ if ((z is num) && (y is num) && (x is num)) {
+ return CssScale._create_2(x, y, z);
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+ static CssScale _create_1(x, y) => JS('CssScale', 'new CSSScale(#,#)', x, y);
+ static CssScale _create_2(x, y, z) =>
+ JS('CssScale', 'new CSSScale(#,#,#)', x, y, z);
+
+ num x;
+
+ num y;
+
+ num z;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSSkew")
+class CssSkew extends CssTransformComponent {
+ // To suppress missing implicit constructor warnings.
+ factory CssSkew._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CssSkew(CssNumericValue ax, CssNumericValue ay) {
+ return CssSkew._create_1(ax, ay);
+ }
+ static CssSkew _create_1(ax, ay) => JS('CssSkew', 'new CSSSkew(#,#)', ax, ay);
+
+ CssNumericValue ax;
+
+ CssNumericValue ay;
+}
+
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: DO NOT EDIT THIS TEMPLATE FILE.
+// The template file was generated by scripts/css_code_generator.py
+
+// Source of CSS properties:
+// CSSPropertyNames.in
+
+@Native("CSSStyleDeclaration,MSStyleCSSProperties,CSS2Properties")
+class CssStyleDeclaration extends Interceptor with CssStyleDeclarationBase {
+ factory CssStyleDeclaration() => new CssStyleDeclaration.css('');
+
+ factory CssStyleDeclaration.css(String css) {
+ final style = new DivElement().style;
+ style.cssText = css;
+ return style;
+ }
+
+ /// Returns the value of the property if the provided *CSS* property
+ /// name is supported on this element and if the value is set. Otherwise
+ /// returns an empty string.
+ ///
+ /// Please note the property name uses camelCase, not-hyphens.
+ String getPropertyValue(String propertyName) {
+ var propValue = _getPropertyValueHelper(propertyName);
+ return propValue ?? '';
+ }
+
+ String _getPropertyValueHelper(String propertyName) {
+ return _getPropertyValue(_browserPropertyName(propertyName));
+ }
+
+ /**
+ * Returns true if the provided *CSS* property name is supported on this
+ * element.
+ *
+ * Please note the property name camelCase, not-hyphens. This
+ * method returns true if the property is accessible via an unprefixed _or_
+ * prefixed property.
+ */
+ bool supportsProperty(String propertyName) {
+ return _supportsProperty(propertyName) ||
+ _supportsProperty(_camelCase("${Device.cssPrefix}$propertyName"));
+ }
+
+ bool _supportsProperty(String propertyName) {
+ return JS('bool', '# in #', propertyName, this);
+ }
+
+ void setProperty(String propertyName, String value, [String priority]) {
+ return _setPropertyHelper(
+ _browserPropertyName(propertyName), value, priority);
+ }
+
+ String _browserPropertyName(String propertyName) {
+ String name = _readCache(propertyName);
+ if (name is String) return name;
+ name = _supportedBrowserPropertyName(propertyName);
+ _writeCache(propertyName, name);
+ return name;
+ }
+
+ String _supportedBrowserPropertyName(String propertyName) {
+ if (_supportsProperty(_camelCase(propertyName))) {
+ return propertyName;
+ }
+ var prefixed = "${Device.cssPrefix}$propertyName";
+ if (_supportsProperty(prefixed)) {
+ return prefixed;
+ }
+ // May be a CSS variable, just use it as provided.
+ return propertyName;
+ }
+
+ static final _propertyCache = JS('', '{}');
+ static String _readCache(String key) =>
+ JS('String|Null', '#[#]', _propertyCache, key);
+ static void _writeCache(String key, String value) {
+ JS('void', '#[#] = #', _propertyCache, key, value);
+ }
+
+ static String _camelCase(String hyphenated) {
+ var replacedMs = JS('String', r'#.replace(/^-ms-/, "ms-")', hyphenated);
+ return JS(
+ 'String',
+ r'#.replace(/-([\da-z])/ig,'
+ r'function(_, letter) { return letter.toUpperCase();})',
+ replacedMs);
+ }
+
+ void _setPropertyHelper(String propertyName, String value,
+ [String priority]) {
+ if (value == null) value = '';
+ if (priority == null) priority = '';
+ JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority);
+ }
+
+ /**
+ * Checks to see if CSS Transitions are supported.
+ */
+ static bool get supportsTransitions {
+ return document.body.style.supportsProperty('transition');
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory CssStyleDeclaration._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String cssFloat;
+
+ String cssText;
+
+ final int length;
+
+ final CssRule parentRule;
+
+ String getPropertyPriority(String property) native;
+
+ @JSName('getPropertyValue')
+ String _getPropertyValue(String property) native;
+
+ String item(int index) native;
+
+ String removeProperty(String property) native;
+
+ /** Gets the value of "background" */
+ String get background => this._background;
+
+ /** Sets the value of "background" */
+ set background(String value) {
+ _background = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('background')
+ String _background;
+
+ /** Gets the value of "background-attachment" */
+ String get backgroundAttachment => this._backgroundAttachment;
+
+ /** Sets the value of "background-attachment" */
+ set backgroundAttachment(String value) {
+ _backgroundAttachment = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('backgroundAttachment')
+ String _backgroundAttachment;
+
+ /** Gets the value of "background-color" */
+ String get backgroundColor => this._backgroundColor;
+
+ /** Sets the value of "background-color" */
+ set backgroundColor(String value) {
+ _backgroundColor = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('backgroundColor')
+ String _backgroundColor;
+
+ /** Gets the value of "background-image" */
+ String get backgroundImage => this._backgroundImage;
+
+ /** Sets the value of "background-image" */
+ set backgroundImage(String value) {
+ _backgroundImage = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('backgroundImage')
+ String _backgroundImage;
+
+ /** Gets the value of "background-position" */
+ String get backgroundPosition => this._backgroundPosition;
+
+ /** Sets the value of "background-position" */
+ set backgroundPosition(String value) {
+ _backgroundPosition = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('backgroundPosition')
+ String _backgroundPosition;
+
+ /** Gets the value of "background-repeat" */
+ String get backgroundRepeat => this._backgroundRepeat;
+
+ /** Sets the value of "background-repeat" */
+ set backgroundRepeat(String value) {
+ _backgroundRepeat = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('backgroundRepeat')
+ String _backgroundRepeat;
+
+ /** Gets the value of "border" */
+ String get border => this._border;
+
+ /** Sets the value of "border" */
+ set border(String value) {
+ _border = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('border')
+ String _border;
+
+ /** Gets the value of "border-bottom" */
+ String get borderBottom => this._borderBottom;
+
+ /** Sets the value of "border-bottom" */
+ set borderBottom(String value) {
+ _borderBottom = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderBottom')
+ String _borderBottom;
+
+ /** Gets the value of "border-bottom-color" */
+ String get borderBottomColor => this._borderBottomColor;
+
+ /** Sets the value of "border-bottom-color" */
+ set borderBottomColor(String value) {
+ _borderBottomColor = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderBottomColor')
+ String _borderBottomColor;
+
+ /** Gets the value of "border-bottom-style" */
+ String get borderBottomStyle => this._borderBottomStyle;
+
+ /** Sets the value of "border-bottom-style" */
+ set borderBottomStyle(String value) {
+ _borderBottomStyle = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderBottomStyle')
+ String _borderBottomStyle;
+
+ /** Gets the value of "border-bottom-width" */
+ String get borderBottomWidth => this._borderBottomWidth;
+
+ /** Sets the value of "border-bottom-width" */
+ set borderBottomWidth(String value) {
+ _borderBottomWidth = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderBottomWidth')
+ String _borderBottomWidth;
+
+ /** Gets the value of "border-collapse" */
+ String get borderCollapse => this._borderCollapse;
+
+ /** Sets the value of "border-collapse" */
+ set borderCollapse(String value) {
+ _borderCollapse = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderCollapse')
+ String _borderCollapse;
+
+ /** Gets the value of "border-color" */
+ String get borderColor => this._borderColor;
+
+ /** Sets the value of "border-color" */
+ set borderColor(String value) {
+ _borderColor = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderColor')
+ String _borderColor;
+
+ /** Gets the value of "border-left" */
+ String get borderLeft => this._borderLeft;
+
+ /** Sets the value of "border-left" */
+ set borderLeft(String value) {
+ _borderLeft = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderLeft')
+ String _borderLeft;
+
+ /** Gets the value of "border-left-color" */
+ String get borderLeftColor => this._borderLeftColor;
+
+ /** Sets the value of "border-left-color" */
+ set borderLeftColor(String value) {
+ _borderLeftColor = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderLeftColor')
+ String _borderLeftColor;
+
+ /** Gets the value of "border-left-style" */
+ String get borderLeftStyle => this._borderLeftStyle;
+
+ /** Sets the value of "border-left-style" */
+ set borderLeftStyle(String value) {
+ _borderLeftStyle = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderLeftStyle')
+ String _borderLeftStyle;
+
+ /** Gets the value of "border-left-width" */
+ String get borderLeftWidth => this._borderLeftWidth;
+
+ /** Sets the value of "border-left-width" */
+ set borderLeftWidth(String value) {
+ _borderLeftWidth = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderLeftWidth')
+ String _borderLeftWidth;
+
+ /** Gets the value of "border-right" */
+ String get borderRight => this._borderRight;
+
+ /** Sets the value of "border-right" */
+ set borderRight(String value) {
+ _borderRight = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderRight')
+ String _borderRight;
+
+ /** Gets the value of "border-right-color" */
+ String get borderRightColor => this._borderRightColor;
+
+ /** Sets the value of "border-right-color" */
+ set borderRightColor(String value) {
+ _borderRightColor = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderRightColor')
+ String _borderRightColor;
+
+ /** Gets the value of "border-right-style" */
+ String get borderRightStyle => this._borderRightStyle;
+
+ /** Sets the value of "border-right-style" */
+ set borderRightStyle(String value) {
+ _borderRightStyle = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderRightStyle')
+ String _borderRightStyle;
+
+ /** Gets the value of "border-right-width" */
+ String get borderRightWidth => this._borderRightWidth;
+
+ /** Sets the value of "border-right-width" */
+ set borderRightWidth(String value) {
+ _borderRightWidth = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderRightWidth')
+ String _borderRightWidth;
+
+ /** Gets the value of "border-spacing" */
+ String get borderSpacing => this._borderSpacing;
+
+ /** Sets the value of "border-spacing" */
+ set borderSpacing(String value) {
+ _borderSpacing = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderSpacing')
+ String _borderSpacing;
+
+ /** Gets the value of "border-style" */
+ String get borderStyle => this._borderStyle;
+
+ /** Sets the value of "border-style" */
+ set borderStyle(String value) {
+ _borderStyle = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderStyle')
+ String _borderStyle;
+
+ /** Gets the value of "border-top" */
+ String get borderTop => this._borderTop;
+
+ /** Sets the value of "border-top" */
+ set borderTop(String value) {
+ _borderTop = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderTop')
+ String _borderTop;
+
+ /** Gets the value of "border-top-color" */
+ String get borderTopColor => this._borderTopColor;
+
+ /** Sets the value of "border-top-color" */
+ set borderTopColor(String value) {
+ _borderTopColor = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderTopColor')
+ String _borderTopColor;
+
+ /** Gets the value of "border-top-style" */
+ String get borderTopStyle => this._borderTopStyle;
+
+ /** Sets the value of "border-top-style" */
+ set borderTopStyle(String value) {
+ _borderTopStyle = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderTopStyle')
+ String _borderTopStyle;
+
+ /** Gets the value of "border-top-width" */
+ String get borderTopWidth => this._borderTopWidth;
+
+ /** Sets the value of "border-top-width" */
+ set borderTopWidth(String value) {
+ _borderTopWidth = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderTopWidth')
+ String _borderTopWidth;
+
+ /** Gets the value of "border-width" */
+ String get borderWidth => this._borderWidth;
+
+ /** Sets the value of "border-width" */
+ set borderWidth(String value) {
+ _borderWidth = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('borderWidth')
+ String _borderWidth;
+
+ /** Gets the value of "bottom" */
+ String get bottom => this._bottom;
+
+ /** Sets the value of "bottom" */
+ set bottom(String value) {
+ _bottom = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('bottom')
+ String _bottom;
+
+ /** Gets the value of "caption-side" */
+ String get captionSide => this._captionSide;
+
+ /** Sets the value of "caption-side" */
+ set captionSide(String value) {
+ _captionSide = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('captionSide')
+ String _captionSide;
+
+ /** Gets the value of "clear" */
+ String get clear => this._clear;
+
+ /** Sets the value of "clear" */
+ set clear(String value) {
+ _clear = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('clear')
+ String _clear;
+
+ /** Gets the value of "clip" */
+ String get clip => this._clip;
+
+ /** Sets the value of "clip" */
+ set clip(String value) {
+ _clip = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('clip')
+ String _clip;
+
+ /** Gets the value of "color" */
+ String get color => this._color;
+
+ /** Sets the value of "color" */
+ set color(String value) {
+ _color = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('color')
+ String _color;
+
+ /** Gets the value of "content" */
+ String get content => this._content;
+
+ /** Sets the value of "content" */
+ set content(String value) {
+ _content = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('content')
+ String _content;
+
+ /** Gets the value of "cursor" */
+ String get cursor => this._cursor;
+
+ /** Sets the value of "cursor" */
+ set cursor(String value) {
+ _cursor = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('cursor')
+ String _cursor;
+
+ /** Gets the value of "direction" */
+ String get direction => this._direction;
+
+ /** Sets the value of "direction" */
+ set direction(String value) {
+ _direction = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('direction')
+ String _direction;
+
+ /** Gets the value of "display" */
+ String get display => this._display;
+
+ /** Sets the value of "display" */
+ set display(String value) {
+ _display = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('display')
+ String _display;
+
+ /** Gets the value of "empty-cells" */
+ String get emptyCells => this._emptyCells;
+
+ /** Sets the value of "empty-cells" */
+ set emptyCells(String value) {
+ _emptyCells = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('emptyCells')
+ String _emptyCells;
+
+ /** Gets the value of "font" */
+ String get font => this._font;
+
+ /** Sets the value of "font" */
+ set font(String value) {
+ _font = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('font')
+ String _font;
+
+ /** Gets the value of "font-family" */
+ String get fontFamily => this._fontFamily;
+
+ /** Sets the value of "font-family" */
+ set fontFamily(String value) {
+ _fontFamily = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('fontFamily')
+ String _fontFamily;
+
+ /** Gets the value of "font-size" */
+ String get fontSize => this._fontSize;
+
+ /** Sets the value of "font-size" */
+ set fontSize(String value) {
+ _fontSize = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('fontSize')
+ String _fontSize;
+
+ /** Gets the value of "font-style" */
+ String get fontStyle => this._fontStyle;
+
+ /** Sets the value of "font-style" */
+ set fontStyle(String value) {
+ _fontStyle = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('fontStyle')
+ String _fontStyle;
+
+ /** Gets the value of "font-variant" */
+ String get fontVariant => this._fontVariant;
+
+ /** Sets the value of "font-variant" */
+ set fontVariant(String value) {
+ _fontVariant = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('fontVariant')
+ String _fontVariant;
+
+ /** Gets the value of "font-weight" */
+ String get fontWeight => this._fontWeight;
+
+ /** Sets the value of "font-weight" */
+ set fontWeight(String value) {
+ _fontWeight = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('fontWeight')
+ String _fontWeight;
+
+ /** Gets the value of "height" */
+ String get height => this._height;
+
+ /** Sets the value of "height" */
+ set height(String value) {
+ _height = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('height')
+ String _height;
+
+ /** Gets the value of "left" */
+ String get left => this._left;
+
+ /** Sets the value of "left" */
+ set left(String value) {
+ _left = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('left')
+ String _left;
+
+ /** Gets the value of "letter-spacing" */
+ String get letterSpacing => this._letterSpacing;
+
+ /** Sets the value of "letter-spacing" */
+ set letterSpacing(String value) {
+ _letterSpacing = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('letterSpacing')
+ String _letterSpacing;
+
+ /** Gets the value of "line-height" */
+ String get lineHeight => this._lineHeight;
+
+ /** Sets the value of "line-height" */
+ set lineHeight(String value) {
+ _lineHeight = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('lineHeight')
+ String _lineHeight;
+
+ /** Gets the value of "list-style" */
+ String get listStyle => this._listStyle;
+
+ /** Sets the value of "list-style" */
+ set listStyle(String value) {
+ _listStyle = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('listStyle')
+ String _listStyle;
+
+ /** Gets the value of "list-style-image" */
+ String get listStyleImage => this._listStyleImage;
+
+ /** Sets the value of "list-style-image" */
+ set listStyleImage(String value) {
+ _listStyleImage = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('listStyleImage')
+ String _listStyleImage;
+
+ /** Gets the value of "list-style-position" */
+ String get listStylePosition => this._listStylePosition;
+
+ /** Sets the value of "list-style-position" */
+ set listStylePosition(String value) {
+ _listStylePosition = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('listStylePosition')
+ String _listStylePosition;
+
+ /** Gets the value of "list-style-type" */
+ String get listStyleType => this._listStyleType;
+
+ /** Sets the value of "list-style-type" */
+ set listStyleType(String value) {
+ _listStyleType = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('listStyleType')
+ String _listStyleType;
+
+ /** Gets the value of "margin" */
+ String get margin => this._margin;
+
+ /** Sets the value of "margin" */
+ set margin(String value) {
+ _margin = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('margin')
+ String _margin;
+
+ /** Gets the value of "margin-bottom" */
+ String get marginBottom => this._marginBottom;
+
+ /** Sets the value of "margin-bottom" */
+ set marginBottom(String value) {
+ _marginBottom = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('marginBottom')
+ String _marginBottom;
+
+ /** Gets the value of "margin-left" */
+ String get marginLeft => this._marginLeft;
+
+ /** Sets the value of "margin-left" */
+ set marginLeft(String value) {
+ _marginLeft = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('marginLeft')
+ String _marginLeft;
+
+ /** Gets the value of "margin-right" */
+ String get marginRight => this._marginRight;
+
+ /** Sets the value of "margin-right" */
+ set marginRight(String value) {
+ _marginRight = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('marginRight')
+ String _marginRight;
+
+ /** Gets the value of "margin-top" */
+ String get marginTop => this._marginTop;
+
+ /** Sets the value of "margin-top" */
+ set marginTop(String value) {
+ _marginTop = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('marginTop')
+ String _marginTop;
+
+ /** Gets the value of "max-height" */
+ String get maxHeight => this._maxHeight;
+
+ /** Sets the value of "max-height" */
+ set maxHeight(String value) {
+ _maxHeight = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('maxHeight')
+ String _maxHeight;
+
+ /** Gets the value of "max-width" */
+ String get maxWidth => this._maxWidth;
+
+ /** Sets the value of "max-width" */
+ set maxWidth(String value) {
+ _maxWidth = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('maxWidth')
+ String _maxWidth;
+
+ /** Gets the value of "min-height" */
+ String get minHeight => this._minHeight;
+
+ /** Sets the value of "min-height" */
+ set minHeight(String value) {
+ _minHeight = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('minHeight')
+ String _minHeight;
+
+ /** Gets the value of "min-width" */
+ String get minWidth => this._minWidth;
+
+ /** Sets the value of "min-width" */
+ set minWidth(String value) {
+ _minWidth = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('minWidth')
+ String _minWidth;
+
+ /** Gets the value of "outline" */
+ String get outline => this._outline;
+
+ /** Sets the value of "outline" */
+ set outline(String value) {
+ _outline = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('outline')
+ String _outline;
+
+ /** Gets the value of "outline-color" */
+ String get outlineColor => this._outlineColor;
+
+ /** Sets the value of "outline-color" */
+ set outlineColor(String value) {
+ _outlineColor = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('outlineColor')
+ String _outlineColor;
+
+ /** Gets the value of "outline-style" */
+ String get outlineStyle => this._outlineStyle;
+
+ /** Sets the value of "outline-style" */
+ set outlineStyle(String value) {
+ _outlineStyle = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('outlineStyle')
+ String _outlineStyle;
+
+ /** Gets the value of "outline-width" */
+ String get outlineWidth => this._outlineWidth;
+
+ /** Sets the value of "outline-width" */
+ set outlineWidth(String value) {
+ _outlineWidth = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('outlineWidth')
+ String _outlineWidth;
+
+ /** Gets the value of "overflow" */
+ String get overflow => this._overflow;
+
+ /** Sets the value of "overflow" */
+ set overflow(String value) {
+ _overflow = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('overflow')
+ String _overflow;
+
+ /** Gets the value of "padding" */
+ String get padding => this._padding;
+
+ /** Sets the value of "padding" */
+ set padding(String value) {
+ _padding = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('padding')
+ String _padding;
+
+ /** Gets the value of "padding-bottom" */
+ String get paddingBottom => this._paddingBottom;
+
+ /** Sets the value of "padding-bottom" */
+ set paddingBottom(String value) {
+ _paddingBottom = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('paddingBottom')
+ String _paddingBottom;
+
+ /** Gets the value of "padding-left" */
+ String get paddingLeft => this._paddingLeft;
+
+ /** Sets the value of "padding-left" */
+ set paddingLeft(String value) {
+ _paddingLeft = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('paddingLeft')
+ String _paddingLeft;
+
+ /** Gets the value of "padding-right" */
+ String get paddingRight => this._paddingRight;
+
+ /** Sets the value of "padding-right" */
+ set paddingRight(String value) {
+ _paddingRight = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('paddingRight')
+ String _paddingRight;
+
+ /** Gets the value of "padding-top" */
+ String get paddingTop => this._paddingTop;
+
+ /** Sets the value of "padding-top" */
+ set paddingTop(String value) {
+ _paddingTop = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('paddingTop')
+ String _paddingTop;
+
+ /** Gets the value of "page-break-after" */
+ String get pageBreakAfter => this._pageBreakAfter;
+
+ /** Sets the value of "page-break-after" */
+ set pageBreakAfter(String value) {
+ _pageBreakAfter = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('pageBreakAfter')
+ String _pageBreakAfter;
+
+ /** Gets the value of "page-break-before" */
+ String get pageBreakBefore => this._pageBreakBefore;
+
+ /** Sets the value of "page-break-before" */
+ set pageBreakBefore(String value) {
+ _pageBreakBefore = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('pageBreakBefore')
+ String _pageBreakBefore;
+
+ /** Gets the value of "page-break-inside" */
+ String get pageBreakInside => this._pageBreakInside;
+
+ /** Sets the value of "page-break-inside" */
+ set pageBreakInside(String value) {
+ _pageBreakInside = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('pageBreakInside')
+ String _pageBreakInside;
+
+ /** Gets the value of "position" */
+ String get position => this._position;
+
+ /** Sets the value of "position" */
+ set position(String value) {
+ _position = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('position')
+ String _position;
+
+ /** Gets the value of "quotes" */
+ String get quotes => this._quotes;
+
+ /** Sets the value of "quotes" */
+ set quotes(String value) {
+ _quotes = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('quotes')
+ String _quotes;
+
+ /** Gets the value of "right" */
+ String get right => this._right;
+
+ /** Sets the value of "right" */
+ set right(String value) {
+ _right = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('right')
+ String _right;
+
+ /** Gets the value of "table-layout" */
+ String get tableLayout => this._tableLayout;
+
+ /** Sets the value of "table-layout" */
+ set tableLayout(String value) {
+ _tableLayout = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('tableLayout')
+ String _tableLayout;
+
+ /** Gets the value of "text-align" */
+ String get textAlign => this._textAlign;
+
+ /** Sets the value of "text-align" */
+ set textAlign(String value) {
+ _textAlign = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('textAlign')
+ String _textAlign;
+
+ /** Gets the value of "text-decoration" */
+ String get textDecoration => this._textDecoration;
+
+ /** Sets the value of "text-decoration" */
+ set textDecoration(String value) {
+ _textDecoration = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('textDecoration')
+ String _textDecoration;
+
+ /** Gets the value of "text-indent" */
+ String get textIndent => this._textIndent;
+
+ /** Sets the value of "text-indent" */
+ set textIndent(String value) {
+ _textIndent = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('textIndent')
+ String _textIndent;
+
+ /** Gets the value of "text-transform" */
+ String get textTransform => this._textTransform;
+
+ /** Sets the value of "text-transform" */
+ set textTransform(String value) {
+ _textTransform = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('textTransform')
+ String _textTransform;
+
+ /** Gets the value of "top" */
+ String get top => this._top;
+
+ /** Sets the value of "top" */
+ set top(String value) {
+ _top = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('top')
+ String _top;
+
+ /** Gets the value of "unicode-bidi" */
+ String get unicodeBidi => this._unicodeBidi;
+
+ /** Sets the value of "unicode-bidi" */
+ set unicodeBidi(String value) {
+ _unicodeBidi = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('unicodeBidi')
+ String _unicodeBidi;
+
+ /** Gets the value of "vertical-align" */
+ String get verticalAlign => this._verticalAlign;
+
+ /** Sets the value of "vertical-align" */
+ set verticalAlign(String value) {
+ _verticalAlign = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('verticalAlign')
+ String _verticalAlign;
+
+ /** Gets the value of "visibility" */
+ String get visibility => this._visibility;
+
+ /** Sets the value of "visibility" */
+ set visibility(String value) {
+ _visibility = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('visibility')
+ String _visibility;
+
+ /** Gets the value of "white-space" */
+ String get whiteSpace => this._whiteSpace;
+
+ /** Sets the value of "white-space" */
+ set whiteSpace(String value) {
+ _whiteSpace = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('whiteSpace')
+ String _whiteSpace;
+
+ /** Gets the value of "width" */
+ String get width => this._width;
+
+ /** Sets the value of "width" */
+ set width(String value) {
+ _width = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('width')
+ String _width;
+
+ /** Gets the value of "word-spacing" */
+ String get wordSpacing => this._wordSpacing;
+
+ /** Sets the value of "word-spacing" */
+ set wordSpacing(String value) {
+ _wordSpacing = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('wordSpacing')
+ String _wordSpacing;
+
+ /** Gets the value of "z-index" */
+ String get zIndex => this._zIndex;
+
+ /** Sets the value of "z-index" */
+ set zIndex(String value) {
+ _zIndex = value == null ? '' : value;
+ }
+
+ @Returns('String')
+ @JSName('zIndex')
+ String _zIndex;
+}
+
+class _CssStyleDeclarationSet extends Object with CssStyleDeclarationBase {
+ final Iterable<Element> _elementIterable;
+ Iterable<CssStyleDeclaration> _elementCssStyleDeclarationSetIterable;
+
+ _CssStyleDeclarationSet(this._elementIterable) {
+ _elementCssStyleDeclarationSetIterable =
+ new List.from(_elementIterable).map((e) => e.style);
+ }
+
+ String getPropertyValue(String propertyName) =>
+ _elementCssStyleDeclarationSetIterable.first
+ .getPropertyValue(propertyName);
+
+ void setProperty(String propertyName, String value, [String priority]) {
+ _elementCssStyleDeclarationSetIterable
+ .forEach((e) => e.setProperty(propertyName, value, priority));
+ }
+
+ void _setAll(String propertyName, String value) {
+ value = value == null ? '' : value;
+ for (Element element in _elementIterable) {
+ JS('void', '#.style[#] = #', element, propertyName, value);
+ }
+ }
+
+ /** Sets the value of "background" */
+ set background(String value) {
+ _setAll('background', value);
+ }
+
+ /** Sets the value of "background-attachment" */
+ set backgroundAttachment(String value) {
+ _setAll('backgroundAttachment', value);
+ }
+
+ /** Sets the value of "background-color" */
+ set backgroundColor(String value) {
+ _setAll('backgroundColor', value);
+ }
+
+ /** Sets the value of "background-image" */
+ set backgroundImage(String value) {
+ _setAll('backgroundImage', value);
+ }
+
+ /** Sets the value of "background-position" */
+ set backgroundPosition(String value) {
+ _setAll('backgroundPosition', value);
+ }
+
+ /** Sets the value of "background-repeat" */
+ set backgroundRepeat(String value) {
+ _setAll('backgroundRepeat', value);
+ }
+
+ /** Sets the value of "border" */
+ set border(String value) {
+ _setAll('border', value);
+ }
+
+ /** Sets the value of "border-bottom" */
+ set borderBottom(String value) {
+ _setAll('borderBottom', value);
+ }
+
+ /** Sets the value of "border-bottom-color" */
+ set borderBottomColor(String value) {
+ _setAll('borderBottomColor', value);
+ }
+
+ /** Sets the value of "border-bottom-style" */
+ set borderBottomStyle(String value) {
+ _setAll('borderBottomStyle', value);
+ }
+
+ /** Sets the value of "border-bottom-width" */
+ set borderBottomWidth(String value) {
+ _setAll('borderBottomWidth', value);
+ }
+
+ /** Sets the value of "border-collapse" */
+ set borderCollapse(String value) {
+ _setAll('borderCollapse', value);
+ }
+
+ /** Sets the value of "border-color" */
+ set borderColor(String value) {
+ _setAll('borderColor', value);
+ }
+
+ /** Sets the value of "border-left" */
+ set borderLeft(String value) {
+ _setAll('borderLeft', value);
+ }
+
+ /** Sets the value of "border-left-color" */
+ set borderLeftColor(String value) {
+ _setAll('borderLeftColor', value);
+ }
+
+ /** Sets the value of "border-left-style" */
+ set borderLeftStyle(String value) {
+ _setAll('borderLeftStyle', value);
+ }
+
+ /** Sets the value of "border-left-width" */
+ set borderLeftWidth(String value) {
+ _setAll('borderLeftWidth', value);
+ }
+
+ /** Sets the value of "border-right" */
+ set borderRight(String value) {
+ _setAll('borderRight', value);
+ }
+
+ /** Sets the value of "border-right-color" */
+ set borderRightColor(String value) {
+ _setAll('borderRightColor', value);
+ }
+
+ /** Sets the value of "border-right-style" */
+ set borderRightStyle(String value) {
+ _setAll('borderRightStyle', value);
+ }
+
+ /** Sets the value of "border-right-width" */
+ set borderRightWidth(String value) {
+ _setAll('borderRightWidth', value);
+ }
+
+ /** Sets the value of "border-spacing" */
+ set borderSpacing(String value) {
+ _setAll('borderSpacing', value);
+ }
+
+ /** Sets the value of "border-style" */
+ set borderStyle(String value) {
+ _setAll('borderStyle', value);
+ }
+
+ /** Sets the value of "border-top" */
+ set borderTop(String value) {
+ _setAll('borderTop', value);
+ }
+
+ /** Sets the value of "border-top-color" */
+ set borderTopColor(String value) {
+ _setAll('borderTopColor', value);
+ }
+
+ /** Sets the value of "border-top-style" */
+ set borderTopStyle(String value) {
+ _setAll('borderTopStyle', value);
+ }
+
+ /** Sets the value of "border-top-width" */
+ set borderTopWidth(String value) {
+ _setAll('borderTopWidth', value);
+ }
+
+ /** Sets the value of "border-width" */
+ set borderWidth(String value) {
+ _setAll('borderWidth', value);
+ }
+
+ /** Sets the value of "bottom" */
+ set bottom(String value) {
+ _setAll('bottom', value);
+ }
+
+ /** Sets the value of "caption-side" */
+ set captionSide(String value) {
+ _setAll('captionSide', value);
+ }
+
+ /** Sets the value of "clear" */
+ set clear(String value) {
+ _setAll('clear', value);
+ }
+
+ /** Sets the value of "clip" */
+ set clip(String value) {
+ _setAll('clip', value);
+ }
+
+ /** Sets the value of "color" */
+ set color(String value) {
+ _setAll('color', value);
+ }
+
+ /** Sets the value of "content" */
+ set content(String value) {
+ _setAll('content', value);
+ }
+
+ /** Sets the value of "cursor" */
+ set cursor(String value) {
+ _setAll('cursor', value);
+ }
+
+ /** Sets the value of "direction" */
+ set direction(String value) {
+ _setAll('direction', value);
+ }
+
+ /** Sets the value of "display" */
+ set display(String value) {
+ _setAll('display', value);
+ }
+
+ /** Sets the value of "empty-cells" */
+ set emptyCells(String value) {
+ _setAll('emptyCells', value);
+ }
+
+ /** Sets the value of "font" */
+ set font(String value) {
+ _setAll('font', value);
+ }
+
+ /** Sets the value of "font-family" */
+ set fontFamily(String value) {
+ _setAll('fontFamily', value);
+ }
+
+ /** Sets the value of "font-size" */
+ set fontSize(String value) {
+ _setAll('fontSize', value);
+ }
+
+ /** Sets the value of "font-style" */
+ set fontStyle(String value) {
+ _setAll('fontStyle', value);
+ }
+
+ /** Sets the value of "font-variant" */
+ set fontVariant(String value) {
+ _setAll('fontVariant', value);
+ }
+
+ /** Sets the value of "font-weight" */
+ set fontWeight(String value) {
+ _setAll('fontWeight', value);
+ }
+
+ /** Sets the value of "height" */
+ set height(String value) {
+ _setAll('height', value);
+ }
+
+ /** Sets the value of "left" */
+ set left(String value) {
+ _setAll('left', value);
+ }
+
+ /** Sets the value of "letter-spacing" */
+ set letterSpacing(String value) {
+ _setAll('letterSpacing', value);
+ }
+
+ /** Sets the value of "line-height" */
+ set lineHeight(String value) {
+ _setAll('lineHeight', value);
+ }
+
+ /** Sets the value of "list-style" */
+ set listStyle(String value) {
+ _setAll('listStyle', value);
+ }
+
+ /** Sets the value of "list-style-image" */
+ set listStyleImage(String value) {
+ _setAll('listStyleImage', value);
+ }
+
+ /** Sets the value of "list-style-position" */
+ set listStylePosition(String value) {
+ _setAll('listStylePosition', value);
+ }
+
+ /** Sets the value of "list-style-type" */
+ set listStyleType(String value) {
+ _setAll('listStyleType', value);
+ }
+
+ /** Sets the value of "margin" */
+ set margin(String value) {
+ _setAll('margin', value);
+ }
+
+ /** Sets the value of "margin-bottom" */
+ set marginBottom(String value) {
+ _setAll('marginBottom', value);
+ }
+
+ /** Sets the value of "margin-left" */
+ set marginLeft(String value) {
+ _setAll('marginLeft', value);
+ }
+
+ /** Sets the value of "margin-right" */
+ set marginRight(String value) {
+ _setAll('marginRight', value);
+ }
+
+ /** Sets the value of "margin-top" */
+ set marginTop(String value) {
+ _setAll('marginTop', value);
+ }
+
+ /** Sets the value of "max-height" */
+ set maxHeight(String value) {
+ _setAll('maxHeight', value);
+ }
+
+ /** Sets the value of "max-width" */
+ set maxWidth(String value) {
+ _setAll('maxWidth', value);
+ }
+
+ /** Sets the value of "min-height" */
+ set minHeight(String value) {
+ _setAll('minHeight', value);
+ }
+
+ /** Sets the value of "min-width" */
+ set minWidth(String value) {
+ _setAll('minWidth', value);
+ }
+
+ /** Sets the value of "outline" */
+ set outline(String value) {
+ _setAll('outline', value);
+ }
+
+ /** Sets the value of "outline-color" */
+ set outlineColor(String value) {
+ _setAll('outlineColor', value);
+ }
+
+ /** Sets the value of "outline-style" */
+ set outlineStyle(String value) {
+ _setAll('outlineStyle', value);
+ }
+
+ /** Sets the value of "outline-width" */
+ set outlineWidth(String value) {
+ _setAll('outlineWidth', value);
+ }
+
+ /** Sets the value of "overflow" */
+ set overflow(String value) {
+ _setAll('overflow', value);
+ }
+
+ /** Sets the value of "padding" */
+ set padding(String value) {
+ _setAll('padding', value);
+ }
+
+ /** Sets the value of "padding-bottom" */
+ set paddingBottom(String value) {
+ _setAll('paddingBottom', value);
+ }
+
+ /** Sets the value of "padding-left" */
+ set paddingLeft(String value) {
+ _setAll('paddingLeft', value);
+ }
+
+ /** Sets the value of "padding-right" */
+ set paddingRight(String value) {
+ _setAll('paddingRight', value);
+ }
+
+ /** Sets the value of "padding-top" */
+ set paddingTop(String value) {
+ _setAll('paddingTop', value);
+ }
+
+ /** Sets the value of "page-break-after" */
+ set pageBreakAfter(String value) {
+ _setAll('pageBreakAfter', value);
+ }
+
+ /** Sets the value of "page-break-before" */
+ set pageBreakBefore(String value) {
+ _setAll('pageBreakBefore', value);
+ }
+
+ /** Sets the value of "page-break-inside" */
+ set pageBreakInside(String value) {
+ _setAll('pageBreakInside', value);
+ }
+
+ /** Sets the value of "position" */
+ set position(String value) {
+ _setAll('position', value);
+ }
+
+ /** Sets the value of "quotes" */
+ set quotes(String value) {
+ _setAll('quotes', value);
+ }
+
+ /** Sets the value of "right" */
+ set right(String value) {
+ _setAll('right', value);
+ }
+
+ /** Sets the value of "table-layout" */
+ set tableLayout(String value) {
+ _setAll('tableLayout', value);
+ }
+
+ /** Sets the value of "text-align" */
+ set textAlign(String value) {
+ _setAll('textAlign', value);
+ }
+
+ /** Sets the value of "text-decoration" */
+ set textDecoration(String value) {
+ _setAll('textDecoration', value);
+ }
+
+ /** Sets the value of "text-indent" */
+ set textIndent(String value) {
+ _setAll('textIndent', value);
+ }
+
+ /** Sets the value of "text-transform" */
+ set textTransform(String value) {
+ _setAll('textTransform', value);
+ }
+
+ /** Sets the value of "top" */
+ set top(String value) {
+ _setAll('top', value);
+ }
+
+ /** Sets the value of "unicode-bidi" */
+ set unicodeBidi(String value) {
+ _setAll('unicodeBidi', value);
+ }
+
+ /** Sets the value of "vertical-align" */
+ set verticalAlign(String value) {
+ _setAll('verticalAlign', value);
+ }
+
+ /** Sets the value of "visibility" */
+ set visibility(String value) {
+ _setAll('visibility', value);
+ }
+
+ /** Sets the value of "white-space" */
+ set whiteSpace(String value) {
+ _setAll('whiteSpace', value);
+ }
+
+ /** Sets the value of "width" */
+ set width(String value) {
+ _setAll('width', value);
+ }
+
+ /** Sets the value of "word-spacing" */
+ set wordSpacing(String value) {
+ _setAll('wordSpacing', value);
+ }
+
+ /** Sets the value of "z-index" */
+ set zIndex(String value) {
+ _setAll('zIndex', value);
+ }
+
+ // Important note: CssStyleDeclarationSet does NOT implement every method
+ // available in CssStyleDeclaration. Some of the methods don't make so much
+ // sense in terms of having a resonable value to return when you're
+ // considering a list of Elements. You will need to manually add any of the
+ // items in the MEMBERS set if you want that functionality.
+}
+
+abstract class CssStyleDeclarationBase {
+ String getPropertyValue(String propertyName);
+ void setProperty(String propertyName, String value, [String priority]);
+
+ /** Gets the value of "align-content" */
+ String get alignContent => getPropertyValue('align-content');
+
+ /** Sets the value of "align-content" */
+ set alignContent(String value) {
+ setProperty('align-content', value, '');
+ }
+
+ /** Gets the value of "align-items" */
+ String get alignItems => getPropertyValue('align-items');
+
+ /** Sets the value of "align-items" */
+ set alignItems(String value) {
+ setProperty('align-items', value, '');
+ }
+
+ /** Gets the value of "align-self" */
+ String get alignSelf => getPropertyValue('align-self');
+
+ /** Sets the value of "align-self" */
+ set alignSelf(String value) {
+ setProperty('align-self', value, '');
+ }
+
+ /** Gets the value of "animation" */
+ String get animation => getPropertyValue('animation');
+
+ /** Sets the value of "animation" */
+ set animation(String value) {
+ setProperty('animation', value, '');
+ }
+
+ /** Gets the value of "animation-delay" */
+ String get animationDelay => getPropertyValue('animation-delay');
+
+ /** Sets the value of "animation-delay" */
+ set animationDelay(String value) {
+ setProperty('animation-delay', value, '');
+ }
+
+ /** Gets the value of "animation-direction" */
+ String get animationDirection => getPropertyValue('animation-direction');
+
+ /** Sets the value of "animation-direction" */
+ set animationDirection(String value) {
+ setProperty('animation-direction', value, '');
+ }
+
+ /** Gets the value of "animation-duration" */
+ String get animationDuration => getPropertyValue('animation-duration');
+
+ /** Sets the value of "animation-duration" */
+ set animationDuration(String value) {
+ setProperty('animation-duration', value, '');
+ }
+
+ /** Gets the value of "animation-fill-mode" */
+ String get animationFillMode => getPropertyValue('animation-fill-mode');
+
+ /** Sets the value of "animation-fill-mode" */
+ set animationFillMode(String value) {
+ setProperty('animation-fill-mode', value, '');
+ }
+
+ /** Gets the value of "animation-iteration-count" */
+ String get animationIterationCount =>
+ getPropertyValue('animation-iteration-count');
+
+ /** Sets the value of "animation-iteration-count" */
+ set animationIterationCount(String value) {
+ setProperty('animation-iteration-count', value, '');
+ }
+
+ /** Gets the value of "animation-name" */
+ String get animationName => getPropertyValue('animation-name');
+
+ /** Sets the value of "animation-name" */
+ set animationName(String value) {
+ setProperty('animation-name', value, '');
+ }
+
+ /** Gets the value of "animation-play-state" */
+ String get animationPlayState => getPropertyValue('animation-play-state');
+
+ /** Sets the value of "animation-play-state" */
+ set animationPlayState(String value) {
+ setProperty('animation-play-state', value, '');
+ }
+
+ /** Gets the value of "animation-timing-function" */
+ String get animationTimingFunction =>
+ getPropertyValue('animation-timing-function');
+
+ /** Sets the value of "animation-timing-function" */
+ set animationTimingFunction(String value) {
+ setProperty('animation-timing-function', value, '');
+ }
+
+ /** Gets the value of "app-region" */
+ String get appRegion => getPropertyValue('app-region');
+
+ /** Sets the value of "app-region" */
+ set appRegion(String value) {
+ setProperty('app-region', value, '');
+ }
+
+ /** Gets the value of "appearance" */
+ String get appearance => getPropertyValue('appearance');
+
+ /** Sets the value of "appearance" */
+ set appearance(String value) {
+ setProperty('appearance', value, '');
+ }
+
+ /** Gets the value of "aspect-ratio" */
+ String get aspectRatio => getPropertyValue('aspect-ratio');
+
+ /** Sets the value of "aspect-ratio" */
+ set aspectRatio(String value) {
+ setProperty('aspect-ratio', value, '');
+ }
+
+ /** Gets the value of "backface-visibility" */
+ String get backfaceVisibility => getPropertyValue('backface-visibility');
+
+ /** Sets the value of "backface-visibility" */
+ set backfaceVisibility(String value) {
+ setProperty('backface-visibility', value, '');
+ }
+
+ /** Gets the value of "background" */
+ String get background => getPropertyValue('background');
+
+ /** Sets the value of "background" */
+ set background(String value) {
+ setProperty('background', value, '');
+ }
+
+ /** Gets the value of "background-attachment" */
+ String get backgroundAttachment => getPropertyValue('background-attachment');
+
+ /** Sets the value of "background-attachment" */
+ set backgroundAttachment(String value) {
+ setProperty('background-attachment', value, '');
+ }
+
+ /** Gets the value of "background-blend-mode" */
+ String get backgroundBlendMode => getPropertyValue('background-blend-mode');
+
+ /** Sets the value of "background-blend-mode" */
+ set backgroundBlendMode(String value) {
+ setProperty('background-blend-mode', value, '');
+ }
+
+ /** Gets the value of "background-clip" */
+ String get backgroundClip => getPropertyValue('background-clip');
+
+ /** Sets the value of "background-clip" */
+ set backgroundClip(String value) {
+ setProperty('background-clip', value, '');
+ }
+
+ /** Gets the value of "background-color" */
+ String get backgroundColor => getPropertyValue('background-color');
+
+ /** Sets the value of "background-color" */
+ set backgroundColor(String value) {
+ setProperty('background-color', value, '');
+ }
+
+ /** Gets the value of "background-composite" */
+ String get backgroundComposite => getPropertyValue('background-composite');
+
+ /** Sets the value of "background-composite" */
+ set backgroundComposite(String value) {
+ setProperty('background-composite', value, '');
+ }
+
+ /** Gets the value of "background-image" */
+ String get backgroundImage => getPropertyValue('background-image');
+
+ /** Sets the value of "background-image" */
+ set backgroundImage(String value) {
+ setProperty('background-image', value, '');
+ }
+
+ /** Gets the value of "background-origin" */
+ String get backgroundOrigin => getPropertyValue('background-origin');
+
+ /** Sets the value of "background-origin" */
+ set backgroundOrigin(String value) {
+ setProperty('background-origin', value, '');
+ }
+
+ /** Gets the value of "background-position" */
+ String get backgroundPosition => getPropertyValue('background-position');
+
+ /** Sets the value of "background-position" */
+ set backgroundPosition(String value) {
+ setProperty('background-position', value, '');
+ }
+
+ /** Gets the value of "background-position-x" */
+ String get backgroundPositionX => getPropertyValue('background-position-x');
+
+ /** Sets the value of "background-position-x" */
+ set backgroundPositionX(String value) {
+ setProperty('background-position-x', value, '');
+ }
+
+ /** Gets the value of "background-position-y" */
+ String get backgroundPositionY => getPropertyValue('background-position-y');
+
+ /** Sets the value of "background-position-y" */
+ set backgroundPositionY(String value) {
+ setProperty('background-position-y', value, '');
+ }
+
+ /** Gets the value of "background-repeat" */
+ String get backgroundRepeat => getPropertyValue('background-repeat');
+
+ /** Sets the value of "background-repeat" */
+ set backgroundRepeat(String value) {
+ setProperty('background-repeat', value, '');
+ }
+
+ /** Gets the value of "background-repeat-x" */
+ String get backgroundRepeatX => getPropertyValue('background-repeat-x');
+
+ /** Sets the value of "background-repeat-x" */
+ set backgroundRepeatX(String value) {
+ setProperty('background-repeat-x', value, '');
+ }
+
+ /** Gets the value of "background-repeat-y" */
+ String get backgroundRepeatY => getPropertyValue('background-repeat-y');
+
+ /** Sets the value of "background-repeat-y" */
+ set backgroundRepeatY(String value) {
+ setProperty('background-repeat-y', value, '');
+ }
+
+ /** Gets the value of "background-size" */
+ String get backgroundSize => getPropertyValue('background-size');
+
+ /** Sets the value of "background-size" */
+ set backgroundSize(String value) {
+ setProperty('background-size', value, '');
+ }
+
+ /** Gets the value of "border" */
+ String get border => getPropertyValue('border');
+
+ /** Sets the value of "border" */
+ set border(String value) {
+ setProperty('border', value, '');
+ }
+
+ /** Gets the value of "border-after" */
+ String get borderAfter => getPropertyValue('border-after');
+
+ /** Sets the value of "border-after" */
+ set borderAfter(String value) {
+ setProperty('border-after', value, '');
+ }
+
+ /** Gets the value of "border-after-color" */
+ String get borderAfterColor => getPropertyValue('border-after-color');
+
+ /** Sets the value of "border-after-color" */
+ set borderAfterColor(String value) {
+ setProperty('border-after-color', value, '');
+ }
+
+ /** Gets the value of "border-after-style" */
+ String get borderAfterStyle => getPropertyValue('border-after-style');
+
+ /** Sets the value of "border-after-style" */
+ set borderAfterStyle(String value) {
+ setProperty('border-after-style', value, '');
+ }
+
+ /** Gets the value of "border-after-width" */
+ String get borderAfterWidth => getPropertyValue('border-after-width');
+
+ /** Sets the value of "border-after-width" */
+ set borderAfterWidth(String value) {
+ setProperty('border-after-width', value, '');
+ }
+
+ /** Gets the value of "border-before" */
+ String get borderBefore => getPropertyValue('border-before');
+
+ /** Sets the value of "border-before" */
+ set borderBefore(String value) {
+ setProperty('border-before', value, '');
+ }
+
+ /** Gets the value of "border-before-color" */
+ String get borderBeforeColor => getPropertyValue('border-before-color');
+
+ /** Sets the value of "border-before-color" */
+ set borderBeforeColor(String value) {
+ setProperty('border-before-color', value, '');
+ }
+
+ /** Gets the value of "border-before-style" */
+ String get borderBeforeStyle => getPropertyValue('border-before-style');
+
+ /** Sets the value of "border-before-style" */
+ set borderBeforeStyle(String value) {
+ setProperty('border-before-style', value, '');
+ }
+
+ /** Gets the value of "border-before-width" */
+ String get borderBeforeWidth => getPropertyValue('border-before-width');
+
+ /** Sets the value of "border-before-width" */
+ set borderBeforeWidth(String value) {
+ setProperty('border-before-width', value, '');
+ }
+
+ /** Gets the value of "border-bottom" */
+ String get borderBottom => getPropertyValue('border-bottom');
+
+ /** Sets the value of "border-bottom" */
+ set borderBottom(String value) {
+ setProperty('border-bottom', value, '');
+ }
+
+ /** Gets the value of "border-bottom-color" */
+ String get borderBottomColor => getPropertyValue('border-bottom-color');
+
+ /** Sets the value of "border-bottom-color" */
+ set borderBottomColor(String value) {
+ setProperty('border-bottom-color', value, '');
+ }
+
+ /** Gets the value of "border-bottom-left-radius" */
+ String get borderBottomLeftRadius =>
+ getPropertyValue('border-bottom-left-radius');
+
+ /** Sets the value of "border-bottom-left-radius" */
+ set borderBottomLeftRadius(String value) {
+ setProperty('border-bottom-left-radius', value, '');
+ }
+
+ /** Gets the value of "border-bottom-right-radius" */
+ String get borderBottomRightRadius =>
+ getPropertyValue('border-bottom-right-radius');
+
+ /** Sets the value of "border-bottom-right-radius" */
+ set borderBottomRightRadius(String value) {
+ setProperty('border-bottom-right-radius', value, '');
+ }
+
+ /** Gets the value of "border-bottom-style" */
+ String get borderBottomStyle => getPropertyValue('border-bottom-style');
+
+ /** Sets the value of "border-bottom-style" */
+ set borderBottomStyle(String value) {
+ setProperty('border-bottom-style', value, '');
+ }
+
+ /** Gets the value of "border-bottom-width" */
+ String get borderBottomWidth => getPropertyValue('border-bottom-width');
+
+ /** Sets the value of "border-bottom-width" */
+ set borderBottomWidth(String value) {
+ setProperty('border-bottom-width', value, '');
+ }
+
+ /** Gets the value of "border-collapse" */
+ String get borderCollapse => getPropertyValue('border-collapse');
+
+ /** Sets the value of "border-collapse" */
+ set borderCollapse(String value) {
+ setProperty('border-collapse', value, '');
+ }
+
+ /** Gets the value of "border-color" */
+ String get borderColor => getPropertyValue('border-color');
+
+ /** Sets the value of "border-color" */
+ set borderColor(String value) {
+ setProperty('border-color', value, '');
+ }
+
+ /** Gets the value of "border-end" */
+ String get borderEnd => getPropertyValue('border-end');
+
+ /** Sets the value of "border-end" */
+ set borderEnd(String value) {
+ setProperty('border-end', value, '');
+ }
+
+ /** Gets the value of "border-end-color" */
+ String get borderEndColor => getPropertyValue('border-end-color');
+
+ /** Sets the value of "border-end-color" */
+ set borderEndColor(String value) {
+ setProperty('border-end-color', value, '');
+ }
+
+ /** Gets the value of "border-end-style" */
+ String get borderEndStyle => getPropertyValue('border-end-style');
+
+ /** Sets the value of "border-end-style" */
+ set borderEndStyle(String value) {
+ setProperty('border-end-style', value, '');
+ }
+
+ /** Gets the value of "border-end-width" */
+ String get borderEndWidth => getPropertyValue('border-end-width');
+
+ /** Sets the value of "border-end-width" */
+ set borderEndWidth(String value) {
+ setProperty('border-end-width', value, '');
+ }
+
+ /** Gets the value of "border-fit" */
+ String get borderFit => getPropertyValue('border-fit');
+
+ /** Sets the value of "border-fit" */
+ set borderFit(String value) {
+ setProperty('border-fit', value, '');
+ }
+
+ /** Gets the value of "border-horizontal-spacing" */
+ String get borderHorizontalSpacing =>
+ getPropertyValue('border-horizontal-spacing');
+
+ /** Sets the value of "border-horizontal-spacing" */
+ set borderHorizontalSpacing(String value) {
+ setProperty('border-horizontal-spacing', value, '');
+ }
+
+ /** Gets the value of "border-image" */
+ String get borderImage => getPropertyValue('border-image');
+
+ /** Sets the value of "border-image" */
+ set borderImage(String value) {
+ setProperty('border-image', value, '');
+ }
+
+ /** Gets the value of "border-image-outset" */
+ String get borderImageOutset => getPropertyValue('border-image-outset');
+
+ /** Sets the value of "border-image-outset" */
+ set borderImageOutset(String value) {
+ setProperty('border-image-outset', value, '');
+ }
+
+ /** Gets the value of "border-image-repeat" */
+ String get borderImageRepeat => getPropertyValue('border-image-repeat');
+
+ /** Sets the value of "border-image-repeat" */
+ set borderImageRepeat(String value) {
+ setProperty('border-image-repeat', value, '');
+ }
+
+ /** Gets the value of "border-image-slice" */
+ String get borderImageSlice => getPropertyValue('border-image-slice');
+
+ /** Sets the value of "border-image-slice" */
+ set borderImageSlice(String value) {
+ setProperty('border-image-slice', value, '');
+ }
+
+ /** Gets the value of "border-image-source" */
+ String get borderImageSource => getPropertyValue('border-image-source');
+
+ /** Sets the value of "border-image-source" */
+ set borderImageSource(String value) {
+ setProperty('border-image-source', value, '');
+ }
+
+ /** Gets the value of "border-image-width" */
+ String get borderImageWidth => getPropertyValue('border-image-width');
+
+ /** Sets the value of "border-image-width" */
+ set borderImageWidth(String value) {
+ setProperty('border-image-width', value, '');
+ }
+
+ /** Gets the value of "border-left" */
+ String get borderLeft => getPropertyValue('border-left');
+
+ /** Sets the value of "border-left" */
+ set borderLeft(String value) {
+ setProperty('border-left', value, '');
+ }
+
+ /** Gets the value of "border-left-color" */
+ String get borderLeftColor => getPropertyValue('border-left-color');
+
+ /** Sets the value of "border-left-color" */
+ set borderLeftColor(String value) {
+ setProperty('border-left-color', value, '');
+ }
+
+ /** Gets the value of "border-left-style" */
+ String get borderLeftStyle => getPropertyValue('border-left-style');
+
+ /** Sets the value of "border-left-style" */
+ set borderLeftStyle(String value) {
+ setProperty('border-left-style', value, '');
+ }
+
+ /** Gets the value of "border-left-width" */
+ String get borderLeftWidth => getPropertyValue('border-left-width');
+
+ /** Sets the value of "border-left-width" */
+ set borderLeftWidth(String value) {
+ setProperty('border-left-width', value, '');
+ }
+
+ /** Gets the value of "border-radius" */
+ String get borderRadius => getPropertyValue('border-radius');
+
+ /** Sets the value of "border-radius" */
+ set borderRadius(String value) {
+ setProperty('border-radius', value, '');
+ }
+
+ /** Gets the value of "border-right" */
+ String get borderRight => getPropertyValue('border-right');
+
+ /** Sets the value of "border-right" */
+ set borderRight(String value) {
+ setProperty('border-right', value, '');
+ }
+
+ /** Gets the value of "border-right-color" */
+ String get borderRightColor => getPropertyValue('border-right-color');
+
+ /** Sets the value of "border-right-color" */
+ set borderRightColor(String value) {
+ setProperty('border-right-color', value, '');
+ }
+
+ /** Gets the value of "border-right-style" */
+ String get borderRightStyle => getPropertyValue('border-right-style');
+
+ /** Sets the value of "border-right-style" */
+ set borderRightStyle(String value) {
+ setProperty('border-right-style', value, '');
+ }
+
+ /** Gets the value of "border-right-width" */
+ String get borderRightWidth => getPropertyValue('border-right-width');
+
+ /** Sets the value of "border-right-width" */
+ set borderRightWidth(String value) {
+ setProperty('border-right-width', value, '');
+ }
+
+ /** Gets the value of "border-spacing" */
+ String get borderSpacing => getPropertyValue('border-spacing');
+
+ /** Sets the value of "border-spacing" */
+ set borderSpacing(String value) {
+ setProperty('border-spacing', value, '');
+ }
+
+ /** Gets the value of "border-start" */
+ String get borderStart => getPropertyValue('border-start');
+
+ /** Sets the value of "border-start" */
+ set borderStart(String value) {
+ setProperty('border-start', value, '');
+ }
+
+ /** Gets the value of "border-start-color" */
+ String get borderStartColor => getPropertyValue('border-start-color');
+
+ /** Sets the value of "border-start-color" */
+ set borderStartColor(String value) {
+ setProperty('border-start-color', value, '');
+ }
+
+ /** Gets the value of "border-start-style" */
+ String get borderStartStyle => getPropertyValue('border-start-style');
+
+ /** Sets the value of "border-start-style" */
+ set borderStartStyle(String value) {
+ setProperty('border-start-style', value, '');
+ }
+
+ /** Gets the value of "border-start-width" */
+ String get borderStartWidth => getPropertyValue('border-start-width');
+
+ /** Sets the value of "border-start-width" */
+ set borderStartWidth(String value) {
+ setProperty('border-start-width', value, '');
+ }
+
+ /** Gets the value of "border-style" */
+ String get borderStyle => getPropertyValue('border-style');
+
+ /** Sets the value of "border-style" */
+ set borderStyle(String value) {
+ setProperty('border-style', value, '');
+ }
+
+ /** Gets the value of "border-top" */
+ String get borderTop => getPropertyValue('border-top');
+
+ /** Sets the value of "border-top" */
+ set borderTop(String value) {
+ setProperty('border-top', value, '');
+ }
+
+ /** Gets the value of "border-top-color" */
+ String get borderTopColor => getPropertyValue('border-top-color');
+
+ /** Sets the value of "border-top-color" */
+ set borderTopColor(String value) {
+ setProperty('border-top-color', value, '');
+ }
+
+ /** Gets the value of "border-top-left-radius" */
+ String get borderTopLeftRadius => getPropertyValue('border-top-left-radius');
+
+ /** Sets the value of "border-top-left-radius" */
+ set borderTopLeftRadius(String value) {
+ setProperty('border-top-left-radius', value, '');
+ }
+
+ /** Gets the value of "border-top-right-radius" */
+ String get borderTopRightRadius =>
+ getPropertyValue('border-top-right-radius');
+
+ /** Sets the value of "border-top-right-radius" */
+ set borderTopRightRadius(String value) {
+ setProperty('border-top-right-radius', value, '');
+ }
+
+ /** Gets the value of "border-top-style" */
+ String get borderTopStyle => getPropertyValue('border-top-style');
+
+ /** Sets the value of "border-top-style" */
+ set borderTopStyle(String value) {
+ setProperty('border-top-style', value, '');
+ }
+
+ /** Gets the value of "border-top-width" */
+ String get borderTopWidth => getPropertyValue('border-top-width');
+
+ /** Sets the value of "border-top-width" */
+ set borderTopWidth(String value) {
+ setProperty('border-top-width', value, '');
+ }
+
+ /** Gets the value of "border-vertical-spacing" */
+ String get borderVerticalSpacing =>
+ getPropertyValue('border-vertical-spacing');
+
+ /** Sets the value of "border-vertical-spacing" */
+ set borderVerticalSpacing(String value) {
+ setProperty('border-vertical-spacing', value, '');
+ }
+
+ /** Gets the value of "border-width" */
+ String get borderWidth => getPropertyValue('border-width');
+
+ /** Sets the value of "border-width" */
+ set borderWidth(String value) {
+ setProperty('border-width', value, '');
+ }
+
+ /** Gets the value of "bottom" */
+ String get bottom => getPropertyValue('bottom');
+
+ /** Sets the value of "bottom" */
+ set bottom(String value) {
+ setProperty('bottom', value, '');
+ }
+
+ /** Gets the value of "box-align" */
+ String get boxAlign => getPropertyValue('box-align');
+
+ /** Sets the value of "box-align" */
+ set boxAlign(String value) {
+ setProperty('box-align', value, '');
+ }
+
+ /** Gets the value of "box-decoration-break" */
+ String get boxDecorationBreak => getPropertyValue('box-decoration-break');
+
+ /** Sets the value of "box-decoration-break" */
+ set boxDecorationBreak(String value) {
+ setProperty('box-decoration-break', value, '');
+ }
+
+ /** Gets the value of "box-direction" */
+ String get boxDirection => getPropertyValue('box-direction');
+
+ /** Sets the value of "box-direction" */
+ set boxDirection(String value) {
+ setProperty('box-direction', value, '');
+ }
+
+ /** Gets the value of "box-flex" */
+ String get boxFlex => getPropertyValue('box-flex');
+
+ /** Sets the value of "box-flex" */
+ set boxFlex(String value) {
+ setProperty('box-flex', value, '');
+ }
+
+ /** Gets the value of "box-flex-group" */
+ String get boxFlexGroup => getPropertyValue('box-flex-group');
+
+ /** Sets the value of "box-flex-group" */
+ set boxFlexGroup(String value) {
+ setProperty('box-flex-group', value, '');
+ }
+
+ /** Gets the value of "box-lines" */
+ String get boxLines => getPropertyValue('box-lines');
+
+ /** Sets the value of "box-lines" */
+ set boxLines(String value) {
+ setProperty('box-lines', value, '');
+ }
+
+ /** Gets the value of "box-ordinal-group" */
+ String get boxOrdinalGroup => getPropertyValue('box-ordinal-group');
+
+ /** Sets the value of "box-ordinal-group" */
+ set boxOrdinalGroup(String value) {
+ setProperty('box-ordinal-group', value, '');
+ }
+
+ /** Gets the value of "box-orient" */
+ String get boxOrient => getPropertyValue('box-orient');
+
+ /** Sets the value of "box-orient" */
+ set boxOrient(String value) {
+ setProperty('box-orient', value, '');
+ }
+
+ /** Gets the value of "box-pack" */
+ String get boxPack => getPropertyValue('box-pack');
+
+ /** Sets the value of "box-pack" */
+ set boxPack(String value) {
+ setProperty('box-pack', value, '');
+ }
+
+ /** Gets the value of "box-reflect" */
+ String get boxReflect => getPropertyValue('box-reflect');
+
+ /** Sets the value of "box-reflect" */
+ set boxReflect(String value) {
+ setProperty('box-reflect', value, '');
+ }
+
+ /** Gets the value of "box-shadow" */
+ String get boxShadow => getPropertyValue('box-shadow');
+
+ /** Sets the value of "box-shadow" */
+ set boxShadow(String value) {
+ setProperty('box-shadow', value, '');
+ }
+
+ /** Gets the value of "box-sizing" */
+ String get boxSizing => getPropertyValue('box-sizing');
+
+ /** Sets the value of "box-sizing" */
+ set boxSizing(String value) {
+ setProperty('box-sizing', value, '');
+ }
+
+ /** Gets the value of "caption-side" */
+ String get captionSide => getPropertyValue('caption-side');
+
+ /** Sets the value of "caption-side" */
+ set captionSide(String value) {
+ setProperty('caption-side', value, '');
+ }
+
+ /** Gets the value of "clear" */
+ String get clear => getPropertyValue('clear');
+
+ /** Sets the value of "clear" */
+ set clear(String value) {
+ setProperty('clear', value, '');
+ }
+
+ /** Gets the value of "clip" */
+ String get clip => getPropertyValue('clip');
+
+ /** Sets the value of "clip" */
+ set clip(String value) {
+ setProperty('clip', value, '');
+ }
+
+ /** Gets the value of "clip-path" */
+ String get clipPath => getPropertyValue('clip-path');
+
+ /** Sets the value of "clip-path" */
+ set clipPath(String value) {
+ setProperty('clip-path', value, '');
+ }
+
+ /** Gets the value of "color" */
+ String get color => getPropertyValue('color');
+
+ /** Sets the value of "color" */
+ set color(String value) {
+ setProperty('color', value, '');
+ }
+
+ /** Gets the value of "column-break-after" */
+ String get columnBreakAfter => getPropertyValue('column-break-after');
+
+ /** Sets the value of "column-break-after" */
+ set columnBreakAfter(String value) {
+ setProperty('column-break-after', value, '');
+ }
+
+ /** Gets the value of "column-break-before" */
+ String get columnBreakBefore => getPropertyValue('column-break-before');
+
+ /** Sets the value of "column-break-before" */
+ set columnBreakBefore(String value) {
+ setProperty('column-break-before', value, '');
+ }
+
+ /** Gets the value of "column-break-inside" */
+ String get columnBreakInside => getPropertyValue('column-break-inside');
+
+ /** Sets the value of "column-break-inside" */
+ set columnBreakInside(String value) {
+ setProperty('column-break-inside', value, '');
+ }
+
+ /** Gets the value of "column-count" */
+ String get columnCount => getPropertyValue('column-count');
+
+ /** Sets the value of "column-count" */
+ set columnCount(String value) {
+ setProperty('column-count', value, '');
+ }
+
+ /** Gets the value of "column-fill" */
+ String get columnFill => getPropertyValue('column-fill');
+
+ /** Sets the value of "column-fill" */
+ set columnFill(String value) {
+ setProperty('column-fill', value, '');
+ }
+
+ /** Gets the value of "column-gap" */
+ String get columnGap => getPropertyValue('column-gap');
+
+ /** Sets the value of "column-gap" */
+ set columnGap(String value) {
+ setProperty('column-gap', value, '');
+ }
+
+ /** Gets the value of "column-rule" */
+ String get columnRule => getPropertyValue('column-rule');
+
+ /** Sets the value of "column-rule" */
+ set columnRule(String value) {
+ setProperty('column-rule', value, '');
+ }
+
+ /** Gets the value of "column-rule-color" */
+ String get columnRuleColor => getPropertyValue('column-rule-color');
+
+ /** Sets the value of "column-rule-color" */
+ set columnRuleColor(String value) {
+ setProperty('column-rule-color', value, '');
+ }
+
+ /** Gets the value of "column-rule-style" */
+ String get columnRuleStyle => getPropertyValue('column-rule-style');
+
+ /** Sets the value of "column-rule-style" */
+ set columnRuleStyle(String value) {
+ setProperty('column-rule-style', value, '');
+ }
+
+ /** Gets the value of "column-rule-width" */
+ String get columnRuleWidth => getPropertyValue('column-rule-width');
+
+ /** Sets the value of "column-rule-width" */
+ set columnRuleWidth(String value) {
+ setProperty('column-rule-width', value, '');
+ }
+
+ /** Gets the value of "column-span" */
+ String get columnSpan => getPropertyValue('column-span');
+
+ /** Sets the value of "column-span" */
+ set columnSpan(String value) {
+ setProperty('column-span', value, '');
+ }
+
+ /** Gets the value of "column-width" */
+ String get columnWidth => getPropertyValue('column-width');
+
+ /** Sets the value of "column-width" */
+ set columnWidth(String value) {
+ setProperty('column-width', value, '');
+ }
+
+ /** Gets the value of "columns" */
+ String get columns => getPropertyValue('columns');
+
+ /** Sets the value of "columns" */
+ set columns(String value) {
+ setProperty('columns', value, '');
+ }
+
+ /** Gets the value of "content" */
+ String get content => getPropertyValue('content');
+
+ /** Sets the value of "content" */
+ set content(String value) {
+ setProperty('content', value, '');
+ }
+
+ /** Gets the value of "counter-increment" */
+ String get counterIncrement => getPropertyValue('counter-increment');
+
+ /** Sets the value of "counter-increment" */
+ set counterIncrement(String value) {
+ setProperty('counter-increment', value, '');
+ }
+
+ /** Gets the value of "counter-reset" */
+ String get counterReset => getPropertyValue('counter-reset');
+
+ /** Sets the value of "counter-reset" */
+ set counterReset(String value) {
+ setProperty('counter-reset', value, '');
+ }
+
+ /** Gets the value of "cursor" */
+ String get cursor => getPropertyValue('cursor');
+
+ /** Sets the value of "cursor" */
+ set cursor(String value) {
+ setProperty('cursor', value, '');
+ }
+
+ /** Gets the value of "direction" */
+ String get direction => getPropertyValue('direction');
+
+ /** Sets the value of "direction" */
+ set direction(String value) {
+ setProperty('direction', value, '');
+ }
+
+ /** Gets the value of "display" */
+ String get display => getPropertyValue('display');
+
+ /** Sets the value of "display" */
+ set display(String value) {
+ setProperty('display', value, '');
+ }
+
+ /** Gets the value of "empty-cells" */
+ String get emptyCells => getPropertyValue('empty-cells');
+
+ /** Sets the value of "empty-cells" */
+ set emptyCells(String value) {
+ setProperty('empty-cells', value, '');
+ }
+
+ /** Gets the value of "filter" */
+ String get filter => getPropertyValue('filter');
+
+ /** Sets the value of "filter" */
+ set filter(String value) {
+ setProperty('filter', value, '');
+ }
+
+ /** Gets the value of "flex" */
+ String get flex => getPropertyValue('flex');
+
+ /** Sets the value of "flex" */
+ set flex(String value) {
+ setProperty('flex', value, '');
+ }
+
+ /** Gets the value of "flex-basis" */
+ String get flexBasis => getPropertyValue('flex-basis');
+
+ /** Sets the value of "flex-basis" */
+ set flexBasis(String value) {
+ setProperty('flex-basis', value, '');
+ }
+
+ /** Gets the value of "flex-direction" */
+ String get flexDirection => getPropertyValue('flex-direction');
+
+ /** Sets the value of "flex-direction" */
+ set flexDirection(String value) {
+ setProperty('flex-direction', value, '');
+ }
+
+ /** Gets the value of "flex-flow" */
+ String get flexFlow => getPropertyValue('flex-flow');
+
+ /** Sets the value of "flex-flow" */
+ set flexFlow(String value) {
+ setProperty('flex-flow', value, '');
+ }
+
+ /** Gets the value of "flex-grow" */
+ String get flexGrow => getPropertyValue('flex-grow');
+
+ /** Sets the value of "flex-grow" */
+ set flexGrow(String value) {
+ setProperty('flex-grow', value, '');
+ }
+
+ /** Gets the value of "flex-shrink" */
+ String get flexShrink => getPropertyValue('flex-shrink');
+
+ /** Sets the value of "flex-shrink" */
+ set flexShrink(String value) {
+ setProperty('flex-shrink', value, '');
+ }
+
+ /** Gets the value of "flex-wrap" */
+ String get flexWrap => getPropertyValue('flex-wrap');
+
+ /** Sets the value of "flex-wrap" */
+ set flexWrap(String value) {
+ setProperty('flex-wrap', value, '');
+ }
+
+ /** Gets the value of "float" */
+ String get float => getPropertyValue('float');
+
+ /** Sets the value of "float" */
+ set float(String value) {
+ setProperty('float', value, '');
+ }
+
+ /** Gets the value of "font" */
+ String get font => getPropertyValue('font');
+
+ /** Sets the value of "font" */
+ set font(String value) {
+ setProperty('font', value, '');
+ }
+
+ /** Gets the value of "font-family" */
+ String get fontFamily => getPropertyValue('font-family');
+
+ /** Sets the value of "font-family" */
+ set fontFamily(String value) {
+ setProperty('font-family', value, '');
+ }
+
+ /** Gets the value of "font-feature-settings" */
+ String get fontFeatureSettings => getPropertyValue('font-feature-settings');
+
+ /** Sets the value of "font-feature-settings" */
+ set fontFeatureSettings(String value) {
+ setProperty('font-feature-settings', value, '');
+ }
+
+ /** Gets the value of "font-kerning" */
+ String get fontKerning => getPropertyValue('font-kerning');
+
+ /** Sets the value of "font-kerning" */
+ set fontKerning(String value) {
+ setProperty('font-kerning', value, '');
+ }
+
+ /** Gets the value of "font-size" */
+ String get fontSize => getPropertyValue('font-size');
+
+ /** Sets the value of "font-size" */
+ set fontSize(String value) {
+ setProperty('font-size', value, '');
+ }
+
+ /** Gets the value of "font-size-delta" */
+ String get fontSizeDelta => getPropertyValue('font-size-delta');
+
+ /** Sets the value of "font-size-delta" */
+ set fontSizeDelta(String value) {
+ setProperty('font-size-delta', value, '');
+ }
+
+ /** Gets the value of "font-smoothing" */
+ String get fontSmoothing => getPropertyValue('font-smoothing');
+
+ /** Sets the value of "font-smoothing" */
+ set fontSmoothing(String value) {
+ setProperty('font-smoothing', value, '');
+ }
+
+ /** Gets the value of "font-stretch" */
+ String get fontStretch => getPropertyValue('font-stretch');
+
+ /** Sets the value of "font-stretch" */
+ set fontStretch(String value) {
+ setProperty('font-stretch', value, '');
+ }
+
+ /** Gets the value of "font-style" */
+ String get fontStyle => getPropertyValue('font-style');
+
+ /** Sets the value of "font-style" */
+ set fontStyle(String value) {
+ setProperty('font-style', value, '');
+ }
+
+ /** Gets the value of "font-variant" */
+ String get fontVariant => getPropertyValue('font-variant');
+
+ /** Sets the value of "font-variant" */
+ set fontVariant(String value) {
+ setProperty('font-variant', value, '');
+ }
+
+ /** Gets the value of "font-variant-ligatures" */
+ String get fontVariantLigatures => getPropertyValue('font-variant-ligatures');
+
+ /** Sets the value of "font-variant-ligatures" */
+ set fontVariantLigatures(String value) {
+ setProperty('font-variant-ligatures', value, '');
+ }
+
+ /** Gets the value of "font-weight" */
+ String get fontWeight => getPropertyValue('font-weight');
+
+ /** Sets the value of "font-weight" */
+ set fontWeight(String value) {
+ setProperty('font-weight', value, '');
+ }
+
+ /** Gets the value of "grid" */
+ String get grid => getPropertyValue('grid');
+
+ /** Sets the value of "grid" */
+ set grid(String value) {
+ setProperty('grid', value, '');
+ }
+
+ /** Gets the value of "grid-area" */
+ String get gridArea => getPropertyValue('grid-area');
+
+ /** Sets the value of "grid-area" */
+ set gridArea(String value) {
+ setProperty('grid-area', value, '');
+ }
+
+ /** Gets the value of "grid-auto-columns" */
+ String get gridAutoColumns => getPropertyValue('grid-auto-columns');
+
+ /** Sets the value of "grid-auto-columns" */
+ set gridAutoColumns(String value) {
+ setProperty('grid-auto-columns', value, '');
+ }
+
+ /** Gets the value of "grid-auto-flow" */
+ String get gridAutoFlow => getPropertyValue('grid-auto-flow');
+
+ /** Sets the value of "grid-auto-flow" */
+ set gridAutoFlow(String value) {
+ setProperty('grid-auto-flow', value, '');
+ }
+
+ /** Gets the value of "grid-auto-rows" */
+ String get gridAutoRows => getPropertyValue('grid-auto-rows');
+
+ /** Sets the value of "grid-auto-rows" */
+ set gridAutoRows(String value) {
+ setProperty('grid-auto-rows', value, '');
+ }
+
+ /** Gets the value of "grid-column" */
+ String get gridColumn => getPropertyValue('grid-column');
+
+ /** Sets the value of "grid-column" */
+ set gridColumn(String value) {
+ setProperty('grid-column', value, '');
+ }
+
+ /** Gets the value of "grid-column-end" */
+ String get gridColumnEnd => getPropertyValue('grid-column-end');
+
+ /** Sets the value of "grid-column-end" */
+ set gridColumnEnd(String value) {
+ setProperty('grid-column-end', value, '');
+ }
+
+ /** Gets the value of "grid-column-start" */
+ String get gridColumnStart => getPropertyValue('grid-column-start');
+
+ /** Sets the value of "grid-column-start" */
+ set gridColumnStart(String value) {
+ setProperty('grid-column-start', value, '');
+ }
+
+ /** Gets the value of "grid-row" */
+ String get gridRow => getPropertyValue('grid-row');
+
+ /** Sets the value of "grid-row" */
+ set gridRow(String value) {
+ setProperty('grid-row', value, '');
+ }
+
+ /** Gets the value of "grid-row-end" */
+ String get gridRowEnd => getPropertyValue('grid-row-end');
+
+ /** Sets the value of "grid-row-end" */
+ set gridRowEnd(String value) {
+ setProperty('grid-row-end', value, '');
+ }
+
+ /** Gets the value of "grid-row-start" */
+ String get gridRowStart => getPropertyValue('grid-row-start');
+
+ /** Sets the value of "grid-row-start" */
+ set gridRowStart(String value) {
+ setProperty('grid-row-start', value, '');
+ }
+
+ /** Gets the value of "grid-template" */
+ String get gridTemplate => getPropertyValue('grid-template');
+
+ /** Sets the value of "grid-template" */
+ set gridTemplate(String value) {
+ setProperty('grid-template', value, '');
+ }
+
+ /** Gets the value of "grid-template-areas" */
+ String get gridTemplateAreas => getPropertyValue('grid-template-areas');
+
+ /** Sets the value of "grid-template-areas" */
+ set gridTemplateAreas(String value) {
+ setProperty('grid-template-areas', value, '');
+ }
+
+ /** Gets the value of "grid-template-columns" */
+ String get gridTemplateColumns => getPropertyValue('grid-template-columns');
+
+ /** Sets the value of "grid-template-columns" */
+ set gridTemplateColumns(String value) {
+ setProperty('grid-template-columns', value, '');
+ }
+
+ /** Gets the value of "grid-template-rows" */
+ String get gridTemplateRows => getPropertyValue('grid-template-rows');
+
+ /** Sets the value of "grid-template-rows" */
+ set gridTemplateRows(String value) {
+ setProperty('grid-template-rows', value, '');
+ }
+
+ /** Gets the value of "height" */
+ String get height => getPropertyValue('height');
+
+ /** Sets the value of "height" */
+ set height(String value) {
+ setProperty('height', value, '');
+ }
+
+ /** Gets the value of "highlight" */
+ String get highlight => getPropertyValue('highlight');
+
+ /** Sets the value of "highlight" */
+ set highlight(String value) {
+ setProperty('highlight', value, '');
+ }
+
+ /** Gets the value of "hyphenate-character" */
+ String get hyphenateCharacter => getPropertyValue('hyphenate-character');
+
+ /** Sets the value of "hyphenate-character" */
+ set hyphenateCharacter(String value) {
+ setProperty('hyphenate-character', value, '');
+ }
+
+ /** Gets the value of "image-rendering" */
+ String get imageRendering => getPropertyValue('image-rendering');
+
+ /** Sets the value of "image-rendering" */
+ set imageRendering(String value) {
+ setProperty('image-rendering', value, '');
+ }
+
+ /** Gets the value of "isolation" */
+ String get isolation => getPropertyValue('isolation');
+
+ /** Sets the value of "isolation" */
+ set isolation(String value) {
+ setProperty('isolation', value, '');
+ }
+
+ /** Gets the value of "justify-content" */
+ String get justifyContent => getPropertyValue('justify-content');
+
+ /** Sets the value of "justify-content" */
+ set justifyContent(String value) {
+ setProperty('justify-content', value, '');
+ }
+
+ /** Gets the value of "justify-self" */
+ String get justifySelf => getPropertyValue('justify-self');
+
+ /** Sets the value of "justify-self" */
+ set justifySelf(String value) {
+ setProperty('justify-self', value, '');
+ }
+
+ /** Gets the value of "left" */
+ String get left => getPropertyValue('left');
+
+ /** Sets the value of "left" */
+ set left(String value) {
+ setProperty('left', value, '');
+ }
+
+ /** Gets the value of "letter-spacing" */
+ String get letterSpacing => getPropertyValue('letter-spacing');
+
+ /** Sets the value of "letter-spacing" */
+ set letterSpacing(String value) {
+ setProperty('letter-spacing', value, '');
+ }
+
+ /** Gets the value of "line-box-contain" */
+ String get lineBoxContain => getPropertyValue('line-box-contain');
+
+ /** Sets the value of "line-box-contain" */
+ set lineBoxContain(String value) {
+ setProperty('line-box-contain', value, '');
+ }
+
+ /** Gets the value of "line-break" */
+ String get lineBreak => getPropertyValue('line-break');
+
+ /** Sets the value of "line-break" */
+ set lineBreak(String value) {
+ setProperty('line-break', value, '');
+ }
+
+ /** Gets the value of "line-clamp" */
+ String get lineClamp => getPropertyValue('line-clamp');
+
+ /** Sets the value of "line-clamp" */
+ set lineClamp(String value) {
+ setProperty('line-clamp', value, '');
+ }
+
+ /** Gets the value of "line-height" */
+ String get lineHeight => getPropertyValue('line-height');
+
+ /** Sets the value of "line-height" */
+ set lineHeight(String value) {
+ setProperty('line-height', value, '');
+ }
+
+ /** Gets the value of "list-style" */
+ String get listStyle => getPropertyValue('list-style');
+
+ /** Sets the value of "list-style" */
+ set listStyle(String value) {
+ setProperty('list-style', value, '');
+ }
+
+ /** Gets the value of "list-style-image" */
+ String get listStyleImage => getPropertyValue('list-style-image');
+
+ /** Sets the value of "list-style-image" */
+ set listStyleImage(String value) {
+ setProperty('list-style-image', value, '');
+ }
+
+ /** Gets the value of "list-style-position" */
+ String get listStylePosition => getPropertyValue('list-style-position');
+
+ /** Sets the value of "list-style-position" */
+ set listStylePosition(String value) {
+ setProperty('list-style-position', value, '');
+ }
+
+ /** Gets the value of "list-style-type" */
+ String get listStyleType => getPropertyValue('list-style-type');
+
+ /** Sets the value of "list-style-type" */
+ set listStyleType(String value) {
+ setProperty('list-style-type', value, '');
+ }
+
+ /** Gets the value of "locale" */
+ String get locale => getPropertyValue('locale');
+
+ /** Sets the value of "locale" */
+ set locale(String value) {
+ setProperty('locale', value, '');
+ }
+
+ /** Gets the value of "logical-height" */
+ String get logicalHeight => getPropertyValue('logical-height');
+
+ /** Sets the value of "logical-height" */
+ set logicalHeight(String value) {
+ setProperty('logical-height', value, '');
+ }
+
+ /** Gets the value of "logical-width" */
+ String get logicalWidth => getPropertyValue('logical-width');
+
+ /** Sets the value of "logical-width" */
+ set logicalWidth(String value) {
+ setProperty('logical-width', value, '');
+ }
+
+ /** Gets the value of "margin" */
+ String get margin => getPropertyValue('margin');
+
+ /** Sets the value of "margin" */
+ set margin(String value) {
+ setProperty('margin', value, '');
+ }
+
+ /** Gets the value of "margin-after" */
+ String get marginAfter => getPropertyValue('margin-after');
+
+ /** Sets the value of "margin-after" */
+ set marginAfter(String value) {
+ setProperty('margin-after', value, '');
+ }
+
+ /** Gets the value of "margin-after-collapse" */
+ String get marginAfterCollapse => getPropertyValue('margin-after-collapse');
+
+ /** Sets the value of "margin-after-collapse" */
+ set marginAfterCollapse(String value) {
+ setProperty('margin-after-collapse', value, '');
+ }
+
+ /** Gets the value of "margin-before" */
+ String get marginBefore => getPropertyValue('margin-before');
+
+ /** Sets the value of "margin-before" */
+ set marginBefore(String value) {
+ setProperty('margin-before', value, '');
+ }
+
+ /** Gets the value of "margin-before-collapse" */
+ String get marginBeforeCollapse => getPropertyValue('margin-before-collapse');
+
+ /** Sets the value of "margin-before-collapse" */
+ set marginBeforeCollapse(String value) {
+ setProperty('margin-before-collapse', value, '');
+ }
+
+ /** Gets the value of "margin-bottom" */
+ String get marginBottom => getPropertyValue('margin-bottom');
+
+ /** Sets the value of "margin-bottom" */
+ set marginBottom(String value) {
+ setProperty('margin-bottom', value, '');
+ }
+
+ /** Gets the value of "margin-bottom-collapse" */
+ String get marginBottomCollapse => getPropertyValue('margin-bottom-collapse');
+
+ /** Sets the value of "margin-bottom-collapse" */
+ set marginBottomCollapse(String value) {
+ setProperty('margin-bottom-collapse', value, '');
+ }
+
+ /** Gets the value of "margin-collapse" */
+ String get marginCollapse => getPropertyValue('margin-collapse');
+
+ /** Sets the value of "margin-collapse" */
+ set marginCollapse(String value) {
+ setProperty('margin-collapse', value, '');
+ }
+
+ /** Gets the value of "margin-end" */
+ String get marginEnd => getPropertyValue('margin-end');
+
+ /** Sets the value of "margin-end" */
+ set marginEnd(String value) {
+ setProperty('margin-end', value, '');
+ }
+
+ /** Gets the value of "margin-left" */
+ String get marginLeft => getPropertyValue('margin-left');
+
+ /** Sets the value of "margin-left" */
+ set marginLeft(String value) {
+ setProperty('margin-left', value, '');
+ }
+
+ /** Gets the value of "margin-right" */
+ String get marginRight => getPropertyValue('margin-right');
+
+ /** Sets the value of "margin-right" */
+ set marginRight(String value) {
+ setProperty('margin-right', value, '');
+ }
+
+ /** Gets the value of "margin-start" */
+ String get marginStart => getPropertyValue('margin-start');
+
+ /** Sets the value of "margin-start" */
+ set marginStart(String value) {
+ setProperty('margin-start', value, '');
+ }
+
+ /** Gets the value of "margin-top" */
+ String get marginTop => getPropertyValue('margin-top');
+
+ /** Sets the value of "margin-top" */
+ set marginTop(String value) {
+ setProperty('margin-top', value, '');
+ }
+
+ /** Gets the value of "margin-top-collapse" */
+ String get marginTopCollapse => getPropertyValue('margin-top-collapse');
+
+ /** Sets the value of "margin-top-collapse" */
+ set marginTopCollapse(String value) {
+ setProperty('margin-top-collapse', value, '');
+ }
+
+ /** Gets the value of "mask" */
+ String get mask => getPropertyValue('mask');
+
+ /** Sets the value of "mask" */
+ set mask(String value) {
+ setProperty('mask', value, '');
+ }
+
+ /** Gets the value of "mask-box-image" */
+ String get maskBoxImage => getPropertyValue('mask-box-image');
+
+ /** Sets the value of "mask-box-image" */
+ set maskBoxImage(String value) {
+ setProperty('mask-box-image', value, '');
+ }
+
+ /** Gets the value of "mask-box-image-outset" */
+ String get maskBoxImageOutset => getPropertyValue('mask-box-image-outset');
+
+ /** Sets the value of "mask-box-image-outset" */
+ set maskBoxImageOutset(String value) {
+ setProperty('mask-box-image-outset', value, '');
+ }
+
+ /** Gets the value of "mask-box-image-repeat" */
+ String get maskBoxImageRepeat => getPropertyValue('mask-box-image-repeat');
+
+ /** Sets the value of "mask-box-image-repeat" */
+ set maskBoxImageRepeat(String value) {
+ setProperty('mask-box-image-repeat', value, '');
+ }
+
+ /** Gets the value of "mask-box-image-slice" */
+ String get maskBoxImageSlice => getPropertyValue('mask-box-image-slice');
+
+ /** Sets the value of "mask-box-image-slice" */
+ set maskBoxImageSlice(String value) {
+ setProperty('mask-box-image-slice', value, '');
+ }
+
+ /** Gets the value of "mask-box-image-source" */
+ String get maskBoxImageSource => getPropertyValue('mask-box-image-source');
+
+ /** Sets the value of "mask-box-image-source" */
+ set maskBoxImageSource(String value) {
+ setProperty('mask-box-image-source', value, '');
+ }
+
+ /** Gets the value of "mask-box-image-width" */
+ String get maskBoxImageWidth => getPropertyValue('mask-box-image-width');
+
+ /** Sets the value of "mask-box-image-width" */
+ set maskBoxImageWidth(String value) {
+ setProperty('mask-box-image-width', value, '');
+ }
+
+ /** Gets the value of "mask-clip" */
+ String get maskClip => getPropertyValue('mask-clip');
+
+ /** Sets the value of "mask-clip" */
+ set maskClip(String value) {
+ setProperty('mask-clip', value, '');
+ }
+
+ /** Gets the value of "mask-composite" */
+ String get maskComposite => getPropertyValue('mask-composite');
+
+ /** Sets the value of "mask-composite" */
+ set maskComposite(String value) {
+ setProperty('mask-composite', value, '');
+ }
+
+ /** Gets the value of "mask-image" */
+ String get maskImage => getPropertyValue('mask-image');
+
+ /** Sets the value of "mask-image" */
+ set maskImage(String value) {
+ setProperty('mask-image', value, '');
+ }
+
+ /** Gets the value of "mask-origin" */
+ String get maskOrigin => getPropertyValue('mask-origin');
+
+ /** Sets the value of "mask-origin" */
+ set maskOrigin(String value) {
+ setProperty('mask-origin', value, '');
+ }
+
+ /** Gets the value of "mask-position" */
+ String get maskPosition => getPropertyValue('mask-position');
+
+ /** Sets the value of "mask-position" */
+ set maskPosition(String value) {
+ setProperty('mask-position', value, '');
+ }
+
+ /** Gets the value of "mask-position-x" */
+ String get maskPositionX => getPropertyValue('mask-position-x');
+
+ /** Sets the value of "mask-position-x" */
+ set maskPositionX(String value) {
+ setProperty('mask-position-x', value, '');
+ }
+
+ /** Gets the value of "mask-position-y" */
+ String get maskPositionY => getPropertyValue('mask-position-y');
+
+ /** Sets the value of "mask-position-y" */
+ set maskPositionY(String value) {
+ setProperty('mask-position-y', value, '');
+ }
+
+ /** Gets the value of "mask-repeat" */
+ String get maskRepeat => getPropertyValue('mask-repeat');
+
+ /** Sets the value of "mask-repeat" */
+ set maskRepeat(String value) {
+ setProperty('mask-repeat', value, '');
+ }
+
+ /** Gets the value of "mask-repeat-x" */
+ String get maskRepeatX => getPropertyValue('mask-repeat-x');
+
+ /** Sets the value of "mask-repeat-x" */
+ set maskRepeatX(String value) {
+ setProperty('mask-repeat-x', value, '');
+ }
+
+ /** Gets the value of "mask-repeat-y" */
+ String get maskRepeatY => getPropertyValue('mask-repeat-y');
+
+ /** Sets the value of "mask-repeat-y" */
+ set maskRepeatY(String value) {
+ setProperty('mask-repeat-y', value, '');
+ }
+
+ /** Gets the value of "mask-size" */
+ String get maskSize => getPropertyValue('mask-size');
+
+ /** Sets the value of "mask-size" */
+ set maskSize(String value) {
+ setProperty('mask-size', value, '');
+ }
+
+ /** Gets the value of "mask-source-type" */
+ String get maskSourceType => getPropertyValue('mask-source-type');
+
+ /** Sets the value of "mask-source-type" */
+ set maskSourceType(String value) {
+ setProperty('mask-source-type', value, '');
+ }
+
+ /** Gets the value of "max-height" */
+ String get maxHeight => getPropertyValue('max-height');
+
+ /** Sets the value of "max-height" */
+ set maxHeight(String value) {
+ setProperty('max-height', value, '');
+ }
+
+ /** Gets the value of "max-logical-height" */
+ String get maxLogicalHeight => getPropertyValue('max-logical-height');
+
+ /** Sets the value of "max-logical-height" */
+ set maxLogicalHeight(String value) {
+ setProperty('max-logical-height', value, '');
+ }
+
+ /** Gets the value of "max-logical-width" */
+ String get maxLogicalWidth => getPropertyValue('max-logical-width');
+
+ /** Sets the value of "max-logical-width" */
+ set maxLogicalWidth(String value) {
+ setProperty('max-logical-width', value, '');
+ }
+
+ /** Gets the value of "max-width" */
+ String get maxWidth => getPropertyValue('max-width');
+
+ /** Sets the value of "max-width" */
+ set maxWidth(String value) {
+ setProperty('max-width', value, '');
+ }
+
+ /** Gets the value of "max-zoom" */
+ String get maxZoom => getPropertyValue('max-zoom');
+
+ /** Sets the value of "max-zoom" */
+ set maxZoom(String value) {
+ setProperty('max-zoom', value, '');
+ }
+
+ /** Gets the value of "min-height" */
+ String get minHeight => getPropertyValue('min-height');
+
+ /** Sets the value of "min-height" */
+ set minHeight(String value) {
+ setProperty('min-height', value, '');
+ }
+
+ /** Gets the value of "min-logical-height" */
+ String get minLogicalHeight => getPropertyValue('min-logical-height');
+
+ /** Sets the value of "min-logical-height" */
+ set minLogicalHeight(String value) {
+ setProperty('min-logical-height', value, '');
+ }
+
+ /** Gets the value of "min-logical-width" */
+ String get minLogicalWidth => getPropertyValue('min-logical-width');
+
+ /** Sets the value of "min-logical-width" */
+ set minLogicalWidth(String value) {
+ setProperty('min-logical-width', value, '');
+ }
+
+ /** Gets the value of "min-width" */
+ String get minWidth => getPropertyValue('min-width');
+
+ /** Sets the value of "min-width" */
+ set minWidth(String value) {
+ setProperty('min-width', value, '');
+ }
+
+ /** Gets the value of "min-zoom" */
+ String get minZoom => getPropertyValue('min-zoom');
+
+ /** Sets the value of "min-zoom" */
+ set minZoom(String value) {
+ setProperty('min-zoom', value, '');
+ }
+
+ /** Gets the value of "mix-blend-mode" */
+ String get mixBlendMode => getPropertyValue('mix-blend-mode');
+
+ /** Sets the value of "mix-blend-mode" */
+ set mixBlendMode(String value) {
+ setProperty('mix-blend-mode', value, '');
+ }
+
+ /** Gets the value of "object-fit" */
+ String get objectFit => getPropertyValue('object-fit');
+
+ /** Sets the value of "object-fit" */
+ set objectFit(String value) {
+ setProperty('object-fit', value, '');
+ }
+
+ /** Gets the value of "object-position" */
+ String get objectPosition => getPropertyValue('object-position');
+
+ /** Sets the value of "object-position" */
+ set objectPosition(String value) {
+ setProperty('object-position', value, '');
+ }
+
+ /** Gets the value of "opacity" */
+ String get opacity => getPropertyValue('opacity');
+
+ /** Sets the value of "opacity" */
+ set opacity(String value) {
+ setProperty('opacity', value, '');
+ }
+
+ /** Gets the value of "order" */
+ String get order => getPropertyValue('order');
+
+ /** Sets the value of "order" */
+ set order(String value) {
+ setProperty('order', value, '');
+ }
+
+ /** Gets the value of "orientation" */
+ String get orientation => getPropertyValue('orientation');
+
+ /** Sets the value of "orientation" */
+ set orientation(String value) {
+ setProperty('orientation', value, '');
+ }
+
+ /** Gets the value of "orphans" */
+ String get orphans => getPropertyValue('orphans');
+
+ /** Sets the value of "orphans" */
+ set orphans(String value) {
+ setProperty('orphans', value, '');
+ }
+
+ /** Gets the value of "outline" */
+ String get outline => getPropertyValue('outline');
+
+ /** Sets the value of "outline" */
+ set outline(String value) {
+ setProperty('outline', value, '');
+ }
+
+ /** Gets the value of "outline-color" */
+ String get outlineColor => getPropertyValue('outline-color');
+
+ /** Sets the value of "outline-color" */
+ set outlineColor(String value) {
+ setProperty('outline-color', value, '');
+ }
+
+ /** Gets the value of "outline-offset" */
+ String get outlineOffset => getPropertyValue('outline-offset');
+
+ /** Sets the value of "outline-offset" */
+ set outlineOffset(String value) {
+ setProperty('outline-offset', value, '');
+ }
+
+ /** Gets the value of "outline-style" */
+ String get outlineStyle => getPropertyValue('outline-style');
+
+ /** Sets the value of "outline-style" */
+ set outlineStyle(String value) {
+ setProperty('outline-style', value, '');
+ }
+
+ /** Gets the value of "outline-width" */
+ String get outlineWidth => getPropertyValue('outline-width');
+
+ /** Sets the value of "outline-width" */
+ set outlineWidth(String value) {
+ setProperty('outline-width', value, '');
+ }
+
+ /** Gets the value of "overflow" */
+ String get overflow => getPropertyValue('overflow');
+
+ /** Sets the value of "overflow" */
+ set overflow(String value) {
+ setProperty('overflow', value, '');
+ }
+
+ /** Gets the value of "overflow-wrap" */
+ String get overflowWrap => getPropertyValue('overflow-wrap');
+
+ /** Sets the value of "overflow-wrap" */
+ set overflowWrap(String value) {
+ setProperty('overflow-wrap', value, '');
+ }
+
+ /** Gets the value of "overflow-x" */
+ String get overflowX => getPropertyValue('overflow-x');
+
+ /** Sets the value of "overflow-x" */
+ set overflowX(String value) {
+ setProperty('overflow-x', value, '');
+ }
+
+ /** Gets the value of "overflow-y" */
+ String get overflowY => getPropertyValue('overflow-y');
+
+ /** Sets the value of "overflow-y" */
+ set overflowY(String value) {
+ setProperty('overflow-y', value, '');
+ }
+
+ /** Gets the value of "padding" */
+ String get padding => getPropertyValue('padding');
+
+ /** Sets the value of "padding" */
+ set padding(String value) {
+ setProperty('padding', value, '');
+ }
+
+ /** Gets the value of "padding-after" */
+ String get paddingAfter => getPropertyValue('padding-after');
+
+ /** Sets the value of "padding-after" */
+ set paddingAfter(String value) {
+ setProperty('padding-after', value, '');
+ }
+
+ /** Gets the value of "padding-before" */
+ String get paddingBefore => getPropertyValue('padding-before');
+
+ /** Sets the value of "padding-before" */
+ set paddingBefore(String value) {
+ setProperty('padding-before', value, '');
+ }
+
+ /** Gets the value of "padding-bottom" */
+ String get paddingBottom => getPropertyValue('padding-bottom');
+
+ /** Sets the value of "padding-bottom" */
+ set paddingBottom(String value) {
+ setProperty('padding-bottom', value, '');
+ }
+
+ /** Gets the value of "padding-end" */
+ String get paddingEnd => getPropertyValue('padding-end');
+
+ /** Sets the value of "padding-end" */
+ set paddingEnd(String value) {
+ setProperty('padding-end', value, '');
+ }
+
+ /** Gets the value of "padding-left" */
+ String get paddingLeft => getPropertyValue('padding-left');
+
+ /** Sets the value of "padding-left" */
+ set paddingLeft(String value) {
+ setProperty('padding-left', value, '');
+ }
+
+ /** Gets the value of "padding-right" */
+ String get paddingRight => getPropertyValue('padding-right');
+
+ /** Sets the value of "padding-right" */
+ set paddingRight(String value) {
+ setProperty('padding-right', value, '');
+ }
+
+ /** Gets the value of "padding-start" */
+ String get paddingStart => getPropertyValue('padding-start');
+
+ /** Sets the value of "padding-start" */
+ set paddingStart(String value) {
+ setProperty('padding-start', value, '');
+ }
+
+ /** Gets the value of "padding-top" */
+ String get paddingTop => getPropertyValue('padding-top');
+
+ /** Sets the value of "padding-top" */
+ set paddingTop(String value) {
+ setProperty('padding-top', value, '');
+ }
+
+ /** Gets the value of "page" */
+ String get page => getPropertyValue('page');
+
+ /** Sets the value of "page" */
+ set page(String value) {
+ setProperty('page', value, '');
+ }
+
+ /** Gets the value of "page-break-after" */
+ String get pageBreakAfter => getPropertyValue('page-break-after');
+
+ /** Sets the value of "page-break-after" */
+ set pageBreakAfter(String value) {
+ setProperty('page-break-after', value, '');
+ }
+
+ /** Gets the value of "page-break-before" */
+ String get pageBreakBefore => getPropertyValue('page-break-before');
+
+ /** Sets the value of "page-break-before" */
+ set pageBreakBefore(String value) {
+ setProperty('page-break-before', value, '');
+ }
+
+ /** Gets the value of "page-break-inside" */
+ String get pageBreakInside => getPropertyValue('page-break-inside');
+
+ /** Sets the value of "page-break-inside" */
+ set pageBreakInside(String value) {
+ setProperty('page-break-inside', value, '');
+ }
+
+ /** Gets the value of "perspective" */
+ String get perspective => getPropertyValue('perspective');
+
+ /** Sets the value of "perspective" */
+ set perspective(String value) {
+ setProperty('perspective', value, '');
+ }
+
+ /** Gets the value of "perspective-origin" */
+ String get perspectiveOrigin => getPropertyValue('perspective-origin');
+
+ /** Sets the value of "perspective-origin" */
+ set perspectiveOrigin(String value) {
+ setProperty('perspective-origin', value, '');
+ }
+
+ /** Gets the value of "perspective-origin-x" */
+ String get perspectiveOriginX => getPropertyValue('perspective-origin-x');
+
+ /** Sets the value of "perspective-origin-x" */
+ set perspectiveOriginX(String value) {
+ setProperty('perspective-origin-x', value, '');
+ }
+
+ /** Gets the value of "perspective-origin-y" */
+ String get perspectiveOriginY => getPropertyValue('perspective-origin-y');
+
+ /** Sets the value of "perspective-origin-y" */
+ set perspectiveOriginY(String value) {
+ setProperty('perspective-origin-y', value, '');
+ }
+
+ /** Gets the value of "pointer-events" */
+ String get pointerEvents => getPropertyValue('pointer-events');
+
+ /** Sets the value of "pointer-events" */
+ set pointerEvents(String value) {
+ setProperty('pointer-events', value, '');
+ }
+
+ /** Gets the value of "position" */
+ String get position => getPropertyValue('position');
+
+ /** Sets the value of "position" */
+ set position(String value) {
+ setProperty('position', value, '');
+ }
+
+ /** Gets the value of "print-color-adjust" */
+ String get printColorAdjust => getPropertyValue('print-color-adjust');
+
+ /** Sets the value of "print-color-adjust" */
+ set printColorAdjust(String value) {
+ setProperty('print-color-adjust', value, '');
+ }
+
+ /** Gets the value of "quotes" */
+ String get quotes => getPropertyValue('quotes');
+
+ /** Sets the value of "quotes" */
+ set quotes(String value) {
+ setProperty('quotes', value, '');
+ }
+
+ /** Gets the value of "resize" */
+ String get resize => getPropertyValue('resize');
+
+ /** Sets the value of "resize" */
+ set resize(String value) {
+ setProperty('resize', value, '');
+ }
+
+ /** Gets the value of "right" */
+ String get right => getPropertyValue('right');
+
+ /** Sets the value of "right" */
+ set right(String value) {
+ setProperty('right', value, '');
+ }
+
+ /** Gets the value of "rtl-ordering" */
+ String get rtlOrdering => getPropertyValue('rtl-ordering');
+
+ /** Sets the value of "rtl-ordering" */
+ set rtlOrdering(String value) {
+ setProperty('rtl-ordering', value, '');
+ }
+
+ /** Gets the value of "ruby-position" */
+ String get rubyPosition => getPropertyValue('ruby-position');
+
+ /** Sets the value of "ruby-position" */
+ set rubyPosition(String value) {
+ setProperty('ruby-position', value, '');
+ }
+
+ /** Gets the value of "scroll-behavior" */
+ String get scrollBehavior => getPropertyValue('scroll-behavior');
+
+ /** Sets the value of "scroll-behavior" */
+ set scrollBehavior(String value) {
+ setProperty('scroll-behavior', value, '');
+ }
+
+ /** Gets the value of "shape-image-threshold" */
+ String get shapeImageThreshold => getPropertyValue('shape-image-threshold');
+
+ /** Sets the value of "shape-image-threshold" */
+ set shapeImageThreshold(String value) {
+ setProperty('shape-image-threshold', value, '');
+ }
+
+ /** Gets the value of "shape-margin" */
+ String get shapeMargin => getPropertyValue('shape-margin');
+
+ /** Sets the value of "shape-margin" */
+ set shapeMargin(String value) {
+ setProperty('shape-margin', value, '');
+ }
+
+ /** Gets the value of "shape-outside" */
+ String get shapeOutside => getPropertyValue('shape-outside');
+
+ /** Sets the value of "shape-outside" */
+ set shapeOutside(String value) {
+ setProperty('shape-outside', value, '');
+ }
+
+ /** Gets the value of "size" */
+ String get size => getPropertyValue('size');
+
+ /** Sets the value of "size" */
+ set size(String value) {
+ setProperty('size', value, '');
+ }
+
+ /** Gets the value of "speak" */
+ String get speak => getPropertyValue('speak');
+
+ /** Sets the value of "speak" */
+ set speak(String value) {
+ setProperty('speak', value, '');
+ }
+
+ /** Gets the value of "src" */
+ String get src => getPropertyValue('src');
+
+ /** Sets the value of "src" */
+ set src(String value) {
+ setProperty('src', value, '');
+ }
+
+ /** Gets the value of "tab-size" */
+ String get tabSize => getPropertyValue('tab-size');
+
+ /** Sets the value of "tab-size" */
+ set tabSize(String value) {
+ setProperty('tab-size', value, '');
+ }
+
+ /** Gets the value of "table-layout" */
+ String get tableLayout => getPropertyValue('table-layout');
+
+ /** Sets the value of "table-layout" */
+ set tableLayout(String value) {
+ setProperty('table-layout', value, '');
+ }
+
+ /** Gets the value of "tap-highlight-color" */
+ String get tapHighlightColor => getPropertyValue('tap-highlight-color');
+
+ /** Sets the value of "tap-highlight-color" */
+ set tapHighlightColor(String value) {
+ setProperty('tap-highlight-color', value, '');
+ }
+
+ /** Gets the value of "text-align" */
+ String get textAlign => getPropertyValue('text-align');
+
+ /** Sets the value of "text-align" */
+ set textAlign(String value) {
+ setProperty('text-align', value, '');
+ }
+
+ /** Gets the value of "text-align-last" */
+ String get textAlignLast => getPropertyValue('text-align-last');
+
+ /** Sets the value of "text-align-last" */
+ set textAlignLast(String value) {
+ setProperty('text-align-last', value, '');
+ }
+
+ /** Gets the value of "text-combine" */
+ String get textCombine => getPropertyValue('text-combine');
+
+ /** Sets the value of "text-combine" */
+ set textCombine(String value) {
+ setProperty('text-combine', value, '');
+ }
+
+ /** Gets the value of "text-decoration" */
+ String get textDecoration => getPropertyValue('text-decoration');
+
+ /** Sets the value of "text-decoration" */
+ set textDecoration(String value) {
+ setProperty('text-decoration', value, '');
+ }
+
+ /** Gets the value of "text-decoration-color" */
+ String get textDecorationColor => getPropertyValue('text-decoration-color');
+
+ /** Sets the value of "text-decoration-color" */
+ set textDecorationColor(String value) {
+ setProperty('text-decoration-color', value, '');
+ }
+
+ /** Gets the value of "text-decoration-line" */
+ String get textDecorationLine => getPropertyValue('text-decoration-line');
+
+ /** Sets the value of "text-decoration-line" */
+ set textDecorationLine(String value) {
+ setProperty('text-decoration-line', value, '');
+ }
+
+ /** Gets the value of "text-decoration-style" */
+ String get textDecorationStyle => getPropertyValue('text-decoration-style');
+
+ /** Sets the value of "text-decoration-style" */
+ set textDecorationStyle(String value) {
+ setProperty('text-decoration-style', value, '');
+ }
+
+ /** Gets the value of "text-decorations-in-effect" */
+ String get textDecorationsInEffect =>
+ getPropertyValue('text-decorations-in-effect');
+
+ /** Sets the value of "text-decorations-in-effect" */
+ set textDecorationsInEffect(String value) {
+ setProperty('text-decorations-in-effect', value, '');
+ }
+
+ /** Gets the value of "text-emphasis" */
+ String get textEmphasis => getPropertyValue('text-emphasis');
+
+ /** Sets the value of "text-emphasis" */
+ set textEmphasis(String value) {
+ setProperty('text-emphasis', value, '');
+ }
+
+ /** Gets the value of "text-emphasis-color" */
+ String get textEmphasisColor => getPropertyValue('text-emphasis-color');
+
+ /** Sets the value of "text-emphasis-color" */
+ set textEmphasisColor(String value) {
+ setProperty('text-emphasis-color', value, '');
+ }
+
+ /** Gets the value of "text-emphasis-position" */
+ String get textEmphasisPosition => getPropertyValue('text-emphasis-position');
+
+ /** Sets the value of "text-emphasis-position" */
+ set textEmphasisPosition(String value) {
+ setProperty('text-emphasis-position', value, '');
+ }
+
+ /** Gets the value of "text-emphasis-style" */
+ String get textEmphasisStyle => getPropertyValue('text-emphasis-style');
+
+ /** Sets the value of "text-emphasis-style" */
+ set textEmphasisStyle(String value) {
+ setProperty('text-emphasis-style', value, '');
+ }
+
+ /** Gets the value of "text-fill-color" */
+ String get textFillColor => getPropertyValue('text-fill-color');
+
+ /** Sets the value of "text-fill-color" */
+ set textFillColor(String value) {
+ setProperty('text-fill-color', value, '');
+ }
+
+ /** Gets the value of "text-indent" */
+ String get textIndent => getPropertyValue('text-indent');
+
+ /** Sets the value of "text-indent" */
+ set textIndent(String value) {
+ setProperty('text-indent', value, '');
+ }
+
+ /** Gets the value of "text-justify" */
+ String get textJustify => getPropertyValue('text-justify');
+
+ /** Sets the value of "text-justify" */
+ set textJustify(String value) {
+ setProperty('text-justify', value, '');
+ }
+
+ /** Gets the value of "text-line-through-color" */
+ String get textLineThroughColor =>
+ getPropertyValue('text-line-through-color');
+
+ /** Sets the value of "text-line-through-color" */
+ set textLineThroughColor(String value) {
+ setProperty('text-line-through-color', value, '');
+ }
+
+ /** Gets the value of "text-line-through-mode" */
+ String get textLineThroughMode => getPropertyValue('text-line-through-mode');
+
+ /** Sets the value of "text-line-through-mode" */
+ set textLineThroughMode(String value) {
+ setProperty('text-line-through-mode', value, '');
+ }
+
+ /** Gets the value of "text-line-through-style" */
+ String get textLineThroughStyle =>
+ getPropertyValue('text-line-through-style');
+
+ /** Sets the value of "text-line-through-style" */
+ set textLineThroughStyle(String value) {
+ setProperty('text-line-through-style', value, '');
+ }
+
+ /** Gets the value of "text-line-through-width" */
+ String get textLineThroughWidth =>
+ getPropertyValue('text-line-through-width');
+
+ /** Sets the value of "text-line-through-width" */
+ set textLineThroughWidth(String value) {
+ setProperty('text-line-through-width', value, '');
+ }
+
+ /** Gets the value of "text-orientation" */
+ String get textOrientation => getPropertyValue('text-orientation');
+
+ /** Sets the value of "text-orientation" */
+ set textOrientation(String value) {
+ setProperty('text-orientation', value, '');
+ }
+
+ /** Gets the value of "text-overflow" */
+ String get textOverflow => getPropertyValue('text-overflow');
+
+ /** Sets the value of "text-overflow" */
+ set textOverflow(String value) {
+ setProperty('text-overflow', value, '');
+ }
+
+ /** Gets the value of "text-overline-color" */
+ String get textOverlineColor => getPropertyValue('text-overline-color');
+
+ /** Sets the value of "text-overline-color" */
+ set textOverlineColor(String value) {
+ setProperty('text-overline-color', value, '');
+ }
+
+ /** Gets the value of "text-overline-mode" */
+ String get textOverlineMode => getPropertyValue('text-overline-mode');
+
+ /** Sets the value of "text-overline-mode" */
+ set textOverlineMode(String value) {
+ setProperty('text-overline-mode', value, '');
+ }
+
+ /** Gets the value of "text-overline-style" */
+ String get textOverlineStyle => getPropertyValue('text-overline-style');
+
+ /** Sets the value of "text-overline-style" */
+ set textOverlineStyle(String value) {
+ setProperty('text-overline-style', value, '');
+ }
+
+ /** Gets the value of "text-overline-width" */
+ String get textOverlineWidth => getPropertyValue('text-overline-width');
+
+ /** Sets the value of "text-overline-width" */
+ set textOverlineWidth(String value) {
+ setProperty('text-overline-width', value, '');
+ }
+
+ /** Gets the value of "text-rendering" */
+ String get textRendering => getPropertyValue('text-rendering');
+
+ /** Sets the value of "text-rendering" */
+ set textRendering(String value) {
+ setProperty('text-rendering', value, '');
+ }
+
+ /** Gets the value of "text-security" */
+ String get textSecurity => getPropertyValue('text-security');
+
+ /** Sets the value of "text-security" */
+ set textSecurity(String value) {
+ setProperty('text-security', value, '');
+ }
+
+ /** Gets the value of "text-shadow" */
+ String get textShadow => getPropertyValue('text-shadow');
+
+ /** Sets the value of "text-shadow" */
+ set textShadow(String value) {
+ setProperty('text-shadow', value, '');
+ }
+
+ /** Gets the value of "text-stroke" */
+ String get textStroke => getPropertyValue('text-stroke');
+
+ /** Sets the value of "text-stroke" */
+ set textStroke(String value) {
+ setProperty('text-stroke', value, '');
+ }
+
+ /** Gets the value of "text-stroke-color" */
+ String get textStrokeColor => getPropertyValue('text-stroke-color');
+
+ /** Sets the value of "text-stroke-color" */
+ set textStrokeColor(String value) {
+ setProperty('text-stroke-color', value, '');
+ }
+
+ /** Gets the value of "text-stroke-width" */
+ String get textStrokeWidth => getPropertyValue('text-stroke-width');
+
+ /** Sets the value of "text-stroke-width" */
+ set textStrokeWidth(String value) {
+ setProperty('text-stroke-width', value, '');
+ }
+
+ /** Gets the value of "text-transform" */
+ String get textTransform => getPropertyValue('text-transform');
+
+ /** Sets the value of "text-transform" */
+ set textTransform(String value) {
+ setProperty('text-transform', value, '');
+ }
+
+ /** Gets the value of "text-underline-color" */
+ String get textUnderlineColor => getPropertyValue('text-underline-color');
+
+ /** Sets the value of "text-underline-color" */
+ set textUnderlineColor(String value) {
+ setProperty('text-underline-color', value, '');
+ }
+
+ /** Gets the value of "text-underline-mode" */
+ String get textUnderlineMode => getPropertyValue('text-underline-mode');
+
+ /** Sets the value of "text-underline-mode" */
+ set textUnderlineMode(String value) {
+ setProperty('text-underline-mode', value, '');
+ }
+
+ /** Gets the value of "text-underline-position" */
+ String get textUnderlinePosition =>
+ getPropertyValue('text-underline-position');
+
+ /** Sets the value of "text-underline-position" */
+ set textUnderlinePosition(String value) {
+ setProperty('text-underline-position', value, '');
+ }
+
+ /** Gets the value of "text-underline-style" */
+ String get textUnderlineStyle => getPropertyValue('text-underline-style');
+
+ /** Sets the value of "text-underline-style" */
+ set textUnderlineStyle(String value) {
+ setProperty('text-underline-style', value, '');
+ }
+
+ /** Gets the value of "text-underline-width" */
+ String get textUnderlineWidth => getPropertyValue('text-underline-width');
+
+ /** Sets the value of "text-underline-width" */
+ set textUnderlineWidth(String value) {
+ setProperty('text-underline-width', value, '');
+ }
+
+ /** Gets the value of "top" */
+ String get top => getPropertyValue('top');
+
+ /** Sets the value of "top" */
+ set top(String value) {
+ setProperty('top', value, '');
+ }
+
+ /** Gets the value of "touch-action" */
+ String get touchAction => getPropertyValue('touch-action');
+
+ /** Sets the value of "touch-action" */
+ set touchAction(String value) {
+ setProperty('touch-action', value, '');
+ }
+
+ /** Gets the value of "touch-action-delay" */
+ String get touchActionDelay => getPropertyValue('touch-action-delay');
+
+ /** Sets the value of "touch-action-delay" */
+ set touchActionDelay(String value) {
+ setProperty('touch-action-delay', value, '');
+ }
+
+ /** Gets the value of "transform" */
+ String get transform => getPropertyValue('transform');
+
+ /** Sets the value of "transform" */
+ set transform(String value) {
+ setProperty('transform', value, '');
+ }
+
+ /** Gets the value of "transform-origin" */
+ String get transformOrigin => getPropertyValue('transform-origin');
+
+ /** Sets the value of "transform-origin" */
+ set transformOrigin(String value) {
+ setProperty('transform-origin', value, '');
+ }
+
+ /** Gets the value of "transform-origin-x" */
+ String get transformOriginX => getPropertyValue('transform-origin-x');
+
+ /** Sets the value of "transform-origin-x" */
+ set transformOriginX(String value) {
+ setProperty('transform-origin-x', value, '');
+ }
+
+ /** Gets the value of "transform-origin-y" */
+ String get transformOriginY => getPropertyValue('transform-origin-y');
+
+ /** Sets the value of "transform-origin-y" */
+ set transformOriginY(String value) {
+ setProperty('transform-origin-y', value, '');
+ }
+
+ /** Gets the value of "transform-origin-z" */
+ String get transformOriginZ => getPropertyValue('transform-origin-z');
+
+ /** Sets the value of "transform-origin-z" */
+ set transformOriginZ(String value) {
+ setProperty('transform-origin-z', value, '');
+ }
+
+ /** Gets the value of "transform-style" */
+ String get transformStyle => getPropertyValue('transform-style');
+
+ /** Sets the value of "transform-style" */
+ set transformStyle(String value) {
+ setProperty('transform-style', value, '');
+ }
+
+ /** Gets the value of "transition" */ @SupportedBrowser(
+ SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ String get transition => getPropertyValue('transition');
+
+ /** Sets the value of "transition" */ @SupportedBrowser(
+ SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ set transition(String value) {
+ setProperty('transition', value, '');
+ }
+
+ /** Gets the value of "transition-delay" */
+ String get transitionDelay => getPropertyValue('transition-delay');
+
+ /** Sets the value of "transition-delay" */
+ set transitionDelay(String value) {
+ setProperty('transition-delay', value, '');
+ }
+
+ /** Gets the value of "transition-duration" */
+ String get transitionDuration => getPropertyValue('transition-duration');
+
+ /** Sets the value of "transition-duration" */
+ set transitionDuration(String value) {
+ setProperty('transition-duration', value, '');
+ }
+
+ /** Gets the value of "transition-property" */
+ String get transitionProperty => getPropertyValue('transition-property');
+
+ /** Sets the value of "transition-property" */
+ set transitionProperty(String value) {
+ setProperty('transition-property', value, '');
+ }
+
+ /** Gets the value of "transition-timing-function" */
+ String get transitionTimingFunction =>
+ getPropertyValue('transition-timing-function');
+
+ /** Sets the value of "transition-timing-function" */
+ set transitionTimingFunction(String value) {
+ setProperty('transition-timing-function', value, '');
+ }
+
+ /** Gets the value of "unicode-bidi" */
+ String get unicodeBidi => getPropertyValue('unicode-bidi');
+
+ /** Sets the value of "unicode-bidi" */
+ set unicodeBidi(String value) {
+ setProperty('unicode-bidi', value, '');
+ }
+
+ /** Gets the value of "unicode-range" */
+ String get unicodeRange => getPropertyValue('unicode-range');
+
+ /** Sets the value of "unicode-range" */
+ set unicodeRange(String value) {
+ setProperty('unicode-range', value, '');
+ }
+
+ /** Gets the value of "user-drag" */
+ String get userDrag => getPropertyValue('user-drag');
+
+ /** Sets the value of "user-drag" */
+ set userDrag(String value) {
+ setProperty('user-drag', value, '');
+ }
+
+ /** Gets the value of "user-modify" */
+ String get userModify => getPropertyValue('user-modify');
+
+ /** Sets the value of "user-modify" */
+ set userModify(String value) {
+ setProperty('user-modify', value, '');
+ }
+
+ /** Gets the value of "user-select" */
+ String get userSelect => getPropertyValue('user-select');
+
+ /** Sets the value of "user-select" */
+ set userSelect(String value) {
+ setProperty('user-select', value, '');
+ }
+
+ /** Gets the value of "user-zoom" */
+ String get userZoom => getPropertyValue('user-zoom');
+
+ /** Sets the value of "user-zoom" */
+ set userZoom(String value) {
+ setProperty('user-zoom', value, '');
+ }
+
+ /** Gets the value of "vertical-align" */
+ String get verticalAlign => getPropertyValue('vertical-align');
+
+ /** Sets the value of "vertical-align" */
+ set verticalAlign(String value) {
+ setProperty('vertical-align', value, '');
+ }
+
+ /** Gets the value of "visibility" */
+ String get visibility => getPropertyValue('visibility');
+
+ /** Sets the value of "visibility" */
+ set visibility(String value) {
+ setProperty('visibility', value, '');
+ }
+
+ /** Gets the value of "white-space" */
+ String get whiteSpace => getPropertyValue('white-space');
+
+ /** Sets the value of "white-space" */
+ set whiteSpace(String value) {
+ setProperty('white-space', value, '');
+ }
+
+ /** Gets the value of "widows" */
+ String get widows => getPropertyValue('widows');
+
+ /** Sets the value of "widows" */
+ set widows(String value) {
+ setProperty('widows', value, '');
+ }
+
+ /** Gets the value of "width" */
+ String get width => getPropertyValue('width');
+
+ /** Sets the value of "width" */
+ set width(String value) {
+ setProperty('width', value, '');
+ }
+
+ /** Gets the value of "will-change" */
+ String get willChange => getPropertyValue('will-change');
+
+ /** Sets the value of "will-change" */
+ set willChange(String value) {
+ setProperty('will-change', value, '');
+ }
+
+ /** Gets the value of "word-break" */
+ String get wordBreak => getPropertyValue('word-break');
+
+ /** Sets the value of "word-break" */
+ set wordBreak(String value) {
+ setProperty('word-break', value, '');
+ }
+
+ /** Gets the value of "word-spacing" */
+ String get wordSpacing => getPropertyValue('word-spacing');
+
+ /** Sets the value of "word-spacing" */
+ set wordSpacing(String value) {
+ setProperty('word-spacing', value, '');
+ }
+
+ /** Gets the value of "word-wrap" */
+ String get wordWrap => getPropertyValue('word-wrap');
+
+ /** Sets the value of "word-wrap" */
+ set wordWrap(String value) {
+ setProperty('word-wrap', value, '');
+ }
+
+ /** Gets the value of "wrap-flow" */
+ String get wrapFlow => getPropertyValue('wrap-flow');
+
+ /** Sets the value of "wrap-flow" */
+ set wrapFlow(String value) {
+ setProperty('wrap-flow', value, '');
+ }
+
+ /** Gets the value of "wrap-through" */
+ String get wrapThrough => getPropertyValue('wrap-through');
+
+ /** Sets the value of "wrap-through" */
+ set wrapThrough(String value) {
+ setProperty('wrap-through', value, '');
+ }
+
+ /** Gets the value of "writing-mode" */
+ String get writingMode => getPropertyValue('writing-mode');
+
+ /** Sets the value of "writing-mode" */
+ set writingMode(String value) {
+ setProperty('writing-mode', value, '');
+ }
+
+ /** Gets the value of "z-index" */
+ String get zIndex => getPropertyValue('z-index');
+
+ /** Sets the value of "z-index" */
+ set zIndex(String value) {
+ setProperty('z-index', value, '');
+ }
+
+ /** Gets the value of "zoom" */
+ String get zoom => getPropertyValue('zoom');
+
+ /** Sets the value of "zoom" */
+ set zoom(String value) {
+ setProperty('zoom', value, '');
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSStyleRule")
+class CssStyleRule extends CssRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssStyleRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String selectorText;
+
+ final CssStyleDeclaration style;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSStyleSheet")
+class CssStyleSheet extends StyleSheet {
+ // To suppress missing implicit constructor warnings.
+ factory CssStyleSheet._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @Returns('_CssRuleList|Null')
+ @Creates('_CssRuleList')
+ final List<CssRule> cssRules;
+
+ final CssRule ownerRule;
+
+ @Returns('_CssRuleList|Null')
+ @Creates('_CssRuleList')
+ final List<CssRule> rules;
+
+ int addRule(String selector, String style, [int index]) native;
+
+ void deleteRule(int index) native;
+
+ int insertRule(String rule, [int index]) native;
+
+ void removeRule(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSStyleValue")
+class CssStyleValue extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CssStyleValue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static Object parse(String property, String cssText) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSSupportsRule")
+class CssSupportsRule extends CssConditionRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssSupportsRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSTransformComponent")
+class CssTransformComponent extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CssTransformComponent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ bool is2D;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSTransformValue")
+class CssTransformValue extends CssStyleValue {
+ // To suppress missing implicit constructor warnings.
+ factory CssTransformValue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CssTransformValue([List<CssTransformComponent> transformComponents]) {
+ if (transformComponents == null) {
+ return CssTransformValue._create_1();
+ }
+ if ((transformComponents is List<CssTransformComponent>)) {
+ return CssTransformValue._create_2(transformComponents);
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+ static CssTransformValue _create_1() =>
+ JS('CssTransformValue', 'new CSSTransformValue()');
+ static CssTransformValue _create_2(transformComponents) =>
+ JS('CssTransformValue', 'new CSSTransformValue(#)', transformComponents);
+
+ final bool is2D;
+
+ final int length;
+
+ CssTransformComponent componentAtIndex(int index) native;
+
+ DomMatrix toMatrix() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSTranslation")
+class CssTranslation extends CssTransformComponent {
+ // To suppress missing implicit constructor warnings.
+ factory CssTranslation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CssTranslation(CssNumericValue x, CssNumericValue y,
+ [CssNumericValue z]) {
+ if ((y is CssNumericValue) && (x is CssNumericValue) && z == null) {
+ return CssTranslation._create_1(x, y);
+ }
+ if ((z is CssNumericValue) &&
+ (y is CssNumericValue) &&
+ (x is CssNumericValue)) {
+ return CssTranslation._create_2(x, y, z);
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+ static CssTranslation _create_1(x, y) =>
+ JS('CssTranslation', 'new CSSTranslation(#,#)', x, y);
+ static CssTranslation _create_2(x, y, z) =>
+ JS('CssTranslation', 'new CSSTranslation(#,#,#)', x, y, z);
+
+ CssNumericValue x;
+
+ CssNumericValue y;
+
+ CssNumericValue z;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSUnitValue")
+class CssUnitValue extends CssNumericValue {
+ // To suppress missing implicit constructor warnings.
+ factory CssUnitValue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CssUnitValue(num value, String unit) {
+ return CssUnitValue._create_1(value, unit);
+ }
+ static CssUnitValue _create_1(value, unit) =>
+ JS('CssUnitValue', 'new CSSUnitValue(#,#)', value, unit);
+
+ final String type;
+
+ String unit;
+
+ num value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSUnparsedValue")
+class CssUnparsedValue extends CssStyleValue {
+ // To suppress missing implicit constructor warnings.
+ factory CssUnparsedValue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int length;
+
+ Object fragmentAtIndex(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSVariableReferenceValue")
+class CssVariableReferenceValue extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CssVariableReferenceValue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final CssUnparsedValue fallback;
+
+ final String variable;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSViewportRule")
+class CssViewportRule extends CssRule {
+ // To suppress missing implicit constructor warnings.
+ factory CssViewportRule._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final CssStyleDeclaration style;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSURLImageValue")
+class CssurlImageValue extends CssImageValue {
+ // To suppress missing implicit constructor warnings.
+ factory CssurlImageValue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CssurlImageValue(String url) {
+ return CssurlImageValue._create_1(url);
+ }
+ static CssurlImageValue _create_1(url) =>
+ JS('CssurlImageValue', 'new CSSURLImageValue(#)', url);
+
+ final String url;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-custom-element-constructor-generation
+@deprecated // experimental
+typedef void CustomElementConstructor();
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CustomElementRegistry")
+class CustomElementRegistry extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CustomElementRegistry._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void define(String name, Object constructor, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ _define_1(name, constructor, options_1);
+ return;
+ }
+ _define_2(name, constructor);
+ return;
+ }
+
+ @JSName('define')
+ void _define_1(name, constructor, options) native;
+ @JSName('define')
+ void _define_2(name, constructor) native;
+
+ Object get(String name) native;
+
+ Future whenDefined(String name) =>
+ promiseToFuture(JS("", "#.whenDefined(#)", this, name));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("CustomEvent")
+class CustomEvent extends Event {
+ @Creates('Null') // Set from Dart code; does not instantiate a native type.
+ var _dartDetail;
+
+ factory CustomEvent(String type,
+ {bool canBubble: true, bool cancelable: true, Object detail}) {
+ final CustomEvent e = document._createEvent('CustomEvent');
+
+ e._dartDetail = detail;
+
+ // Only try setting the detail if it's one of these types to avoid
+ // first-chance exceptions. Can expand this list in the future as needed.
+ if (detail is List || detail is Map || detail is String || detail is num) {
+ try {
+ detail = convertDartToNative_SerializedScriptValue(detail);
+ e._initCustomEvent(type, canBubble, cancelable, detail);
+ } catch (_) {
+ e._initCustomEvent(type, canBubble, cancelable, null);
+ }
+ } else {
+ e._initCustomEvent(type, canBubble, cancelable, null);
+ }
+
+ return e;
+ }
+
+ get detail {
+ if (_dartDetail != null) {
+ return _dartDetail;
+ }
+ return _detail;
+ }
+
+ factory CustomEvent._(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return CustomEvent._create_1(type, eventInitDict_1);
+ }
+ return CustomEvent._create_2(type);
+ }
+ static CustomEvent _create_1(type, eventInitDict) =>
+ JS('CustomEvent', 'new CustomEvent(#,#)', type, eventInitDict);
+ static CustomEvent _create_2(type) =>
+ JS('CustomEvent', 'new CustomEvent(#)', type);
+
+ dynamic get _detail =>
+ convertNativeToDart_SerializedScriptValue(this._get__detail);
+ @JSName('detail')
+ @Creates('Null')
+ final dynamic _get__detail;
+
+ @JSName('initCustomEvent')
+ void _initCustomEvent(String type,
+ [bool bubbles, bool cancelable, Object detail]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLDListElement")
+class DListElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory DListElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DListElement() => JS(
+ 'returns:DListElement;creates:DListElement;new:true',
+ '#.createElement(#)',
+ document,
+ "dl");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ DListElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLDataElement")
+class DataElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory DataElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ DataElement.created() : super.created();
+
+ String value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("HTMLDataListElement")
+class DataListElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory DataListElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DataListElement() => document.createElement("datalist");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ DataListElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Element.isTagSupported('datalist');
+
+ @Returns('HtmlCollection|Null')
+ @Creates('HtmlCollection')
+ final List<Node> options;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DataTransfer")
+class DataTransfer extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DataTransfer._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DataTransfer() {
+ return DataTransfer._create_1();
+ }
+ static DataTransfer _create_1() => JS('DataTransfer', 'new DataTransfer()');
+
+ String dropEffect;
+
+ String effectAllowed;
+
+ @Returns('FileList|Null')
+ @Creates('FileList')
+ final List<File> files;
+
+ final DataTransferItemList items;
+
+ final List<String> types;
+
+ void clearData([String format]) native;
+
+ String getData(String format) native;
+
+ void setData(String format, String data) native;
+
+ void setDragImage(Element image, int x, int y) native;
+}
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DataTransferItem")
+class DataTransferItem extends Interceptor {
+ Entry getAsEntry() {
+ Entry entry = _webkitGetAsEntry();
+
+ if (entry.isFile)
+ applyExtension('FileEntry', entry);
+ else if (entry.isDirectory)
+ applyExtension('DirectoryEntry', entry);
+ else
+ applyExtension('Entry', entry);
+
+ return entry;
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory DataTransferItem._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String kind;
+
+ final String type;
+
+ File getAsFile() native;
+
+ @JSName('webkitGetAsEntry')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ Entry _webkitGetAsEntry() native;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DataTransferItemList")
+class DataTransferItemList extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DataTransferItemList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int length;
+
+ DataTransferItem add(data_OR_file, [String type]) native;
+
+ @JSName('add')
+ DataTransferItem addData(String data, String type) native;
+
+ @JSName('add')
+ DataTransferItem addFile(File file) native;
+
+ void clear() native;
+
+ DataTransferItem item(int index) native;
+
+ void remove(int index) native;
+
+ DataTransferItem operator [](int index) {
+ return JS('DataTransferItem', '#[#]', this, index);
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void DatabaseCallback(SqlDatabase database);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void DecodeErrorCallback(DomException error);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void DecodeSuccessCallback(AudioBuffer decodedData);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DedicatedWorkerGlobalScope")
+class DedicatedWorkerGlobalScope extends WorkerGlobalScope {
+ // To suppress missing implicit constructor warnings.
+ factory DedicatedWorkerGlobalScope._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `message` events to event
+ * handlers that are not necessarily instances of [DedicatedWorkerGlobalScope].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ static const int PERSISTENT = 1;
+
+ static const int TEMPORARY = 0;
+
+ void close() native;
+
+ void postMessage(/*any*/ message, [List<Object> transfer]) {
+ if (transfer != null) {
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_1(message_1, transfer);
+ return;
+ }
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_2(message_1);
+ return;
+ }
+
+ @JSName('postMessage')
+ void _postMessage_1(message, List<Object> transfer) native;
+ @JSName('postMessage')
+ void _postMessage_2(message) native;
+
+ @JSName('webkitRequestFileSystem')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void _webkitRequestFileSystem(int type, int size,
+ [_FileSystemCallback successCallback,
+ _ErrorCallback errorCallback]) native;
+
+ @JSName('webkitRequestFileSystemSync')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ _DOMFileSystemSync requestFileSystemSync(int type, int size) native;
+
+ @JSName('webkitResolveLocalFileSystemSyncURL')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ _EntrySync resolveLocalFileSystemSyncUrl(String url) native;
+
+ @JSName('webkitResolveLocalFileSystemURL')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void _webkitResolveLocalFileSystemUrl(
+ String url, _EntryCallback successCallback,
+ [_ErrorCallback errorCallback]) native;
+
+ /// Stream of `message` events handled by this [DedicatedWorkerGlobalScope].
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+ static DedicatedWorkerGlobalScope get instance {
+ return _workerSelf as DedicatedWorkerGlobalScope;
+ }
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeprecatedStorageInfo")
+class DeprecatedStorageInfo extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DeprecatedStorageInfo._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int PERSISTENT = 1;
+
+ static const int TEMPORARY = 0;
+
+ void queryUsageAndQuota(int storageType,
+ [StorageUsageCallback usageCallback,
+ StorageErrorCallback errorCallback]) native;
+
+ void requestQuota(int storageType, int newQuotaInBytes,
+ [StorageQuotaCallback quotaCallback,
+ StorageErrorCallback errorCallback]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeprecatedStorageQuota")
+class DeprecatedStorageQuota extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DeprecatedStorageQuota._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void queryUsageAndQuota(StorageUsageCallback usageCallback,
+ [StorageErrorCallback errorCallback]) native;
+
+ void requestQuota(int newQuotaInBytes,
+ [StorageQuotaCallback quotaCallback,
+ StorageErrorCallback errorCallback]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeprecationReport")
+class DeprecationReport extends ReportBody {
+ // To suppress missing implicit constructor warnings.
+ factory DeprecationReport._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int lineNumber;
+
+ final String message;
+
+ final String sourceFile;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("HTMLDetailsElement")
+class DetailsElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory DetailsElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DetailsElement() => document.createElement("details");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ DetailsElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Element.isTagSupported('details');
+
+ bool open;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DetectedBarcode")
+class DetectedBarcode extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DetectedBarcode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DetectedBarcode() {
+ return DetectedBarcode._create_1();
+ }
+ static DetectedBarcode _create_1() =>
+ JS('DetectedBarcode', 'new DetectedBarcode()');
+
+ final Rectangle boundingBox;
+
+ final List cornerPoints;
+
+ final String rawValue;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DetectedFace")
+class DetectedFace extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DetectedFace._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DetectedFace() {
+ return DetectedFace._create_1();
+ }
+ static DetectedFace _create_1() => JS('DetectedFace', 'new DetectedFace()');
+
+ final Rectangle boundingBox;
+
+ final List landmarks;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DetectedText")
+class DetectedText extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DetectedText._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DetectedText() {
+ return DetectedText._create_1();
+ }
+ static DetectedText _create_1() => JS('DetectedText', 'new DetectedText()');
+
+ final Rectangle boundingBox;
+
+ final List cornerPoints;
+
+ final String rawValue;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeviceAcceleration")
+class DeviceAcceleration extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DeviceAcceleration._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num x;
+
+ final num y;
+
+ final num z;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeviceMotionEvent")
+class DeviceMotionEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory DeviceMotionEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DeviceMotionEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return DeviceMotionEvent._create_1(type, eventInitDict_1);
+ }
+ return DeviceMotionEvent._create_2(type);
+ }
+ static DeviceMotionEvent _create_1(type, eventInitDict) => JS(
+ 'DeviceMotionEvent', 'new DeviceMotionEvent(#,#)', type, eventInitDict);
+ static DeviceMotionEvent _create_2(type) =>
+ JS('DeviceMotionEvent', 'new DeviceMotionEvent(#)', type);
+
+ final DeviceAcceleration acceleration;
+
+ final DeviceAcceleration accelerationIncludingGravity;
+
+ final num interval;
+
+ final DeviceRotationRate rotationRate;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeviceOrientationEvent")
+class DeviceOrientationEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory DeviceOrientationEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DeviceOrientationEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return DeviceOrientationEvent._create_1(type, eventInitDict_1);
+ }
+ return DeviceOrientationEvent._create_2(type);
+ }
+ static DeviceOrientationEvent _create_1(type, eventInitDict) => JS(
+ 'DeviceOrientationEvent',
+ 'new DeviceOrientationEvent(#,#)',
+ type,
+ eventInitDict);
+ static DeviceOrientationEvent _create_2(type) =>
+ JS('DeviceOrientationEvent', 'new DeviceOrientationEvent(#)', type);
+
+ final bool absolute;
+
+ final num alpha;
+
+ final num beta;
+
+ final num gamma;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DeviceRotationRate")
+class DeviceRotationRate extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DeviceRotationRate._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num alpha;
+
+ final num beta;
+
+ final num gamma;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("HTMLDialogElement")
+class DialogElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory DialogElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ DialogElement.created() : super.created();
+
+ bool open;
+
+ String returnValue;
+
+ void close([String returnValue]) native;
+
+ void show() native;
+
+ void showModal() native;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DirectoryEntry")
+class DirectoryEntry extends Entry {
+ /**
+ * Create a new directory with the specified `path`. If `exclusive` is true,
+ * the returned Future will complete with an error if a directory already
+ * exists with the specified `path`.
+ */
+ Future<Entry> createDirectory(String path, {bool exclusive: false}) {
+ return _getDirectory(path,
+ options: {'create': true, 'exclusive': exclusive});
+ }
+
+ DirectoryReader createReader() {
+ DirectoryReader reader = _createReader();
+ applyExtension('DirectoryReader', reader);
+ return reader;
+ }
+
+ /**
+ * Retrieve an already existing directory entry. The returned future will
+ * result in an error if a directory at `path` does not exist or if the item
+ * at `path` is not a directory.
+ */
+ Future<Entry> getDirectory(String path) {
+ return _getDirectory(path);
+ }
+
+ /**
+ * Create a new file with the specified `path`. If `exclusive` is true,
+ * the returned Future will complete with an error if a file already
+ * exists at the specified `path`.
+ */
+ Future<Entry> createFile(String path, {bool exclusive: false}) {
+ return _getFile(path, options: {'create': true, 'exclusive': exclusive});
+ }
+
+ /**
+ * Retrieve an already existing file entry. The returned future will
+ * result in an error if a file at `path` does not exist or if the item at
+ * `path` is not a file.
+ */
+ Future<Entry> getFile(String path) {
+ return _getFile(path);
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory DirectoryEntry._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('createReader')
+ DirectoryReader _createReader() native;
+
+ void __getDirectory(String path,
+ [Map options,
+ _EntryCallback successCallback,
+ _ErrorCallback errorCallback]) {
+ if (errorCallback != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ __getDirectory_1(path, options_1, successCallback, errorCallback);
+ return;
+ }
+ if (successCallback != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ __getDirectory_2(path, options_1, successCallback);
+ return;
+ }
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ __getDirectory_3(path, options_1);
+ return;
+ }
+ __getDirectory_4(path);
+ return;
+ }
+
+ @JSName('getDirectory')
+ void __getDirectory_1(path, options, _EntryCallback successCallback,
+ _ErrorCallback errorCallback) native;
+ @JSName('getDirectory')
+ void __getDirectory_2(path, options, _EntryCallback successCallback) native;
+ @JSName('getDirectory')
+ void __getDirectory_3(path, options) native;
+ @JSName('getDirectory')
+ void __getDirectory_4(path) native;
+
+ @JSName('getDirectory')
+ Future<Entry> _getDirectory(String path, {Map options}) {
+ var completer = new Completer<Entry>();
+ __getDirectory(path, options, (value) {
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ void __getFile(String path,
+ [Map options,
+ _EntryCallback successCallback,
+ _ErrorCallback errorCallback]) {
+ if (errorCallback != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ __getFile_1(path, options_1, successCallback, errorCallback);
+ return;
+ }
+ if (successCallback != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ __getFile_2(path, options_1, successCallback);
+ return;
+ }
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ __getFile_3(path, options_1);
+ return;
+ }
+ __getFile_4(path);
+ return;
+ }
+
+ @JSName('getFile')
+ void __getFile_1(path, options, _EntryCallback successCallback,
+ _ErrorCallback errorCallback) native;
+ @JSName('getFile')
+ void __getFile_2(path, options, _EntryCallback successCallback) native;
+ @JSName('getFile')
+ void __getFile_3(path, options) native;
+ @JSName('getFile')
+ void __getFile_4(path) native;
+
+ @JSName('getFile')
+ Future<Entry> _getFile(String path, {Map options}) {
+ var completer = new Completer<Entry>();
+ __getFile(path, options, (value) {
+ applyExtension('FileEntry', value);
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ @JSName('removeRecursively')
+ void _removeRecursively(VoidCallback successCallback,
+ [_ErrorCallback errorCallback]) native;
+
+ @JSName('removeRecursively')
+ Future removeRecursively() {
+ var completer = new Completer();
+ _removeRecursively(() {
+ completer.complete();
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DirectoryReader")
+class DirectoryReader extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DirectoryReader._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('readEntries')
+ void _readEntries(_EntriesCallback successCallback,
+ [_ErrorCallback errorCallback]) native;
+
+ Future<List<Entry>> readEntries() {
+ var completer = new Completer<List<Entry>>();
+ _readEntries((values) {
+ values.forEach((value) {
+ applyExtension('Entry', value);
+ Entry entry = value as Entry;
+ if (entry.isFile)
+ applyExtension('FileEntry', entry);
+ else if (entry.isDirectory) applyExtension('DirectoryEntry', entry);
+ });
+ completer.complete(new List<Entry>.from(values));
+ }, (error) {
+ completer.completeError(error);
+ });
+
+ return completer.future;
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A generic container for content on an HTML page;
+ * corresponds to the <div> tag.
+ *
+ * The [DivElement] is a generic container and does not have any semantic
+ * significance. It is functionally similar to [SpanElement].
+ *
+ * The [DivElement] is a block-level element, as opposed to [SpanElement],
+ * which is an inline-level element.
+ *
+ * Example usage:
+ *
+ * DivElement div = new DivElement();
+ * div.text = 'Here's my new DivElem
+ * document.body.elements.add(elem);
+ *
+ * See also:
+ *
+ * * [HTML `<div>` element](http://www.w3.org/TR/html-markup/div.html) from W3C.
+ * * [Block-level element](http://www.w3.org/TR/CSS2/visuren.html#block-boxes) from W3C.
+ * * [Inline-level element](http://www.w3.org/TR/CSS2/visuren.html#inline-boxes) from W3C.
+ */
+@Native("HTMLDivElement")
+class DivElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory DivElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DivElement() => JS('returns:DivElement;creates:DivElement;new:true',
+ '#.createElement(#)', document, "div");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ DivElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * The base class for all documents.
+ *
+ * Each web page loaded in the browser has its own [Document] object, which is
+ * typically an [HtmlDocument].
+ *
+ * If you aren't comfortable with DOM concepts, see the Dart tutorial
+ * [Target 2: Connect Dart & HTML](http://www.dartlang.org/docs/tutorials/connect-dart-html/).
+ */
+@Native("Document")
+class Document extends Node {
+ // To suppress missing implicit constructor warnings.
+ factory Document._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> pointerLockChangeEvent =
+ const EventStreamProvider<Event>('pointerlockchange');
+
+ static const EventStreamProvider<Event> pointerLockErrorEvent =
+ const EventStreamProvider<Event>('pointerlockerror');
+
+ /**
+ * Static factory designed to expose `readystatechange` events to event
+ * handlers that are not necessarily instances of [Document].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> readyStateChangeEvent =
+ const EventStreamProvider<Event>('readystatechange');
+
+ /**
+ * Static factory designed to expose `securitypolicyviolation` events to event
+ * handlers that are not necessarily instances of [Document].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<SecurityPolicyViolationEvent>
+ securityPolicyViolationEvent =
+ const EventStreamProvider<SecurityPolicyViolationEvent>(
+ 'securitypolicyviolation');
+
+ /**
+ * Static factory designed to expose `selectionchange` events to event
+ * handlers that are not necessarily instances of [Document].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> selectionChangeEvent =
+ const EventStreamProvider<Event>('selectionchange');
+
+ factory Document() {
+ return Document._create_1();
+ }
+ static Document _create_1() => JS('Document', 'new Document()');
+
+ final String addressSpace;
+
+ @JSName('body')
+ HtmlElement _body;
+
+ final String contentType;
+
+ String cookie;
+
+ final ScriptElement currentScript;
+
+ WindowBase get window => _convertNativeToDart_Window(this._get_window);
+ @JSName('defaultView')
+ @Creates('Window|=Object')
+ @Returns('Window|=Object')
+ @Creates('Window|=Object|Null')
+ @Returns('Window|=Object|Null')
+ final dynamic _get_window;
+
+ final Element documentElement;
+
+ final String domain;
+
+ final bool fullscreenEnabled;
+
+ @JSName('head')
+ final HeadElement _head;
+
+ final bool hidden;
+
+ final DomImplementation implementation;
+
+ @JSName('lastModified')
+ final String _lastModified;
+
+ final String origin;
+
+ @JSName('preferredStylesheetSet')
+ final String _preferredStylesheetSet;
+
+ final String readyState;
+
+ @JSName('referrer')
+ final String _referrer;
+
+ final SvgSvgElement rootElement;
+
+ Element rootScroller;
+
+ final Element scrollingElement;
+
+ @JSName('selectedStylesheetSet')
+ String _selectedStylesheetSet;
+
+ final String suborigin;
+
+ final DocumentTimeline timeline;
+
+ @JSName('title')
+ String _title;
+
+ @JSName('visibilityState')
+ final String _visibilityState;
+
+ @JSName('webkitFullscreenElement')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ final Element _webkitFullscreenElement;
+
+ @JSName('webkitFullscreenEnabled')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ final bool _webkitFullscreenEnabled;
+
+ @JSName('webkitHidden')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ final bool _webkitHidden;
+
+ @JSName('webkitVisibilityState')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ final String _webkitVisibilityState;
+
+ Node adoptNode(Node node) native;
+
+ @JSName('caretRangeFromPoint')
+ Range _caretRangeFromPoint(int x, int y) native;
+
+ DocumentFragment createDocumentFragment() native;
+
+ @JSName('createElement')
+ Element _createElement(String localName_OR_tagName,
+ [options_OR_typeExtension]) native;
+
+ @JSName('createElementNS')
+ Element _createElementNS(String namespaceURI, String qualifiedName,
+ [options_OR_typeExtension]) native;
+
+ @JSName('createEvent')
+ Event _createEvent(String eventType) native;
+
+ Range createRange() native;
+
+ @JSName('createTextNode')
+ Text _createTextNode(String data) native;
+
+ Touch _createTouch(Window view, EventTarget target, int identifier, num pageX,
+ num pageY, num screenX, num screenY,
+ [num radiusX, num radiusY, num rotationAngle, num force]) {
+ if (force != null) {
+ var target_1 = _convertDartToNative_EventTarget(target);
+ return _createTouch_1(view, target_1, identifier, pageX, pageY, screenX,
+ screenY, radiusX, radiusY, rotationAngle, force);
+ }
+ if (rotationAngle != null) {
+ var target_1 = _convertDartToNative_EventTarget(target);
+ return _createTouch_2(view, target_1, identifier, pageX, pageY, screenX,
+ screenY, radiusX, radiusY, rotationAngle);
+ }
+ if (radiusY != null) {
+ var target_1 = _convertDartToNative_EventTarget(target);
+ return _createTouch_3(view, target_1, identifier, pageX, pageY, screenX,
+ screenY, radiusX, radiusY);
+ }
+ if (radiusX != null) {
+ var target_1 = _convertDartToNative_EventTarget(target);
+ return _createTouch_4(
+ view, target_1, identifier, pageX, pageY, screenX, screenY, radiusX);
+ }
+ var target_1 = _convertDartToNative_EventTarget(target);
+ return _createTouch_5(
+ view, target_1, identifier, pageX, pageY, screenX, screenY);
+ }
+
+ @JSName('createTouch')
+ Touch _createTouch_1(Window view, target, identifier, pageX, pageY, screenX,
+ screenY, radiusX, radiusY, rotationAngle, force) native;
+ @JSName('createTouch')
+ Touch _createTouch_2(Window view, target, identifier, pageX, pageY, screenX,
+ screenY, radiusX, radiusY, rotationAngle) native;
+ @JSName('createTouch')
+ Touch _createTouch_3(Window view, target, identifier, pageX, pageY, screenX,
+ screenY, radiusX, radiusY) native;
+ @JSName('createTouch')
+ Touch _createTouch_4(Window view, target, identifier, pageX, pageY, screenX,
+ screenY, radiusX) native;
+ @JSName('createTouch')
+ Touch _createTouch_5(
+ Window view, target, identifier, pageX, pageY, screenX, screenY) native;
+
+ @JSName('createTouchList')
+ TouchList _createTouchList(Touch touches) native;
+
+ bool execCommand(String commandId, [bool showUI, String value]) native;
+
+ void exitFullscreen() native;
+
+ void exitPointerLock() native;
+
+ List<Animation> getAnimations() native;
+
+ @Creates('NodeList|HtmlCollection')
+ @Returns('NodeList|HtmlCollection')
+ List<Node> getElementsByClassName(String classNames) native;
+
+ @Creates('NodeList|HtmlCollection')
+ @Returns('NodeList|HtmlCollection')
+ List<Node> getElementsByName(String elementName) native;
+
+ @Creates('NodeList|HtmlCollection')
+ @Returns('NodeList|HtmlCollection')
+ List<Node> getElementsByTagName(String localName) native;
+
+ Node importNode(Node node, [bool deep]) native;
+
+ bool queryCommandEnabled(String commandId) native;
+
+ bool queryCommandIndeterm(String commandId) native;
+
+ bool queryCommandState(String commandId) native;
+
+ bool queryCommandSupported(String commandId) native;
+
+ String queryCommandValue(String commandId) native;
+
+ Function registerElement2(String type, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return _registerElement2_1(type, options_1);
+ }
+ return _registerElement2_2(type);
+ }
+
+ @JSName('registerElement')
+ Function _registerElement2_1(type, options) native;
+ @JSName('registerElement')
+ Function _registerElement2_2(type) native;
+
+ @JSName('webkitExitFullscreen')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void _webkitExitFullscreen() native;
+
+ // From NonElementParentNode
+
+ Element getElementById(String elementId) native;
+
+ // From DocumentOrShadowRoot
+
+ final Element activeElement;
+
+ final Element fullscreenElement;
+
+ final Element pointerLockElement;
+
+ @JSName('styleSheets')
+ @Returns('_StyleSheetList|Null')
+ @Creates('_StyleSheetList')
+ final List<StyleSheet> _styleSheets;
+
+ @JSName('elementFromPoint')
+ Element _elementFromPoint(int x, int y) native;
+
+ List<Element> elementsFromPoint(int x, int y) native;
+
+ // From FontFaceSource
+
+ final FontFaceSet fonts;
+
+ // From ParentNode
+
+ @JSName('childElementCount')
+ final int _childElementCount;
+
+ @JSName('children')
+ @Returns('HtmlCollection|Null')
+ @Creates('HtmlCollection')
+ final List<Node> _children;
+
+ @JSName('firstElementChild')
+ final Element _firstElementChild;
+
+ @JSName('lastElementChild')
+ final Element _lastElementChild;
+
+ /**
+ * Finds the first descendant element of this document that matches the
+ * specified group of selectors.
+ *
+ * Unless your webpage contains multiple documents, the top-level
+ * [querySelector]
+ * method behaves the same as this method, so you should use it instead to
+ * save typing a few characters.
+ *
+ * [selectors] should be a string using CSS selector syntax.
+ *
+ * var element1 = document.querySelector('.className');
+ * var element2 = document.querySelector('#id');
+ *
+ * For details about CSS selector syntax, see the
+ * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+ */
+ Element querySelector(String selectors) native;
+
+ @JSName('querySelectorAll')
+ @Creates('NodeList')
+ @Returns('NodeList')
+ List<Node> _querySelectorAll(String selectors) native;
+
+ /// Stream of `abort` events handled by this [Document].
+ Stream<Event> get onAbort => Element.abortEvent.forTarget(this);
+
+ /// Stream of `beforecopy` events handled by this [Document].
+ Stream<Event> get onBeforeCopy => Element.beforeCopyEvent.forTarget(this);
+
+ /// Stream of `beforecut` events handled by this [Document].
+ Stream<Event> get onBeforeCut => Element.beforeCutEvent.forTarget(this);
+
+ /// Stream of `beforepaste` events handled by this [Document].
+ Stream<Event> get onBeforePaste => Element.beforePasteEvent.forTarget(this);
+
+ /// Stream of `blur` events handled by this [Document].
+ Stream<Event> get onBlur => Element.blurEvent.forTarget(this);
+
+ Stream<Event> get onCanPlay => Element.canPlayEvent.forTarget(this);
+
+ Stream<Event> get onCanPlayThrough =>
+ Element.canPlayThroughEvent.forTarget(this);
+
+ /// Stream of `change` events handled by this [Document].
+ Stream<Event> get onChange => Element.changeEvent.forTarget(this);
+
+ /// Stream of `click` events handled by this [Document].
+ Stream<MouseEvent> get onClick => Element.clickEvent.forTarget(this);
+
+ /// Stream of `contextmenu` events handled by this [Document].
+ Stream<MouseEvent> get onContextMenu =>
+ Element.contextMenuEvent.forTarget(this);
+
+ /// Stream of `copy` events handled by this [Document].
+ Stream<ClipboardEvent> get onCopy => Element.copyEvent.forTarget(this);
+
+ /// Stream of `cut` events handled by this [Document].
+ Stream<ClipboardEvent> get onCut => Element.cutEvent.forTarget(this);
+
+ /// Stream of `doubleclick` events handled by this [Document].
+ @DomName('Document.ondblclick')
+ Stream<Event> get onDoubleClick => Element.doubleClickEvent.forTarget(this);
+
+ /// Stream of `drag` events handled by this [Document].
+ Stream<MouseEvent> get onDrag => Element.dragEvent.forTarget(this);
+
+ /// Stream of `dragend` events handled by this [Document].
+ Stream<MouseEvent> get onDragEnd => Element.dragEndEvent.forTarget(this);
+
+ /// Stream of `dragenter` events handled by this [Document].
+ Stream<MouseEvent> get onDragEnter => Element.dragEnterEvent.forTarget(this);
+
+ /// Stream of `dragleave` events handled by this [Document].
+ Stream<MouseEvent> get onDragLeave => Element.dragLeaveEvent.forTarget(this);
+
+ /// Stream of `dragover` events handled by this [Document].
+ Stream<MouseEvent> get onDragOver => Element.dragOverEvent.forTarget(this);
+
+ /// Stream of `dragstart` events handled by this [Document].
+ Stream<MouseEvent> get onDragStart => Element.dragStartEvent.forTarget(this);
+
+ /// Stream of `drop` events handled by this [Document].
+ Stream<MouseEvent> get onDrop => Element.dropEvent.forTarget(this);
+
+ Stream<Event> get onDurationChange =>
+ Element.durationChangeEvent.forTarget(this);
+
+ Stream<Event> get onEmptied => Element.emptiedEvent.forTarget(this);
+
+ Stream<Event> get onEnded => Element.endedEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [Document].
+ Stream<Event> get onError => Element.errorEvent.forTarget(this);
+
+ /// Stream of `focus` events handled by this [Document].
+ Stream<Event> get onFocus => Element.focusEvent.forTarget(this);
+
+ /// Stream of `input` events handled by this [Document].
+ Stream<Event> get onInput => Element.inputEvent.forTarget(this);
+
+ /// Stream of `invalid` events handled by this [Document].
+ Stream<Event> get onInvalid => Element.invalidEvent.forTarget(this);
+
+ /// Stream of `keydown` events handled by this [Document].
+ Stream<KeyboardEvent> get onKeyDown => Element.keyDownEvent.forTarget(this);
+
+ /// Stream of `keypress` events handled by this [Document].
+ Stream<KeyboardEvent> get onKeyPress => Element.keyPressEvent.forTarget(this);
+
+ /// Stream of `keyup` events handled by this [Document].
+ Stream<KeyboardEvent> get onKeyUp => Element.keyUpEvent.forTarget(this);
+
+ /// Stream of `load` events handled by this [Document].
+ Stream<Event> get onLoad => Element.loadEvent.forTarget(this);
+
+ Stream<Event> get onLoadedData => Element.loadedDataEvent.forTarget(this);
+
+ Stream<Event> get onLoadedMetadata =>
+ Element.loadedMetadataEvent.forTarget(this);
+
+ /// Stream of `mousedown` events handled by this [Document].
+ Stream<MouseEvent> get onMouseDown => Element.mouseDownEvent.forTarget(this);
+
+ /// Stream of `mouseenter` events handled by this [Document].
+ Stream<MouseEvent> get onMouseEnter =>
+ Element.mouseEnterEvent.forTarget(this);
+
+ /// Stream of `mouseleave` events handled by this [Document].
+ Stream<MouseEvent> get onMouseLeave =>
+ Element.mouseLeaveEvent.forTarget(this);
+
+ /// Stream of `mousemove` events handled by this [Document].
+ Stream<MouseEvent> get onMouseMove => Element.mouseMoveEvent.forTarget(this);
+
+ /// Stream of `mouseout` events handled by this [Document].
+ Stream<MouseEvent> get onMouseOut => Element.mouseOutEvent.forTarget(this);
+
+ /// Stream of `mouseover` events handled by this [Document].
+ Stream<MouseEvent> get onMouseOver => Element.mouseOverEvent.forTarget(this);
+
+ /// Stream of `mouseup` events handled by this [Document].
+ Stream<MouseEvent> get onMouseUp => Element.mouseUpEvent.forTarget(this);
+
+ /// Stream of `mousewheel` events handled by this [Document].
+ Stream<WheelEvent> get onMouseWheel =>
+ Element.mouseWheelEvent.forTarget(this);
+
+ /// Stream of `paste` events handled by this [Document].
+ Stream<ClipboardEvent> get onPaste => Element.pasteEvent.forTarget(this);
+
+ Stream<Event> get onPause => Element.pauseEvent.forTarget(this);
+
+ Stream<Event> get onPlay => Element.playEvent.forTarget(this);
+
+ Stream<Event> get onPlaying => Element.playingEvent.forTarget(this);
+
+ Stream<Event> get onPointerLockChange =>
+ pointerLockChangeEvent.forTarget(this);
+
+ Stream<Event> get onPointerLockError => pointerLockErrorEvent.forTarget(this);
+
+ Stream<Event> get onRateChange => Element.rateChangeEvent.forTarget(this);
+
+ /// Stream of `readystatechange` events handled by this [Document].
+ Stream<Event> get onReadyStateChange => readyStateChangeEvent.forTarget(this);
+
+ /// Stream of `reset` events handled by this [Document].
+ Stream<Event> get onReset => Element.resetEvent.forTarget(this);
+
+ Stream<Event> get onResize => Element.resizeEvent.forTarget(this);
+
+ /// Stream of `scroll` events handled by this [Document].
+ Stream<Event> get onScroll => Element.scrollEvent.forTarget(this);
+
+ /// Stream of `search` events handled by this [Document].
+ Stream<Event> get onSearch => Element.searchEvent.forTarget(this);
+
+ /// Stream of `securitypolicyviolation` events handled by this [Document].
+ Stream<SecurityPolicyViolationEvent> get onSecurityPolicyViolation =>
+ securityPolicyViolationEvent.forTarget(this);
+
+ Stream<Event> get onSeeked => Element.seekedEvent.forTarget(this);
+
+ Stream<Event> get onSeeking => Element.seekingEvent.forTarget(this);
+
+ /// Stream of `select` events handled by this [Document].
+ Stream<Event> get onSelect => Element.selectEvent.forTarget(this);
+
+ /// Stream of `selectionchange` events handled by this [Document].
+ Stream<Event> get onSelectionChange => selectionChangeEvent.forTarget(this);
+
+ /// Stream of `selectstart` events handled by this [Document].
+ Stream<Event> get onSelectStart => Element.selectStartEvent.forTarget(this);
+
+ Stream<Event> get onStalled => Element.stalledEvent.forTarget(this);
+
+ /// Stream of `submit` events handled by this [Document].
+ Stream<Event> get onSubmit => Element.submitEvent.forTarget(this);
+
+ Stream<Event> get onSuspend => Element.suspendEvent.forTarget(this);
+
+ Stream<Event> get onTimeUpdate => Element.timeUpdateEvent.forTarget(this);
+
+ /// Stream of `touchcancel` events handled by this [Document].
+ Stream<TouchEvent> get onTouchCancel =>
+ Element.touchCancelEvent.forTarget(this);
+
+ /// Stream of `touchend` events handled by this [Document].
+ Stream<TouchEvent> get onTouchEnd => Element.touchEndEvent.forTarget(this);
+
+ /// Stream of `touchmove` events handled by this [Document].
+ Stream<TouchEvent> get onTouchMove => Element.touchMoveEvent.forTarget(this);
+
+ /// Stream of `touchstart` events handled by this [Document].
+ Stream<TouchEvent> get onTouchStart =>
+ Element.touchStartEvent.forTarget(this);
+
+ Stream<Event> get onVolumeChange => Element.volumeChangeEvent.forTarget(this);
+
+ Stream<Event> get onWaiting => Element.waitingEvent.forTarget(this);
+
+ /// Stream of `fullscreenchange` events handled by this [Document].
+ Stream<Event> get onFullscreenChange =>
+ Element.fullscreenChangeEvent.forTarget(this);
+
+ /// Stream of `fullscreenerror` events handled by this [Document].
+ Stream<Event> get onFullscreenError =>
+ Element.fullscreenErrorEvent.forTarget(this);
+
+ /**
+ * Finds all descendant elements of this document that match the specified
+ * group of selectors.
+ *
+ * Unless your webpage contains multiple documents, the top-level
+ * [querySelectorAll]
+ * method behaves the same as this method, so you should use it instead to
+ * save typing a few characters.
+ *
+ * [selectors] should be a string using CSS selector syntax.
+ *
+ * var items = document.querySelectorAll('.itemClassName');
+ *
+ * For details about CSS selector syntax, see the
+ * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+ */
+ ElementList<T> querySelectorAll<T extends Element>(String selectors) =>
+ new _FrozenElementList<T>._wrap(_querySelectorAll(selectors));
+
+ /// Checks if [registerElement] is supported on the current platform.
+ bool get supportsRegisterElement {
+ return JS('bool', '("registerElement" in #)', this);
+ }
+
+ /// *Deprecated*: use [supportsRegisterElement] instead.
+ @deprecated
+ bool get supportsRegister => supportsRegisterElement;
+
+ void registerElement(String tag, Type customElementClass,
+ {String extendsTag}) {
+ registerElement2(
+ tag, {'prototype': customElementClass, 'extends': extendsTag});
+ }
+
+ @pragma('dart2js:tryInline') // Almost all call sites have one argument.
+ Element createElement(String tagName, [String typeExtension]) {
+ return (typeExtension == null)
+ ? _createElement_2(tagName)
+ : _createElement(tagName, typeExtension);
+ }
+
+ // The two-argument version of this is automatically generated, but we need to
+ // omit the typeExtension if it's null on Firefox or we get an is="null" attribute.
+ _createElement_2(String tagName) =>
+ JS('Element', '#.createElement(#)', this, tagName);
+
+ // The three-argument version of this is automatically generated, but we need to
+ // omit the typeExtension if it's null on Firefox or we get an is="null" attribute.
+ _createElementNS_2(String namespaceURI, String qualifiedName) => JS(
+ 'Element', '#.createElementNS(#, #)', this, namespaceURI, qualifiedName);
+
+ Element createElementNS(String namespaceURI, String qualifiedName,
+ [String typeExtension]) {
+ return (typeExtension == null)
+ ? _createElementNS_2(namespaceURI, qualifiedName)
+ : _createElementNS(namespaceURI, qualifiedName, typeExtension);
+ }
+
+ NodeIterator _createNodeIterator(Node root,
+ [int whatToShow, NodeFilter filter]) =>
+ JS('NodeIterator', '#.createNodeIterator(#, #, #, false)', this, root,
+ whatToShow, filter);
+
+ TreeWalker _createTreeWalker(Node root,
+ [int whatToShow, NodeFilter filter]) =>
+ JS('TreeWalker', '#.createTreeWalker(#, #, #, false)', this, root,
+ whatToShow, filter);
+
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ String get visibilityState => JS(
+ 'String',
+ '(#.visibilityState || #.mozVisibilityState || #.msVisibilityState ||'
+ '#.webkitVisibilityState)',
+ this,
+ this,
+ this,
+ this);
+}
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DocumentFragment")
+class DocumentFragment extends Node
+ implements NonElementParentNode, ParentNode {
+ factory DocumentFragment() => document.createDocumentFragment();
+
+ factory DocumentFragment.html(String html,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ return document.body.createFragment(html,
+ validator: validator, treeSanitizer: treeSanitizer);
+ }
+
+ factory DocumentFragment.svg(String svgContent,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ return new svg.SvgSvgElement().createFragment(svgContent,
+ validator: validator, treeSanitizer: treeSanitizer);
+ }
+
+ HtmlCollection get _children =>
+ throw new UnimplementedError('Use _docChildren instead');
+
+ // Native field is used only by Dart code so does not lead to instantiation
+ // of native classes
+ @Creates('Null')
+ List<Element> _docChildren;
+
+ List<Element> get children {
+ if (_docChildren == null) {
+ _docChildren = new FilteredElementList(this);
+ }
+ return _docChildren;
+ }
+
+ set children(List<Element> value) {
+ // Copy list first since we don't want liveness during iteration.
+ var copy = value.toList();
+ var children = this.children;
+ children.clear();
+ children.addAll(copy);
+ }
+
+ /**
+ * Finds all descendant elements of this document fragment that match the
+ * specified group of selectors.
+ *
+ * [selectors] should be a string using CSS selector syntax.
+ *
+ * var items = document.querySelectorAll('.itemClassName');
+ *
+ * For details about CSS selector syntax, see the
+ * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+ */
+ ElementList<T> querySelectorAll<T extends Element>(String selectors) =>
+ new _FrozenElementList<T>._wrap(_querySelectorAll(selectors));
+
+ String get innerHtml {
+ final e = new DivElement();
+ e.append(this.clone(true));
+ return e.innerHtml;
+ }
+
+ set innerHtml(String value) {
+ this.setInnerHtml(value);
+ }
+
+ void setInnerHtml(String html,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ this.nodes.clear();
+ append(document.body.createFragment(html,
+ validator: validator, treeSanitizer: treeSanitizer));
+ }
+
+ /**
+ * Adds the specified text as a text node after the last child of this
+ * document fragment.
+ */
+ void appendText(String text) {
+ this.append(new Text(text));
+ }
+
+ /**
+ * Parses the specified text as HTML and adds the resulting node after the
+ * last child of this document fragment.
+ */
+ void appendHtml(String text,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ this.append(new DocumentFragment.html(text,
+ validator: validator, treeSanitizer: treeSanitizer));
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory DocumentFragment._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ // From NonElementParentNode
+
+ Element getElementById(String elementId) native;
+
+ // From ParentNode
+
+ @JSName('childElementCount')
+ final int _childElementCount;
+
+ @JSName('firstElementChild')
+ final Element _firstElementChild;
+
+ @JSName('lastElementChild')
+ final Element _lastElementChild;
+
+ /**
+ * Finds the first descendant element of this document fragment that matches
+ * the specified group of selectors.
+ *
+ * [selectors] should be a string using CSS selector syntax.
+ *
+ * var element1 = fragment.querySelector('.className');
+ * var element2 = fragment.querySelector('#id');
+ *
+ * For details about CSS selector syntax, see the
+ * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+ */
+ Element querySelector(String selectors) native;
+
+ @JSName('querySelectorAll')
+ @Creates('NodeList')
+ @Returns('NodeList')
+ List<Node> _querySelectorAll(String selectors) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DocumentOrShadowRoot")
+class DocumentOrShadowRoot extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DocumentOrShadowRoot._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Element activeElement;
+
+ final Element fullscreenElement;
+
+ final Element pointerLockElement;
+
+ @Returns('_StyleSheetList|Null')
+ @Creates('_StyleSheetList')
+ final List<StyleSheet> styleSheets;
+
+ Element elementFromPoint(int x, int y) native;
+
+ List<Element> elementsFromPoint(int x, int y) native;
+
+ Selection getSelection() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DocumentTimeline")
+class DocumentTimeline extends AnimationTimeline {
+ // To suppress missing implicit constructor warnings.
+ factory DocumentTimeline._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DocumentTimeline([Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return DocumentTimeline._create_1(options_1);
+ }
+ return DocumentTimeline._create_2();
+ }
+ static DocumentTimeline _create_1(options) =>
+ JS('DocumentTimeline', 'new DocumentTimeline(#)', options);
+ static DocumentTimeline _create_2() =>
+ JS('DocumentTimeline', 'new DocumentTimeline()');
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMError")
+class DomError extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DomError._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DomError(String name, [String message]) {
+ if (message != null) {
+ return DomError._create_1(name, message);
+ }
+ return DomError._create_2(name);
+ }
+ static DomError _create_1(name, message) =>
+ JS('DomError', 'new DOMError(#,#)', name, message);
+ static DomError _create_2(name) => JS('DomError', 'new DOMError(#)', name);
+
+ final String message;
+
+ final String name;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("DOMException")
+class DomException extends Interceptor {
+ static const String INDEX_SIZE = 'IndexSizeError';
+ static const String HIERARCHY_REQUEST = 'HierarchyRequestError';
+ static const String WRONG_DOCUMENT = 'WrongDocumentError';
+ static const String INVALID_CHARACTER = 'InvalidCharacterError';
+ static const String NO_MODIFICATION_ALLOWED = 'NoModificationAllowedError';
+ static const String NOT_FOUND = 'NotFoundError';
+ static const String NOT_SUPPORTED = 'NotSupportedError';
+ static const String INVALID_STATE = 'InvalidStateError';
+ static const String SYNTAX = 'SyntaxError';
+ static const String INVALID_MODIFICATION = 'InvalidModificationError';
+ static const String NAMESPACE = 'NamespaceError';
+ static const String INVALID_ACCESS = 'InvalidAccessError';
+ static const String TYPE_MISMATCH = 'TypeMismatchError';
+ static const String SECURITY = 'SecurityError';
+ static const String NETWORK = 'NetworkError';
+ static const String ABORT = 'AbortError';
+ static const String URL_MISMATCH = 'URLMismatchError';
+ static const String QUOTA_EXCEEDED = 'QuotaExceededError';
+ static const String TIMEOUT = 'TimeoutError';
+ static const String INVALID_NODE_TYPE = 'InvalidNodeTypeError';
+ static const String DATA_CLONE = 'DataCloneError';
+ static const String ENCODING = 'EncodingError';
+ static const String NOT_READABLE = 'NotReadableError';
+ static const String UNKNOWN = 'UnknownError';
+ static const String CONSTRAINT = 'ConstraintError';
+ static const String TRANSACTION_INACTIVE = 'TransactionInactiveError';
+ static const String READ_ONLY = 'ReadOnlyError';
+ static const String VERSION = 'VersionError';
+ static const String OPERATION = 'OperationError';
+ static const String NOT_ALLOWED = 'NotAllowedError';
+ // Is TypeError class derived from DomException but name is 'TypeError'
+ static const String TYPE_ERROR = 'TypeError';
+
+ String get name {
+ var errorName = JS('String', '#.name', this);
+ // Although Safari nightly has updated the name to SecurityError, Safari 5
+ // and 6 still return SECURITY_ERR.
+ if (Device.isWebKit && errorName == 'SECURITY_ERR') return 'SecurityError';
+ // Chrome release still uses old string, remove this line when Chrome stable
+ // also prints out SyntaxError.
+ if (Device.isWebKit && errorName == 'SYNTAX_ERR') return 'SyntaxError';
+ return errorName;
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory DomException._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String message;
+
+ String toString() => JS('String', 'String(#)', this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMImplementation")
+class DomImplementation extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DomImplementation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ XmlDocument createDocument(
+ String namespaceURI, String qualifiedName, _DocumentType doctype) native;
+
+ _DocumentType createDocumentType(
+ String qualifiedName, String publicId, String systemId) native;
+
+ @JSName('createHTMLDocument')
+ HtmlDocument createHtmlDocument([String title]) native;
+
+ bool hasFeature() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Iterator")
+class DomIterator extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DomIterator._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Object next([Object value]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMMatrix")
+class DomMatrix extends DomMatrixReadOnly {
+ // To suppress missing implicit constructor warnings.
+ factory DomMatrix._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DomMatrix([Object init]) {
+ if (init != null) {
+ return DomMatrix._create_1(init);
+ }
+ return DomMatrix._create_2();
+ }
+ static DomMatrix _create_1(init) => JS('DomMatrix', 'new DOMMatrix(#)', init);
+ static DomMatrix _create_2() => JS('DomMatrix', 'new DOMMatrix()');
+
+ // Shadowing definition.
+ num get a => JS("num", "#.a", this);
+
+ set a(num value) {
+ JS("void", "#.a = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get b => JS("num", "#.b", this);
+
+ set b(num value) {
+ JS("void", "#.b = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get c => JS("num", "#.c", this);
+
+ set c(num value) {
+ JS("void", "#.c = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get d => JS("num", "#.d", this);
+
+ set d(num value) {
+ JS("void", "#.d = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get e => JS("num", "#.e", this);
+
+ set e(num value) {
+ JS("void", "#.e = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get f => JS("num", "#.f", this);
+
+ set f(num value) {
+ JS("void", "#.f = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m11 => JS("num", "#.m11", this);
+
+ set m11(num value) {
+ JS("void", "#.m11 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m12 => JS("num", "#.m12", this);
+
+ set m12(num value) {
+ JS("void", "#.m12 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m13 => JS("num", "#.m13", this);
+
+ set m13(num value) {
+ JS("void", "#.m13 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m14 => JS("num", "#.m14", this);
+
+ set m14(num value) {
+ JS("void", "#.m14 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m21 => JS("num", "#.m21", this);
+
+ set m21(num value) {
+ JS("void", "#.m21 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m22 => JS("num", "#.m22", this);
+
+ set m22(num value) {
+ JS("void", "#.m22 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m23 => JS("num", "#.m23", this);
+
+ set m23(num value) {
+ JS("void", "#.m23 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m24 => JS("num", "#.m24", this);
+
+ set m24(num value) {
+ JS("void", "#.m24 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m31 => JS("num", "#.m31", this);
+
+ set m31(num value) {
+ JS("void", "#.m31 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m32 => JS("num", "#.m32", this);
+
+ set m32(num value) {
+ JS("void", "#.m32 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m33 => JS("num", "#.m33", this);
+
+ set m33(num value) {
+ JS("void", "#.m33 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m34 => JS("num", "#.m34", this);
+
+ set m34(num value) {
+ JS("void", "#.m34 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m41 => JS("num", "#.m41", this);
+
+ set m41(num value) {
+ JS("void", "#.m41 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m42 => JS("num", "#.m42", this);
+
+ set m42(num value) {
+ JS("void", "#.m42 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m43 => JS("num", "#.m43", this);
+
+ set m43(num value) {
+ JS("void", "#.m43 = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get m44 => JS("num", "#.m44", this);
+
+ set m44(num value) {
+ JS("void", "#.m44 = #", this, value);
+ }
+
+ static DomMatrix fromFloat32Array(Float32List array32) native;
+
+ static DomMatrix fromFloat64Array(Float64List array64) native;
+
+ static DomMatrix fromMatrix([Map other]) {
+ if (other != null) {
+ var other_1 = convertDartToNative_Dictionary(other);
+ return _fromMatrix_1(other_1);
+ }
+ return _fromMatrix_2();
+ }
+
+ @JSName('fromMatrix')
+ static DomMatrix _fromMatrix_1(other) native;
+ @JSName('fromMatrix')
+ static DomMatrix _fromMatrix_2() native;
+
+ DomMatrix invertSelf() native;
+
+ DomMatrix multiplySelf([Map other]) {
+ if (other != null) {
+ var other_1 = convertDartToNative_Dictionary(other);
+ return _multiplySelf_1(other_1);
+ }
+ return _multiplySelf_2();
+ }
+
+ @JSName('multiplySelf')
+ DomMatrix _multiplySelf_1(other) native;
+ @JSName('multiplySelf')
+ DomMatrix _multiplySelf_2() native;
+
+ DomMatrix preMultiplySelf([Map other]) {
+ if (other != null) {
+ var other_1 = convertDartToNative_Dictionary(other);
+ return _preMultiplySelf_1(other_1);
+ }
+ return _preMultiplySelf_2();
+ }
+
+ @JSName('preMultiplySelf')
+ DomMatrix _preMultiplySelf_1(other) native;
+ @JSName('preMultiplySelf')
+ DomMatrix _preMultiplySelf_2() native;
+
+ DomMatrix rotateAxisAngleSelf([num x, num y, num z, num angle]) native;
+
+ DomMatrix rotateFromVectorSelf([num x, num y]) native;
+
+ DomMatrix rotateSelf([num rotX, num rotY, num rotZ]) native;
+
+ DomMatrix scale3dSelf([num scale, num originX, num originY, num originZ])
+ native;
+
+ DomMatrix scaleSelf(
+ [num scaleX,
+ num scaleY,
+ num scaleZ,
+ num originX,
+ num originY,
+ num originZ]) native;
+
+ DomMatrix setMatrixValue(String transformList) native;
+
+ DomMatrix skewXSelf([num sx]) native;
+
+ DomMatrix skewYSelf([num sy]) native;
+
+ DomMatrix translateSelf([num tx, num ty, num tz]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMMatrixReadOnly")
+class DomMatrixReadOnly extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DomMatrixReadOnly._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DomMatrixReadOnly([Object init]) {
+ if (init != null) {
+ return DomMatrixReadOnly._create_1(init);
+ }
+ return DomMatrixReadOnly._create_2();
+ }
+ static DomMatrixReadOnly _create_1(init) =>
+ JS('DomMatrixReadOnly', 'new DOMMatrixReadOnly(#)', init);
+ static DomMatrixReadOnly _create_2() =>
+ JS('DomMatrixReadOnly', 'new DOMMatrixReadOnly()');
+
+ num get a => JS("num", "#.a", this);
+
+ num get b => JS("num", "#.b", this);
+
+ num get c => JS("num", "#.c", this);
+
+ num get d => JS("num", "#.d", this);
+
+ num get e => JS("num", "#.e", this);
+
+ num get f => JS("num", "#.f", this);
+
+ bool get is2D => JS("bool", "#.is2D", this);
+
+ bool get isIdentity => JS("bool", "#.isIdentity", this);
+
+ num get m11 => JS("num", "#.m11", this);
+
+ num get m12 => JS("num", "#.m12", this);
+
+ num get m13 => JS("num", "#.m13", this);
+
+ num get m14 => JS("num", "#.m14", this);
+
+ num get m21 => JS("num", "#.m21", this);
+
+ num get m22 => JS("num", "#.m22", this);
+
+ num get m23 => JS("num", "#.m23", this);
+
+ num get m24 => JS("num", "#.m24", this);
+
+ num get m31 => JS("num", "#.m31", this);
+
+ num get m32 => JS("num", "#.m32", this);
+
+ num get m33 => JS("num", "#.m33", this);
+
+ num get m34 => JS("num", "#.m34", this);
+
+ num get m41 => JS("num", "#.m41", this);
+
+ num get m42 => JS("num", "#.m42", this);
+
+ num get m43 => JS("num", "#.m43", this);
+
+ num get m44 => JS("num", "#.m44", this);
+
+ DomMatrix flipX() native;
+
+ DomMatrix flipY() native;
+
+ static DomMatrixReadOnly fromFloat32Array(Float32List array32) native;
+
+ static DomMatrixReadOnly fromFloat64Array(Float64List array64) native;
+
+ static DomMatrixReadOnly fromMatrix([Map other]) {
+ if (other != null) {
+ var other_1 = convertDartToNative_Dictionary(other);
+ return _fromMatrix_1(other_1);
+ }
+ return _fromMatrix_2();
+ }
+
+ @JSName('fromMatrix')
+ static DomMatrixReadOnly _fromMatrix_1(other) native;
+ @JSName('fromMatrix')
+ static DomMatrixReadOnly _fromMatrix_2() native;
+
+ DomMatrix inverse() native;
+
+ DomMatrix multiply([Map other]) {
+ if (other != null) {
+ var other_1 = convertDartToNative_Dictionary(other);
+ return _multiply_1(other_1);
+ }
+ return _multiply_2();
+ }
+
+ @JSName('multiply')
+ DomMatrix _multiply_1(other) native;
+ @JSName('multiply')
+ DomMatrix _multiply_2() native;
+
+ DomMatrix rotate([num rotX, num rotY, num rotZ]) native;
+
+ DomMatrix rotateAxisAngle([num x, num y, num z, num angle]) native;
+
+ DomMatrix rotateFromVector([num x, num y]) native;
+
+ DomMatrix scale(
+ [num scaleX,
+ num scaleY,
+ num scaleZ,
+ num originX,
+ num originY,
+ num originZ]) native;
+
+ DomMatrix scale3d([num scale, num originX, num originY, num originZ]) native;
+
+ DomMatrix skewX([num sx]) native;
+
+ DomMatrix skewY([num sy]) native;
+
+ Float32List toFloat32Array() native;
+
+ Float64List toFloat64Array() native;
+
+ DomPoint transformPoint([Map point]) {
+ if (point != null) {
+ var point_1 = convertDartToNative_Dictionary(point);
+ return _transformPoint_1(point_1);
+ }
+ return _transformPoint_2();
+ }
+
+ @JSName('transformPoint')
+ DomPoint _transformPoint_1(point) native;
+ @JSName('transformPoint')
+ DomPoint _transformPoint_2() native;
+
+ DomMatrix translate([num tx, num ty, num tz]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMParser")
+class DomParser extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DomParser._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DomParser() {
+ return DomParser._create_1();
+ }
+ static DomParser _create_1() => JS('DomParser', 'new DOMParser()');
+
+ Document parseFromString(String str, String type) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMPoint")
+class DomPoint extends DomPointReadOnly {
+ // To suppress missing implicit constructor warnings.
+ factory DomPoint._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DomPoint([num x, num y, num z, num w]) {
+ if (w != null) {
+ return DomPoint._create_1(x, y, z, w);
+ }
+ if (z != null) {
+ return DomPoint._create_2(x, y, z);
+ }
+ if (y != null) {
+ return DomPoint._create_3(x, y);
+ }
+ if (x != null) {
+ return DomPoint._create_4(x);
+ }
+ return DomPoint._create_5();
+ }
+ static DomPoint _create_1(x, y, z, w) =>
+ JS('DomPoint', 'new DOMPoint(#,#,#,#)', x, y, z, w);
+ static DomPoint _create_2(x, y, z) =>
+ JS('DomPoint', 'new DOMPoint(#,#,#)', x, y, z);
+ static DomPoint _create_3(x, y) => JS('DomPoint', 'new DOMPoint(#,#)', x, y);
+ static DomPoint _create_4(x) => JS('DomPoint', 'new DOMPoint(#)', x);
+ static DomPoint _create_5() => JS('DomPoint', 'new DOMPoint()');
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ JS('bool', '!!(window.DOMPoint) || !!(window.WebKitPoint)');
+
+ // Shadowing definition.
+ num get w => JS("num", "#.w", this);
+
+ set w(num value) {
+ JS("void", "#.w = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get x => JS("num", "#.x", this);
+
+ set x(num value) {
+ JS("void", "#.x = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get y => JS("num", "#.y", this);
+
+ set y(num value) {
+ JS("void", "#.y = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get z => JS("num", "#.z", this);
+
+ set z(num value) {
+ JS("void", "#.z = #", this, value);
+ }
+
+ static DomPoint fromPoint([Map other]) {
+ if (other != null) {
+ var other_1 = convertDartToNative_Dictionary(other);
+ return _fromPoint_1(other_1);
+ }
+ return _fromPoint_2();
+ }
+
+ @JSName('fromPoint')
+ static DomPoint _fromPoint_1(other) native;
+ @JSName('fromPoint')
+ static DomPoint _fromPoint_2() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMPointReadOnly")
+class DomPointReadOnly extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DomPointReadOnly._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DomPointReadOnly([num x, num y, num z, num w]) {
+ if (w != null) {
+ return DomPointReadOnly._create_1(x, y, z, w);
+ }
+ if (z != null) {
+ return DomPointReadOnly._create_2(x, y, z);
+ }
+ if (y != null) {
+ return DomPointReadOnly._create_3(x, y);
+ }
+ if (x != null) {
+ return DomPointReadOnly._create_4(x);
+ }
+ return DomPointReadOnly._create_5();
+ }
+ static DomPointReadOnly _create_1(x, y, z, w) =>
+ JS('DomPointReadOnly', 'new DOMPointReadOnly(#,#,#,#)', x, y, z, w);
+ static DomPointReadOnly _create_2(x, y, z) =>
+ JS('DomPointReadOnly', 'new DOMPointReadOnly(#,#,#)', x, y, z);
+ static DomPointReadOnly _create_3(x, y) =>
+ JS('DomPointReadOnly', 'new DOMPointReadOnly(#,#)', x, y);
+ static DomPointReadOnly _create_4(x) =>
+ JS('DomPointReadOnly', 'new DOMPointReadOnly(#)', x);
+ static DomPointReadOnly _create_5() =>
+ JS('DomPointReadOnly', 'new DOMPointReadOnly()');
+
+ num get w => JS("num", "#.w", this);
+
+ num get x => JS("num", "#.x", this);
+
+ num get y => JS("num", "#.y", this);
+
+ num get z => JS("num", "#.z", this);
+
+ static DomPointReadOnly fromPoint([Map other]) {
+ if (other != null) {
+ var other_1 = convertDartToNative_Dictionary(other);
+ return _fromPoint_1(other_1);
+ }
+ return _fromPoint_2();
+ }
+
+ @JSName('fromPoint')
+ static DomPointReadOnly _fromPoint_1(other) native;
+ @JSName('fromPoint')
+ static DomPointReadOnly _fromPoint_2() native;
+
+ DomPoint matrixTransform([Map matrix]) {
+ if (matrix != null) {
+ var matrix_1 = convertDartToNative_Dictionary(matrix);
+ return _matrixTransform_1(matrix_1);
+ }
+ return _matrixTransform_2();
+ }
+
+ @JSName('matrixTransform')
+ DomPoint _matrixTransform_1(matrix) native;
+ @JSName('matrixTransform')
+ DomPoint _matrixTransform_2() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMQuad")
+class DomQuad extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DomQuad._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DomQuad([Map p1, Map p2, Map p3, Map p4]) {
+ if (p4 != null) {
+ var p1_1 = convertDartToNative_Dictionary(p1);
+ var p2_2 = convertDartToNative_Dictionary(p2);
+ var p3_3 = convertDartToNative_Dictionary(p3);
+ var p4_4 = convertDartToNative_Dictionary(p4);
+ return DomQuad._create_1(p1_1, p2_2, p3_3, p4_4);
+ }
+ if (p3 != null) {
+ var p1_1 = convertDartToNative_Dictionary(p1);
+ var p2_2 = convertDartToNative_Dictionary(p2);
+ var p3_3 = convertDartToNative_Dictionary(p3);
+ return DomQuad._create_2(p1_1, p2_2, p3_3);
+ }
+ if (p2 != null) {
+ var p1_1 = convertDartToNative_Dictionary(p1);
+ var p2_2 = convertDartToNative_Dictionary(p2);
+ return DomQuad._create_3(p1_1, p2_2);
+ }
+ if (p1 != null) {
+ var p1_1 = convertDartToNative_Dictionary(p1);
+ return DomQuad._create_4(p1_1);
+ }
+ return DomQuad._create_5();
+ }
+ static DomQuad _create_1(p1, p2, p3, p4) =>
+ JS('DomQuad', 'new DOMQuad(#,#,#,#)', p1, p2, p3, p4);
+ static DomQuad _create_2(p1, p2, p3) =>
+ JS('DomQuad', 'new DOMQuad(#,#,#)', p1, p2, p3);
+ static DomQuad _create_3(p1, p2) => JS('DomQuad', 'new DOMQuad(#,#)', p1, p2);
+ static DomQuad _create_4(p1) => JS('DomQuad', 'new DOMQuad(#)', p1);
+ static DomQuad _create_5() => JS('DomQuad', 'new DOMQuad()');
+
+ final DomPoint p1;
+
+ final DomPoint p2;
+
+ final DomPoint p3;
+
+ final DomPoint p4;
+
+ static DomQuad fromQuad([Map other]) {
+ if (other != null) {
+ var other_1 = convertDartToNative_Dictionary(other);
+ return _fromQuad_1(other_1);
+ }
+ return _fromQuad_2();
+ }
+
+ @JSName('fromQuad')
+ static DomQuad _fromQuad_1(other) native;
+ @JSName('fromQuad')
+ static DomQuad _fromQuad_2() native;
+
+ static DomQuad fromRect([Map other]) {
+ if (other != null) {
+ var other_1 = convertDartToNative_Dictionary(other);
+ return _fromRect_1(other_1);
+ }
+ return _fromRect_2();
+ }
+
+ @JSName('fromRect')
+ static DomQuad _fromRect_1(other) native;
+ @JSName('fromRect')
+ static DomQuad _fromRect_2() native;
+
+ Rectangle getBounds() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ClientRectList,DOMRectList")
+class DomRectList extends Interceptor
+ with ListMixin<Rectangle>, ImmutableListMixin<Rectangle>
+ implements List<Rectangle>, JavaScriptIndexingBehavior<Rectangle> {
+ // To suppress missing implicit constructor warnings.
+ factory DomRectList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ Rectangle operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("Rectangle", "#[#]", this, index);
+ }
+
+ void operator []=(int index, Rectangle value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<Rectangle> mixins.
+ // Rectangle is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ Rectangle get first {
+ if (this.length > 0) {
+ return JS('Rectangle', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ Rectangle get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('Rectangle', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ Rectangle get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('Rectangle', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ Rectangle elementAt(int index) => this[index];
+ // -- end List<Rectangle> mixins.
+
+ Rectangle item(int index) native;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMRectReadOnly")
+class DomRectReadOnly extends Interceptor implements Rectangle {
+ // NOTE! All code below should be common with RectangleBase.
+ String toString() {
+ return 'Rectangle ($left, $top) $width x $height';
+ }
+
+ bool operator ==(other) {
+ if (other is! Rectangle) return false;
+ return left == other.left &&
+ top == other.top &&
+ width == other.width &&
+ height == other.height;
+ }
+
+ int get hashCode => _JenkinsSmiHash.hash4(
+ left.hashCode, top.hashCode, width.hashCode, height.hashCode);
+
+ /**
+ * Computes the intersection of `this` and [other].
+ *
+ * The intersection of two axis-aligned rectangles, if any, is always another
+ * axis-aligned rectangle.
+ *
+ * Returns the intersection of this and `other`, or null if they don't
+ * intersect.
+ */
+ Rectangle intersection(Rectangle other) {
+ var x0 = max(left, other.left);
+ var x1 = min(left + width, other.left + other.width);
+
+ if (x0 <= x1) {
+ var y0 = max(top, other.top);
+ var y1 = min(top + height, other.top + other.height);
+
+ if (y0 <= y1) {
+ return new Rectangle(x0, y0, x1 - x0, y1 - y0);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if `this` intersects [other].
+ */
+ bool intersects(Rectangle<num> other) {
+ return (left <= other.left + other.width &&
+ other.left <= left + width &&
+ top <= other.top + other.height &&
+ other.top <= top + height);
+ }
+
+ /**
+ * Returns a new rectangle which completely contains `this` and [other].
+ */
+ Rectangle boundingBox(Rectangle other) {
+ var right = max(this.left + this.width, other.left + other.width);
+ var bottom = max(this.top + this.height, other.top + other.height);
+
+ var left = min(this.left, other.left);
+ var top = min(this.top, other.top);
+
+ return new Rectangle(left, top, right - left, bottom - top);
+ }
+
+ /**
+ * Tests whether `this` entirely contains [another].
+ */
+ bool containsRectangle(Rectangle<num> another) {
+ return left <= another.left &&
+ left + width >= another.left + another.width &&
+ top <= another.top &&
+ top + height >= another.top + another.height;
+ }
+
+ /**
+ * Tests whether [another] is inside or along the edges of `this`.
+ */
+ bool containsPoint(Point<num> another) {
+ return another.x >= left &&
+ another.x <= left + width &&
+ another.y >= top &&
+ another.y <= top + height;
+ }
+
+ Point get topLeft => new Point(this.left, this.top);
+ Point get topRight => new Point(this.left + this.width, this.top);
+ Point get bottomRight =>
+ new Point(this.left + this.width, this.top + this.height);
+ Point get bottomLeft => new Point(this.left, this.top + this.height);
+
+ // To suppress missing implicit constructor warnings.
+ factory DomRectReadOnly._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DomRectReadOnly([num x, num y, num width, num height]) {
+ if (height != null) {
+ return DomRectReadOnly._create_1(x, y, width, height);
+ }
+ if (width != null) {
+ return DomRectReadOnly._create_2(x, y, width);
+ }
+ if (y != null) {
+ return DomRectReadOnly._create_3(x, y);
+ }
+ if (x != null) {
+ return DomRectReadOnly._create_4(x);
+ }
+ return DomRectReadOnly._create_5();
+ }
+ static DomRectReadOnly _create_1(x, y, width, height) => JS(
+ 'DomRectReadOnly', 'new DOMRectReadOnly(#,#,#,#)', x, y, width, height);
+ static DomRectReadOnly _create_2(x, y, width) =>
+ JS('DomRectReadOnly', 'new DOMRectReadOnly(#,#,#)', x, y, width);
+ static DomRectReadOnly _create_3(x, y) =>
+ JS('DomRectReadOnly', 'new DOMRectReadOnly(#,#)', x, y);
+ static DomRectReadOnly _create_4(x) =>
+ JS('DomRectReadOnly', 'new DOMRectReadOnly(#)', x);
+ static DomRectReadOnly _create_5() =>
+ JS('DomRectReadOnly', 'new DOMRectReadOnly()');
+
+ num get bottom => JS("num", "#.bottom", this);
+
+ num get height => JS("num", "#.height", this);
+
+ num get left => JS("num", "#.left", this);
+
+ num get right => JS("num", "#.right", this);
+
+ num get top => JS("num", "#.top", this);
+
+ num get width => JS("num", "#.width", this);
+
+ num get x => JS("num", "#.x", this);
+
+ num get y => JS("num", "#.y", this);
+
+ static DomRectReadOnly fromRect([Map other]) {
+ if (other != null) {
+ var other_1 = convertDartToNative_Dictionary(other);
+ return _fromRect_1(other_1);
+ }
+ return _fromRect_2();
+ }
+
+ @JSName('fromRect')
+ static DomRectReadOnly _fromRect_1(other) native;
+ @JSName('fromRect')
+ static DomRectReadOnly _fromRect_2() native;
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMStringList")
+class DomStringList extends Interceptor
+ with ListMixin<String>, ImmutableListMixin<String>
+ implements JavaScriptIndexingBehavior<String>, List<String> {
+ // To suppress missing implicit constructor warnings.
+ factory DomStringList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ String operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("String", "#[#]", this, index);
+ }
+
+ void operator []=(int index, String value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<String> mixins.
+ // String is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ String get first {
+ if (this.length > 0) {
+ return JS('String', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ String get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('String', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ String get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('String', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ String elementAt(int index) => this[index];
+ // -- end List<String> mixins.
+
+ String item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMStringMap")
+class DomStringMap extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DomStringMap._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void __delete__(String name) native;
+
+ void __setter__(String name, String value) native;
+
+ String item(String name) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DOMTokenList")
+class DomTokenList extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DomTokenList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int length;
+
+ String value;
+
+ void add(String tokens) native;
+
+ bool contains(String token) native;
+
+ String item(int index) native;
+
+ void remove(String tokens) native;
+
+ void replace(String token, String newToken) native;
+
+ bool supports(String token) native;
+
+ bool toggle(String token, [bool force]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class _ChildrenElementList extends ListBase<Element>
+ implements NodeListWrapper {
+ // Raw Element.
+ final Element _element;
+ final HtmlCollection _childElements;
+
+ _ChildrenElementList._wrap(Element element)
+ : _childElements = element._children,
+ _element = element;
+
+ bool contains(Object element) => _childElements.contains(element);
+
+ bool get isEmpty {
+ return _element._firstElementChild == null;
+ }
+
+ int get length {
+ return _childElements.length;
+ }
+
+ Element operator [](int index) {
+ return _childElements[index];
+ }
+
+ void operator []=(int index, Element value) {
+ _element._replaceChild(value, _childElements[index]);
+ }
+
+ set length(int newLength) {
+ // TODO(jacobr): remove children when length is reduced.
+ throw new UnsupportedError('Cannot resize element lists');
+ }
+
+ Element add(Element value) {
+ _element.append(value);
+ return value;
+ }
+
+ Iterator<Element> get iterator => toList().iterator;
+
+ void addAll(Iterable<Element> iterable) {
+ if (iterable is _ChildNodeListLazy) {
+ iterable = new List.from(iterable);
+ }
+
+ for (Element element in iterable) {
+ _element.append(element);
+ }
+ }
+
+ void sort([int compare(Element a, Element b)]) {
+ throw new UnsupportedError('Cannot sort element lists');
+ }
+
+ void shuffle([Random random]) {
+ throw new UnsupportedError('Cannot shuffle element lists');
+ }
+
+ void removeWhere(bool test(Element element)) {
+ _filter(test, false);
+ }
+
+ void retainWhere(bool test(Element element)) {
+ _filter(test, true);
+ }
+
+ void _filter(bool test(Element element), bool retainMatching) {
+ var removed;
+ if (retainMatching) {
+ removed = _element.children.where((e) => !test(e));
+ } else {
+ removed = _element.children.where(test);
+ }
+ for (var e in removed) e.remove();
+ }
+
+ void fillRange(int start, int end, [Element fillValue]) {
+ throw new UnimplementedError();
+ }
+
+ void replaceRange(int start, int end, Iterable<Element> iterable) {
+ throw new UnimplementedError();
+ }
+
+ void removeRange(int start, int end) {
+ throw new UnimplementedError();
+ }
+
+ void setRange(int start, int end, Iterable<Element> iterable,
+ [int skipCount = 0]) {
+ throw new UnimplementedError();
+ }
+
+ bool remove(Object object) {
+ if (object is Element) {
+ Element element = object;
+ if (identical(element.parentNode, _element)) {
+ _element._removeChild(element);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void insert(int index, Element element) {
+ if (index < 0 || index > length) {
+ throw new RangeError.range(index, 0, length);
+ }
+ if (index == length) {
+ _element.append(element);
+ } else {
+ _element.insertBefore(element, this[index]);
+ }
+ }
+
+ void setAll(int index, Iterable<Element> iterable) {
+ throw new UnimplementedError();
+ }
+
+ void clear() {
+ _element._clearChildren();
+ }
+
+ Element removeAt(int index) {
+ final result = this[index];
+ if (result != null) {
+ _element._removeChild(result);
+ }
+ return result;
+ }
+
+ Element removeLast() {
+ final result = this.last;
+ if (result != null) {
+ _element._removeChild(result);
+ }
+ return result;
+ }
+
+ Element get first {
+ Element result = _element._firstElementChild;
+ if (result == null) throw new StateError("No elements");
+ return result;
+ }
+
+ Element get last {
+ Element result = _element._lastElementChild;
+ if (result == null) throw new StateError("No elements");
+ return result;
+ }
+
+ Element get single {
+ if (length > 1) throw new StateError("More than one element");
+ return first;
+ }
+
+ List<Node> get rawList => _childElements;
+}
+
+/**
+ * An immutable list containing HTML elements. This list contains some
+ * additional methods when compared to regular lists for ease of CSS
+ * manipulation on a group of elements.
+ */
+abstract class ElementList<T extends Element> extends ListBase<T> {
+ /**
+ * The union of all CSS classes applied to the elements in this list.
+ *
+ * This set makes it easy to add, remove or toggle (add if not present, remove
+ * if present) the classes applied to a collection of elements.
+ *
+ * htmlList.classes.add('selected');
+ * htmlList.classes.toggle('isOnline');
+ * htmlList.classes.remove('selected');
+ */
+ CssClassSet get classes;
+
+ /** Replace the classes with `value` for every element in this list. */
+ set classes(Iterable<String> value);
+
+ /**
+ * Access the union of all [CssStyleDeclaration]s that are associated with an
+ * [ElementList].
+ *
+ * Grouping the style objects all together provides easy editing of specific
+ * properties of a collection of elements. Setting a specific property value
+ * will set that property in all [Element]s in the [ElementList]. Getting a
+ * specific property value will return the value of the property of the first
+ * element in the [ElementList].
+ */
+ CssStyleDeclarationBase get style;
+
+ /**
+ * Access dimensions and position of the Elements in this list.
+ *
+ * Setting the height or width properties will set the height or width
+ * property for all elements in the list. This returns a rectangle with the
+ * dimensions actually available for content
+ * in this element, in pixels, regardless of this element's box-sizing
+ * property. Getting the height or width returns the height or width of the
+ * first Element in this list.
+ *
+ * Unlike [getBoundingClientRect], the dimensions of this rectangle
+ * will return the same numerical height if the element is hidden or not.
+ */
+ CssRect get contentEdge;
+
+ /**
+ * Access dimensions and position of the first Element's content + padding box
+ * in this list.
+ *
+ * This returns a rectangle with the dimensions actually available for content
+ * in this element, in pixels, regardless of this element's box-sizing
+ * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+ * will return the same numerical height if the element is hidden or not. This
+ * can be used to retrieve jQuery's `innerHeight` value for an element. This
+ * is also a rectangle equalling the dimensions of clientHeight and
+ * clientWidth.
+ */
+ CssRect get paddingEdge;
+
+ /**
+ * Access dimensions and position of the first Element's content + padding +
+ * border box in this list.
+ *
+ * This returns a rectangle with the dimensions actually available for content
+ * in this element, in pixels, regardless of this element's box-sizing
+ * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+ * will return the same numerical height if the element is hidden or not. This
+ * can be used to retrieve jQuery's `outerHeight` value for an element.
+ */
+ CssRect get borderEdge;
+
+ /**
+ * Access dimensions and position of the first Element's content + padding +
+ * border + margin box in this list.
+ *
+ * This returns a rectangle with the dimensions actually available for content
+ * in this element, in pixels, regardless of this element's box-sizing
+ * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+ * will return the same numerical height if the element is hidden or not. This
+ * can be used to retrieve jQuery's `outerHeight` value for an element.
+ */
+ CssRect get marginEdge;
+
+ /// Stream of `abort` events handled by this [Element].
+ ElementStream<Event> get onAbort;
+
+ /// Stream of `beforecopy` events handled by this [Element].
+ ElementStream<Event> get onBeforeCopy;
+
+ /// Stream of `beforecut` events handled by this [Element].
+ ElementStream<Event> get onBeforeCut;
+
+ /// Stream of `beforepaste` events handled by this [Element].
+ ElementStream<Event> get onBeforePaste;
+
+ /// Stream of `blur` events handled by this [Element].
+ ElementStream<Event> get onBlur;
+
+ ElementStream<Event> get onCanPlay;
+
+ ElementStream<Event> get onCanPlayThrough;
+
+ /// Stream of `change` events handled by this [Element].
+ ElementStream<Event> get onChange;
+
+ /// Stream of `click` events handled by this [Element].
+ ElementStream<MouseEvent> get onClick;
+
+ /// Stream of `contextmenu` events handled by this [Element].
+ ElementStream<MouseEvent> get onContextMenu;
+
+ /// Stream of `copy` events handled by this [Element].
+ ElementStream<ClipboardEvent> get onCopy;
+
+ /// Stream of `cut` events handled by this [Element].
+ ElementStream<ClipboardEvent> get onCut;
+
+ /// Stream of `doubleclick` events handled by this [Element].
+ @DomName('Element.ondblclick')
+ ElementStream<Event> get onDoubleClick;
+
+ /**
+ * A stream of `drag` events fired when this element currently being dragged.
+ *
+ * A `drag` event is added to this stream as soon as the drag begins.
+ * A `drag` event is also added to this stream at intervals while the drag
+ * operation is still ongoing.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDrag;
+
+ /**
+ * A stream of `dragend` events fired when this element completes a drag
+ * operation.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragEnd;
+
+ /**
+ * A stream of `dragenter` events fired when a dragged object is first dragged
+ * over this element.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragEnter;
+
+ /**
+ * A stream of `dragleave` events fired when an object being dragged over this
+ * element leaves this element's target area.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragLeave;
+
+ /**
+ * A stream of `dragover` events fired when a dragged object is currently
+ * being dragged over this element.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragOver;
+
+ /**
+ * A stream of `dragstart` events fired when this element starts being
+ * dragged.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragStart;
+
+ /**
+ * A stream of `drop` events fired when a dragged object is dropped on this
+ * element.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDrop;
+
+ ElementStream<Event> get onDurationChange;
+
+ ElementStream<Event> get onEmptied;
+
+ ElementStream<Event> get onEnded;
+
+ /// Stream of `error` events handled by this [Element].
+ ElementStream<Event> get onError;
+
+ /// Stream of `focus` events handled by this [Element].
+ ElementStream<Event> get onFocus;
+
+ /// Stream of `input` events handled by this [Element].
+ ElementStream<Event> get onInput;
+
+ /// Stream of `invalid` events handled by this [Element].
+ ElementStream<Event> get onInvalid;
+
+ /// Stream of `keydown` events handled by this [Element].
+ ElementStream<KeyboardEvent> get onKeyDown;
+
+ /// Stream of `keypress` events handled by this [Element].
+ ElementStream<KeyboardEvent> get onKeyPress;
+
+ /// Stream of `keyup` events handled by this [Element].
+ ElementStream<KeyboardEvent> get onKeyUp;
+
+ /// Stream of `load` events handled by this [Element].
+ ElementStream<Event> get onLoad;
+
+ ElementStream<Event> get onLoadedData;
+
+ ElementStream<Event> get onLoadedMetadata;
+
+ /// Stream of `mousedown` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseDown;
+
+ /// Stream of `mouseenter` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseEnter;
+
+ /// Stream of `mouseleave` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseLeave;
+
+ /// Stream of `mousemove` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseMove;
+
+ /// Stream of `mouseout` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseOut;
+
+ /// Stream of `mouseover` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseOver;
+
+ /// Stream of `mouseup` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseUp;
+
+ /// Stream of `mousewheel` events handled by this [Element].
+ ElementStream<WheelEvent> get onMouseWheel;
+
+ /// Stream of `paste` events handled by this [Element].
+ ElementStream<ClipboardEvent> get onPaste;
+
+ ElementStream<Event> get onPause;
+
+ ElementStream<Event> get onPlay;
+
+ ElementStream<Event> get onPlaying;
+
+ ElementStream<Event> get onRateChange;
+
+ /// Stream of `reset` events handled by this [Element].
+ ElementStream<Event> get onReset;
+
+ ElementStream<Event> get onResize;
+
+ /// Stream of `scroll` events handled by this [Element].
+ ElementStream<Event> get onScroll;
+
+ /// Stream of `search` events handled by this [Element].
+ ElementStream<Event> get onSearch;
+
+ ElementStream<Event> get onSeeked;
+
+ ElementStream<Event> get onSeeking;
+
+ /// Stream of `select` events handled by this [Element].
+ ElementStream<Event> get onSelect;
+
+ /// Stream of `selectstart` events handled by this [Element].
+ ElementStream<Event> get onSelectStart;
+
+ ElementStream<Event> get onStalled;
+
+ /// Stream of `submit` events handled by this [Element].
+ ElementStream<Event> get onSubmit;
+
+ ElementStream<Event> get onSuspend;
+
+ ElementStream<Event> get onTimeUpdate;
+
+ /// Stream of `touchcancel` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchCancel;
+
+ /// Stream of `touchend` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchEnd;
+
+ /// Stream of `touchenter` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchEnter;
+
+ /// Stream of `touchleave` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchLeave;
+
+ /// Stream of `touchmove` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchMove;
+
+ /// Stream of `touchstart` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchStart;
+
+ /// Stream of `transitionend` events handled by this [Element].
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ ElementStream<TransitionEvent> get onTransitionEnd;
+
+ ElementStream<Event> get onVolumeChange;
+
+ ElementStream<Event> get onWaiting;
+
+ /// Stream of `fullscreenchange` events handled by this [Element].
+ ElementStream<Event> get onFullscreenChange;
+
+ /// Stream of `fullscreenerror` events handled by this [Element].
+ ElementStream<Event> get onFullscreenError;
+
+ ElementStream<WheelEvent> get onWheel;
+}
+
+// Wrapper over an immutable NodeList to make it implement ElementList.
+//
+// Clients are {`Document`, `DocumentFragment`}.`querySelectorAll` which are
+// declared to return `ElementList`. This provides all the static analysis
+// benefit so there is no need for this class have a constrained type parameter.
+//
+class _FrozenElementList<E extends Element> extends ListBase<E>
+ implements ElementList<E>, NodeListWrapper {
+ final List<Node> _nodeList;
+
+ _FrozenElementList._wrap(this._nodeList) {
+ assert(this._nodeList.every((element) => element is E),
+ "Query expects only HTML elements of type $E but found ${this._nodeList.firstWhere((e) => e is! E)}");
+ }
+
+ int get length => _nodeList.length;
+
+ E operator [](int index) => _nodeList[index];
+
+ void operator []=(int index, E value) {
+ throw new UnsupportedError('Cannot modify list');
+ }
+
+ set length(int newLength) {
+ throw new UnsupportedError('Cannot modify list');
+ }
+
+ void sort([Comparator<E> compare]) {
+ throw new UnsupportedError('Cannot sort list');
+ }
+
+ void shuffle([Random random]) {
+ throw new UnsupportedError('Cannot shuffle list');
+ }
+
+ E get first => _nodeList.first;
+
+ E get last => _nodeList.last;
+
+ E get single => _nodeList.single;
+
+ CssClassSet get classes => new _MultiElementCssClassSet(this);
+
+ CssStyleDeclarationBase get style => new _CssStyleDeclarationSet(this);
+
+ set classes(Iterable<String> value) {
+ // TODO(sra): This might be faster for Sets:
+ //
+ // new _MultiElementCssClassSet(this).writeClasses(value)
+ //
+ // as the code below converts the Iterable[value] to a string multiple
+ // times. Maybe compute the string and set className here.
+ forEach((e) => e.classes = value);
+ }
+
+ CssRect get contentEdge => new _ContentCssListRect(this);
+
+ CssRect get paddingEdge => this.first.paddingEdge;
+
+ CssRect get borderEdge => this.first.borderEdge;
+
+ CssRect get marginEdge => this.first.marginEdge;
+
+ List<Node> get rawList => _nodeList;
+
+ /// Stream of `abort` events handled by this [Element].
+ ElementStream<Event> get onAbort => Element.abortEvent._forElementList(this);
+
+ /// Stream of `beforecopy` events handled by this [Element].
+ ElementStream<Event> get onBeforeCopy =>
+ Element.beforeCopyEvent._forElementList(this);
+
+ /// Stream of `beforecut` events handled by this [Element].
+ ElementStream<Event> get onBeforeCut =>
+ Element.beforeCutEvent._forElementList(this);
+
+ /// Stream of `beforepaste` events handled by this [Element].
+ ElementStream<Event> get onBeforePaste =>
+ Element.beforePasteEvent._forElementList(this);
+
+ /// Stream of `blur` events handled by this [Element].
+ ElementStream<Event> get onBlur => Element.blurEvent._forElementList(this);
+
+ ElementStream<Event> get onCanPlay =>
+ Element.canPlayEvent._forElementList(this);
+
+ ElementStream<Event> get onCanPlayThrough =>
+ Element.canPlayThroughEvent._forElementList(this);
+
+ /// Stream of `change` events handled by this [Element].
+ ElementStream<Event> get onChange =>
+ Element.changeEvent._forElementList(this);
+
+ /// Stream of `click` events handled by this [Element].
+ ElementStream<MouseEvent> get onClick =>
+ Element.clickEvent._forElementList(this);
+
+ /// Stream of `contextmenu` events handled by this [Element].
+ ElementStream<MouseEvent> get onContextMenu =>
+ Element.contextMenuEvent._forElementList(this);
+
+ /// Stream of `copy` events handled by this [Element].
+ ElementStream<ClipboardEvent> get onCopy =>
+ Element.copyEvent._forElementList(this);
+
+ /// Stream of `cut` events handled by this [Element].
+ ElementStream<ClipboardEvent> get onCut =>
+ Element.cutEvent._forElementList(this);
+
+ /// Stream of `doubleclick` events handled by this [Element].
+ @DomName('Element.ondblclick')
+ ElementStream<Event> get onDoubleClick =>
+ Element.doubleClickEvent._forElementList(this);
+
+ /**
+ * A stream of `drag` events fired when this element currently being dragged.
+ *
+ * A `drag` event is added to this stream as soon as the drag begins.
+ * A `drag` event is also added to this stream at intervals while the drag
+ * operation is still ongoing.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDrag =>
+ Element.dragEvent._forElementList(this);
+
+ /**
+ * A stream of `dragend` events fired when this element completes a drag
+ * operation.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragEnd =>
+ Element.dragEndEvent._forElementList(this);
+
+ /**
+ * A stream of `dragenter` events fired when a dragged object is first dragged
+ * over this element.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragEnter =>
+ Element.dragEnterEvent._forElementList(this);
+
+ /**
+ * A stream of `dragleave` events fired when an object being dragged over this
+ * element leaves this element's target area.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragLeave =>
+ Element.dragLeaveEvent._forElementList(this);
+
+ /**
+ * A stream of `dragover` events fired when a dragged object is currently
+ * being dragged over this element.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragOver =>
+ Element.dragOverEvent._forElementList(this);
+
+ /**
+ * A stream of `dragstart` events fired when this element starts being
+ * dragged.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragStart =>
+ Element.dragStartEvent._forElementList(this);
+
+ /**
+ * A stream of `drop` events fired when a dragged object is dropped on this
+ * element.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDrop =>
+ Element.dropEvent._forElementList(this);
+
+ ElementStream<Event> get onDurationChange =>
+ Element.durationChangeEvent._forElementList(this);
+
+ ElementStream<Event> get onEmptied =>
+ Element.emptiedEvent._forElementList(this);
+
+ ElementStream<Event> get onEnded => Element.endedEvent._forElementList(this);
+
+ /// Stream of `error` events handled by this [Element].
+ ElementStream<Event> get onError => Element.errorEvent._forElementList(this);
+
+ /// Stream of `focus` events handled by this [Element].
+ ElementStream<Event> get onFocus => Element.focusEvent._forElementList(this);
+
+ /// Stream of `input` events handled by this [Element].
+ ElementStream<Event> get onInput => Element.inputEvent._forElementList(this);
+
+ /// Stream of `invalid` events handled by this [Element].
+ ElementStream<Event> get onInvalid =>
+ Element.invalidEvent._forElementList(this);
+
+ /// Stream of `keydown` events handled by this [Element].
+ ElementStream<KeyboardEvent> get onKeyDown =>
+ Element.keyDownEvent._forElementList(this);
+
+ /// Stream of `keypress` events handled by this [Element].
+ ElementStream<KeyboardEvent> get onKeyPress =>
+ Element.keyPressEvent._forElementList(this);
+
+ /// Stream of `keyup` events handled by this [Element].
+ ElementStream<KeyboardEvent> get onKeyUp =>
+ Element.keyUpEvent._forElementList(this);
+
+ /// Stream of `load` events handled by this [Element].
+ ElementStream<Event> get onLoad => Element.loadEvent._forElementList(this);
+
+ ElementStream<Event> get onLoadedData =>
+ Element.loadedDataEvent._forElementList(this);
+
+ ElementStream<Event> get onLoadedMetadata =>
+ Element.loadedMetadataEvent._forElementList(this);
+
+ /// Stream of `mousedown` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseDown =>
+ Element.mouseDownEvent._forElementList(this);
+
+ /// Stream of `mouseenter` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseEnter =>
+ Element.mouseEnterEvent._forElementList(this);
+
+ /// Stream of `mouseleave` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseLeave =>
+ Element.mouseLeaveEvent._forElementList(this);
+
+ /// Stream of `mousemove` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseMove =>
+ Element.mouseMoveEvent._forElementList(this);
+
+ /// Stream of `mouseout` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseOut =>
+ Element.mouseOutEvent._forElementList(this);
+
+ /// Stream of `mouseover` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseOver =>
+ Element.mouseOverEvent._forElementList(this);
+
+ /// Stream of `mouseup` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseUp =>
+ Element.mouseUpEvent._forElementList(this);
+
+ /// Stream of `mousewheel` events handled by this [Element].
+ ElementStream<WheelEvent> get onMouseWheel =>
+ Element.mouseWheelEvent._forElementList(this);
+
+ /// Stream of `paste` events handled by this [Element].
+ ElementStream<ClipboardEvent> get onPaste =>
+ Element.pasteEvent._forElementList(this);
+
+ ElementStream<Event> get onPause => Element.pauseEvent._forElementList(this);
+
+ ElementStream<Event> get onPlay => Element.playEvent._forElementList(this);
+
+ ElementStream<Event> get onPlaying =>
+ Element.playingEvent._forElementList(this);
+
+ ElementStream<Event> get onRateChange =>
+ Element.rateChangeEvent._forElementList(this);
+
+ /// Stream of `reset` events handled by this [Element].
+ ElementStream<Event> get onReset => Element.resetEvent._forElementList(this);
+
+ ElementStream<Event> get onResize =>
+ Element.resizeEvent._forElementList(this);
+
+ /// Stream of `scroll` events handled by this [Element].
+ ElementStream<Event> get onScroll =>
+ Element.scrollEvent._forElementList(this);
+
+ /// Stream of `search` events handled by this [Element].
+ ElementStream<Event> get onSearch =>
+ Element.searchEvent._forElementList(this);
+
+ ElementStream<Event> get onSeeked =>
+ Element.seekedEvent._forElementList(this);
+
+ ElementStream<Event> get onSeeking =>
+ Element.seekingEvent._forElementList(this);
+
+ /// Stream of `select` events handled by this [Element].
+ ElementStream<Event> get onSelect =>
+ Element.selectEvent._forElementList(this);
+
+ /// Stream of `selectstart` events handled by this [Element].
+ ElementStream<Event> get onSelectStart =>
+ Element.selectStartEvent._forElementList(this);
+
+ ElementStream<Event> get onStalled =>
+ Element.stalledEvent._forElementList(this);
+
+ /// Stream of `submit` events handled by this [Element].
+ ElementStream<Event> get onSubmit =>
+ Element.submitEvent._forElementList(this);
+
+ ElementStream<Event> get onSuspend =>
+ Element.suspendEvent._forElementList(this);
+
+ ElementStream<Event> get onTimeUpdate =>
+ Element.timeUpdateEvent._forElementList(this);
+
+ /// Stream of `touchcancel` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchCancel =>
+ Element.touchCancelEvent._forElementList(this);
+
+ /// Stream of `touchend` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchEnd =>
+ Element.touchEndEvent._forElementList(this);
+
+ /// Stream of `touchenter` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchEnter =>
+ Element.touchEnterEvent._forElementList(this);
+
+ /// Stream of `touchleave` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchLeave =>
+ Element.touchLeaveEvent._forElementList(this);
+
+ /// Stream of `touchmove` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchMove =>
+ Element.touchMoveEvent._forElementList(this);
+
+ /// Stream of `touchstart` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchStart =>
+ Element.touchStartEvent._forElementList(this);
+
+ /// Stream of `transitionend` events handled by this [Element].
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ ElementStream<TransitionEvent> get onTransitionEnd =>
+ Element.transitionEndEvent._forElementList(this);
+
+ ElementStream<Event> get onVolumeChange =>
+ Element.volumeChangeEvent._forElementList(this);
+
+ ElementStream<Event> get onWaiting =>
+ Element.waitingEvent._forElementList(this);
+
+ /// Stream of `fullscreenchange` events handled by this [Element].
+ ElementStream<Event> get onFullscreenChange =>
+ Element.fullscreenChangeEvent._forElementList(this);
+
+ /// Stream of `fullscreenerror` events handled by this [Element].
+ ElementStream<Event> get onFullscreenError =>
+ Element.fullscreenErrorEvent._forElementList(this);
+
+ ElementStream<WheelEvent> get onWheel =>
+ Element.wheelEvent._forElementList(this);
+}
+
+/**
+ * An abstract class, which all HTML elements extend.
+ */
+@Native("Element")
+class Element extends Node
+ implements
+ NonDocumentTypeChildNode,
+ GlobalEventHandlers,
+ ParentNode,
+ ChildNode {
+ /**
+ * Creates an HTML element from a valid fragment of HTML.
+ *
+ * var element = new Element.html('<div class="foo">content</div>');
+ *
+ * The HTML fragment should contain only one single root element, any
+ * leading or trailing text nodes will be removed.
+ *
+ * The HTML fragment is parsed as if it occurred within the context of a
+ * `<body>` tag, this means that special elements such as `<caption>` which
+ * must be parsed within the scope of a `<table>` element will be dropped. Use
+ * [createFragment] to parse contextual HTML fragments.
+ *
+ * Unless a validator is provided this will perform the default validation
+ * and remove all scriptable elements and attributes.
+ *
+ * See also:
+ *
+ * * [NodeValidator]
+ *
+ */
+ factory Element.html(String html,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ var fragment = document.body.createFragment(html,
+ validator: validator, treeSanitizer: treeSanitizer);
+
+ return fragment.nodes.where((e) => e is Element).single;
+ }
+
+ /**
+ * Custom element creation constructor.
+ *
+ * This constructor is used by the DOM when a custom element has been
+ * created. It can only be invoked by subclasses of Element from
+ * that classes created constructor.
+ *
+ * class CustomElement extends Element {
+ * factory CustomElement() => new Element.tag('x-custom');
+ *
+ * CustomElement.created() : super.created() {
+ * // Perform any element initialization.
+ * }
+ * }
+ * document.registerElement('x-custom', CustomElement);
+ */
+ Element.created() : super._created();
+
+ /**
+ * Creates the HTML element specified by the tag name.
+ *
+ * This is similar to [Document.createElement].
+ * [tag] should be a valid HTML tag name. If [tag] is an unknown tag then
+ * this will create an [UnknownElement].
+ *
+ * var divElement = new Element.tag('div');
+ * print(divElement is DivElement); // 'true'
+ * var myElement = new Element.tag('unknownTag');
+ * print(myElement is UnknownElement); // 'true'
+ *
+ * For standard elements it is better to use the element type constructors:
+ *
+ * var element = new DivElement();
+ *
+ * It is better to use e.g `new CanvasElement()` because the type of the
+ * expression is `CanvasElement`, whereas the type of `Element.tag` is the
+ * less specific `Element`.
+ *
+ * See also:
+ *
+ * * [isTagSupported]
+ */
+ factory Element.tag(String tag, [String typeExtention]) =>
+ _ElementFactoryProvider.createElement_tag(tag, typeExtention);
+
+ /// Creates a new `<a>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('a')`.
+ factory Element.a() => new AnchorElement();
+
+ /// Creates a new `<article>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('article')`.
+ factory Element.article() => new Element.tag('article');
+
+ /// Creates a new `<aside>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('aside')`.
+ factory Element.aside() => new Element.tag('aside');
+
+ /// Creates a new `<audio>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('audio')`.
+ factory Element.audio() => new Element.tag('audio');
+
+ /// Creates a new `<br>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('br')`.
+ factory Element.br() => new BRElement();
+
+ /// Creates a new `<canvas>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('canvas')`.
+ factory Element.canvas() => new CanvasElement();
+
+ /// Creates a new `<div>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('div')`.
+ factory Element.div() => new DivElement();
+
+ /// Creates a new `<footer>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('footer')`.
+ factory Element.footer() => new Element.tag('footer');
+
+ /// Creates a new `<header>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('header')`.
+ factory Element.header() => new Element.tag('header');
+
+ /// Creates a new `<hr>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('hr')`.
+ factory Element.hr() => new Element.tag('hr');
+
+ /// Creates a new `<iframe>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('iframe')`.
+ factory Element.iframe() => new Element.tag('iframe');
+
+ /// Creates a new `<img>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('img')`.
+ factory Element.img() => new Element.tag('img');
+
+ /// Creates a new `<li>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('li')`.
+ factory Element.li() => new Element.tag('li');
+
+ /// Creates a new `<nav>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('nav')`.
+ factory Element.nav() => new Element.tag('nav');
+
+ /// Creates a new `<ol>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('ol')`.
+ factory Element.ol() => new Element.tag('ol');
+
+ /// Creates a new `<option>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('option')`.
+ factory Element.option() => new Element.tag('option');
+
+ /// Creates a new `<p>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('p')`.
+ factory Element.p() => new Element.tag('p');
+
+ /// Creates a new `<pre>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('pre')`.
+ factory Element.pre() => new Element.tag('pre');
+
+ /// Creates a new `<section>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('section')`.
+ factory Element.section() => new Element.tag('section');
+
+ /// Creates a new `<select>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('select')`.
+ factory Element.select() => new Element.tag('select');
+
+ /// Creates a new `<span>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('span')`.
+ factory Element.span() => new Element.tag('span');
+
+ /// Creates a new `<svg>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('svg')`.
+ factory Element.svg() => new Element.tag('svg');
+
+ /// Creates a new `<table>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('table')`.
+ factory Element.table() => new Element.tag('table');
+
+ /// Creates a new `<td>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('td')`.
+ factory Element.td() => new Element.tag('td');
+
+ /// Creates a new `<textarea>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('textarea')`.
+ factory Element.textarea() => new Element.tag('textarea');
+
+ /// Creates a new `<th>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('th')`.
+ factory Element.th() => new Element.tag('th');
+
+ /// Creates a new `<tr>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('tr')`.
+ factory Element.tr() => new Element.tag('tr');
+
+ /// Creates a new `<ul>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('ul')`.
+ factory Element.ul() => new Element.tag('ul');
+
+ /// Creates a new `<video>` element.
+ ///
+ /// This is equivalent to calling `new Element.tag('video')`.
+ factory Element.video() => new Element.tag('video');
+
+ /**
+ * All attributes on this element.
+ *
+ * Any modifications to the attribute map will automatically be applied to
+ * this element.
+ *
+ * This only includes attributes which are not in a namespace
+ * (such as 'xlink:href'), additional attributes can be accessed via
+ * [getNamespacedAttributes].
+ */
+ Map<String, String> get attributes => new _ElementAttributeMap(this);
+
+ set attributes(Map<String, String> value) {
+ Map<String, String> attributes = this.attributes;
+ attributes.clear();
+ for (String key in value.keys) {
+ attributes[key] = value[key];
+ }
+ }
+
+ @pragma('dart2js:tryInline')
+ String getAttribute(String name) {
+ // Protect [name] against string conversion to "null" or "undefined".
+ assert(name != null, 'Attribute name cannot be null');
+ return _getAttribute(name);
+ }
+
+ @pragma('dart2js:tryInline')
+ String getAttributeNS(String namespaceURI, String name) {
+ // Protect [name] against string conversion to "null" or "undefined".
+ // [namespaceURI] does not need protecting, both `null` and `undefined` map to `null`.
+ assert(name != null, 'Attribute name cannot be null');
+ return _getAttributeNS(namespaceURI, name);
+ }
+
+ @pragma('dart2js:tryInline')
+ bool hasAttribute(String name) {
+ // Protect [name] against string conversion to "null" or "undefined".
+ assert(name != null, 'Attribute name cannot be null');
+ return _hasAttribute(name);
+ }
+
+ @pragma('dart2js:tryInline')
+ bool hasAttributeNS(String namespaceURI, String name) {
+ // Protect [name] against string conversion to "null" or "undefined".
+ // [namespaceURI] does not need protecting, both `null` and `undefined` map to `null`.
+ assert(name != null, 'Attribute name cannot be null');
+ return _hasAttributeNS(namespaceURI, name);
+ }
+
+ @pragma('dart2js:tryInline')
+ void removeAttribute(String name) {
+ // Protect [name] against string conversion to "null" or "undefined".
+ assert(name != null, 'Attribute name cannot be null');
+ _removeAttribute(name);
+ }
+
+ @pragma('dart2js:tryInline')
+ void removeAttributeNS(String namespaceURI, String name) {
+ // Protect [name] against string conversion to "null" or "undefined".
+ assert(name != null, 'Attribute name cannot be null');
+ _removeAttributeNS(namespaceURI, name);
+ }
+
+ @pragma('dart2js:tryInline')
+ void setAttribute(String name, String value) {
+ // Protect [name] against string conversion to "null" or "undefined".
+ assert(name != null, 'Attribute name cannot be null');
+ // TODO(sra): assert(value != null, 'Attribute value cannot be null.');
+ _setAttribute(name, value);
+ }
+
+ @pragma('dart2js:tryInline')
+ void setAttributeNS(String namespaceURI, String name, String value) {
+ // Protect [name] against string conversion to "null" or "undefined".
+ assert(name != null, 'Attribute name cannot be null');
+ // TODO(sra): assert(value != null, 'Attribute value cannot be null.');
+ _setAttributeNS(namespaceURI, name, value);
+ }
+
+ /**
+ * List of the direct children of this element.
+ *
+ * This collection can be used to add and remove elements from the document.
+ *
+ * var item = new DivElement();
+ * item.text = 'Something';
+ * document.body.children.add(item) // Item is now displayed on the page.
+ * for (var element in document.body.children) {
+ * element.style.background = 'red'; // Turns every child of body red.
+ * }
+ */
+ List<Element> get children => new _ChildrenElementList._wrap(this);
+
+ set children(List<Element> value) {
+ // Copy list first since we don't want liveness during iteration.
+ var copy = value.toList();
+ var children = this.children;
+ children.clear();
+ children.addAll(copy);
+ }
+
+ /**
+ * Finds all descendent elements of this element that match the specified
+ * group of selectors.
+ *
+ * [selectors] should be a string using CSS selector syntax.
+ *
+ * var items = element.querySelectorAll('.itemClassName');
+ *
+ * For details about CSS selector syntax, see the
+ * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+ */
+ ElementList<T> querySelectorAll<T extends Element>(String selectors) =>
+ new _FrozenElementList<T>._wrap(_querySelectorAll(selectors));
+
+ @JSName('setApplyScroll')
+ void _setApplyScroll(ScrollStateCallback scrollStateCallback,
+ String nativeScrollBehavior) native;
+
+ Future<ScrollState> setApplyScroll(String nativeScrollBehavior) {
+ var completer = new Completer<ScrollState>();
+ _setApplyScroll((value) {
+ completer.complete(value);
+ }, nativeScrollBehavior);
+ return completer.future;
+ }
+
+ @JSName('setDistributeScroll')
+ void _setDistributeScroll(ScrollStateCallback scrollStateCallback,
+ String nativeScrollBehavior) native;
+
+ Future<ScrollState> setDistributeScroll(String nativeScrollBehavior) {
+ var completer = new Completer<ScrollState>();
+ _setDistributeScroll((value) {
+ completer.complete(value);
+ }, nativeScrollBehavior);
+ return completer.future;
+ }
+
+ /**
+ * The set of CSS classes applied to this element.
+ *
+ * This set makes it easy to add, remove or toggle the classes applied to
+ * this element.
+ *
+ * element.classes.add('selected');
+ * element.classes.toggle('isOnline');
+ * element.classes.remove('selected');
+ */
+ CssClassSet get classes => new _ElementCssClassSet(this);
+
+ set classes(Iterable<String> value) {
+ // TODO(sra): Do this without reading the classes in clear() and addAll(),
+ // or writing the classes in clear().
+ CssClassSet classSet = classes;
+ classSet.clear();
+ classSet.addAll(value);
+ }
+
+ /**
+ * Allows access to all custom data attributes (data-*) set on this element.
+ *
+ * The keys for the map must follow these rules:
+ *
+ * * The name must not begin with 'xml'.
+ * * The name cannot contain a semi-colon (';').
+ * * The name cannot contain any capital letters.
+ *
+ * Any keys from markup will be converted to camel-cased keys in the map.
+ *
+ * For example, HTML specified as:
+ *
+ * <div data-my-random-value='value'></div>
+ *
+ * Would be accessed in Dart as:
+ *
+ * var value = element.dataset['myRandomValue'];
+ *
+ * See also:
+ *
+ * * [Custom data
+ * attributes](http://dev.w3.org/html5/spec-preview/global-attributes.html#custom-data-attribute)
+ */
+ Map<String, String> get dataset => new _DataAttributeMap(attributes);
+
+ set dataset(Map<String, String> value) {
+ final data = this.dataset;
+ data.clear();
+ for (String key in value.keys) {
+ data[key] = value[key];
+ }
+ }
+
+ /**
+ * Gets a map for manipulating the attributes of a particular namespace.
+ *
+ * This is primarily useful for SVG attributes such as xref:link.
+ */
+ Map<String, String> getNamespacedAttributes(String namespace) {
+ return new _NamespacedAttributeMap(this, namespace);
+ }
+
+ /**
+ * The set of all CSS values applied to this element, including inherited
+ * and default values.
+ *
+ * The computedStyle contains values that are inherited from other
+ * sources, such as parent elements or stylesheets. This differs from the
+ * [style] property, which contains only the values specified directly on this
+ * element.
+ *
+ * PseudoElement can be values such as `::after`, `::before`, `::marker`,
+ * `::line-marker`.
+ *
+ * See also:
+ *
+ * * [Cascade and Inheritance](https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Cascade_and_inheritance)
+ * from MDN.
+ * * [Pseudo-elements](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements)
+ * from MDN.
+ */
+ CssStyleDeclaration getComputedStyle([String pseudoElement]) {
+ if (pseudoElement == null) {
+ pseudoElement = '';
+ }
+ // TODO(jacobr): last param should be null, see b/5045788
+ return window._getComputedStyle(this, pseudoElement);
+ }
+
+ /**
+ * Gets the position of this element relative to the client area of the page.
+ */
+ Rectangle get client =>
+ new Rectangle(clientLeft, clientTop, clientWidth, clientHeight);
+
+ /**
+ * Gets the offset of this element relative to its offsetParent.
+ */
+ Rectangle get offset =>
+ new Rectangle(offsetLeft, offsetTop, offsetWidth, offsetHeight);
+
+ /**
+ * Adds the specified text after the last child of this element.
+ */
+ void appendText(String text) {
+ this.append(new Text(text));
+ }
+
+ /**
+ * Parses the specified text as HTML and adds the resulting node after the
+ * last child of this element.
+ */
+ void appendHtml(String text,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ this.insertAdjacentHtml('beforeend', text,
+ validator: validator, treeSanitizer: treeSanitizer);
+ }
+
+ /**
+ * Checks to see if the tag name is supported by the current platform.
+ *
+ * The tag should be a valid HTML tag name.
+ */
+ static bool isTagSupported(String tag) {
+ var e = _ElementFactoryProvider.createElement_tag(tag, null);
+ return e is Element && !(e is UnknownElement);
+ }
+
+ /**
+ * Called by the DOM when this element has been inserted into the live
+ * document.
+ *
+ * More information can be found in the
+ * [Custom Elements](http://w3c.github.io/webcomponents/spec/custom/#dfn-attached-callback)
+ * draft specification.
+ */
+ void attached() {
+ // For the deprecation period, call the old callback.
+ enteredView();
+ }
+
+ /**
+ * Called by the DOM when this element has been removed from the live
+ * document.
+ *
+ * More information can be found in the
+ * [Custom Elements](http://w3c.github.io/webcomponents/spec/custom/#dfn-detached-callback)
+ * draft specification.
+ */
+ void detached() {
+ // For the deprecation period, call the old callback.
+ leftView();
+ }
+
+ /** *Deprecated*: override [attached] instead. */
+ @deprecated
+ void enteredView() {}
+
+ List<Rectangle> getClientRects() {
+ var value = _getClientRects();
+
+ // If no prototype we need one for the world to hookup to the proper Dart class.
+ var jsProto = JS('', '#.prototype', value);
+ if (jsProto == null) {
+ JS('', '#.prototype = Object.create(null)', value);
+ }
+
+ applyExtension('DOMRectList', value);
+
+ return value;
+ }
+
+ /** *Deprecated*: override [detached] instead. */
+ @deprecated
+ void leftView() {}
+
+ /**
+ * Creates a new AnimationEffect object whose target element is the object
+ * on which the method is called, and calls the play() method of the
+ * AnimationTimeline object of the document timeline of the node document
+ * of the element, passing the newly created AnimationEffect as the argument
+ * to the method. Returns an Animation for the effect.
+ *
+ * Examples
+ *
+ * var animation = elem.animate([{"opacity": 75}, {"opacity": 0}], 200);
+ *
+ * var animation = elem.animate([
+ * {"transform": "translate(100px, -100%)"},
+ * {"transform" : "translate(400px, 500px)"}
+ * ], 1500);
+ *
+ * The [frames] parameter is an Iterable<Map>, where the
+ * map entries specify CSS animation effects. The
+ * [timing] paramter can be a double, representing the number of milliseconds
+ * for the transition, or a Map with fields corresponding to those
+ * of the [Timing] object.
+ **/
+ @SupportedBrowser(SupportedBrowser.CHROME, '36')
+ Animation animate(Iterable<Map<String, dynamic>> frames, [timing]) {
+ if (frames is! Iterable || !(frames.every((x) => x is Map))) {
+ throw new ArgumentError("The frames parameter should be a List of Maps "
+ "with frame information");
+ }
+ var convertedFrames;
+ if (frames is Iterable) {
+ convertedFrames = frames.map(convertDartToNative_Dictionary).toList();
+ } else {
+ convertedFrames = frames;
+ }
+ var convertedTiming =
+ timing is Map ? convertDartToNative_Dictionary(timing) : timing;
+ return convertedTiming == null
+ ? _animate(convertedFrames)
+ : _animate(convertedFrames, convertedTiming);
+ }
+
+ @JSName('animate')
+ Animation _animate(Object effect, [timing]) native;
+ /**
+ * Called by the DOM whenever an attribute on this has been changed.
+ */
+ void attributeChanged(String name, String oldValue, String newValue) {}
+
+ @Returns('String')
+ // Non-null for Elements.
+ String get localName => JS('String', '#', _localName);
+
+ /**
+ * A URI that identifies the XML namespace of this element.
+ *
+ * `null` if no namespace URI is specified.
+ *
+ * ## Other resources
+ *
+ * * [Node.namespaceURI](http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-NodeNSname)
+ * from W3C.
+ */
+ String get namespaceUri => _namespaceUri;
+
+ /**
+ * The string representation of this element.
+ *
+ * This is equivalent to reading the [localName] property.
+ */
+ String toString() => localName;
+
+ /**
+ * Scrolls this element into view.
+ *
+ * Only one of of the alignment options may be specified at a time.
+ *
+ * If no options are specified then this will attempt to scroll the minimum
+ * amount needed to bring the element into view.
+ *
+ * Note that alignCenter is currently only supported on WebKit platforms. If
+ * alignCenter is specified but not supported then this will fall back to
+ * alignTop.
+ *
+ * See also:
+ *
+ * * [scrollIntoView](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView)
+ * from MDN.
+ * * [scrollIntoViewIfNeeded](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoViewIfNeeded)
+ * from MDN.
+ */
+ void scrollIntoView([ScrollAlignment alignment]) {
+ var hasScrollIntoViewIfNeeded = true;
+ hasScrollIntoViewIfNeeded =
+ JS('bool', '!!(#.scrollIntoViewIfNeeded)', this);
+ if (alignment == ScrollAlignment.TOP) {
+ this._scrollIntoView(true);
+ } else if (alignment == ScrollAlignment.BOTTOM) {
+ this._scrollIntoView(false);
+ } else if (hasScrollIntoViewIfNeeded) {
+ if (alignment == ScrollAlignment.CENTER) {
+ this._scrollIntoViewIfNeeded(true);
+ } else {
+ this._scrollIntoViewIfNeeded();
+ }
+ } else {
+ this._scrollIntoView();
+ }
+ }
+
+ /**
+ * Static factory designed to expose `mousewheel` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<WheelEvent> mouseWheelEvent =
+ const _CustomEventStreamProvider<WheelEvent>(
+ Element._determineMouseWheelEventType);
+
+ static String _determineMouseWheelEventType(EventTarget e) => 'wheel';
+
+ /**
+ * Static factory designed to expose `transitionend` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<TransitionEvent> transitionEndEvent =
+ const _CustomEventStreamProvider<TransitionEvent>(
+ Element._determineTransitionEventType);
+
+ static String _determineTransitionEventType(EventTarget e) {
+ // Unfortunately the normal 'ontransitionend' style checks don't work here.
+ if (Device.isWebKit) {
+ return 'webkitTransitionEnd';
+ } else if (Device.isOpera) {
+ return 'oTransitionEnd';
+ }
+ return 'transitionend';
+ }
+
+ /**
+ * Inserts text into the DOM at the specified location.
+ *
+ * To see the possible values for [where], read the doc for
+ * [insertAdjacentHtml].
+ *
+ * See also:
+ *
+ * * [insertAdjacentHtml]
+ */
+ void insertAdjacentText(String where, String text) {
+ if (JS('bool', '!!#.insertAdjacentText', this)) {
+ _insertAdjacentText(where, text);
+ } else {
+ _insertAdjacentNode(where, new Text(text));
+ }
+ }
+
+ @JSName('insertAdjacentText')
+ void _insertAdjacentText(String where, String text) native;
+
+ /**
+ * Parses text as an HTML fragment and inserts it into the DOM at the
+ * specified location.
+ *
+ * The [where] parameter indicates where to insert the HTML fragment:
+ *
+ * * 'beforeBegin': Immediately before this element.
+ * * 'afterBegin': As the first child of this element.
+ * * 'beforeEnd': As the last child of this element.
+ * * 'afterEnd': Immediately after this element.
+ *
+ * var html = '<div class="something">content</div>';
+ * // Inserts as the first child
+ * document.body.insertAdjacentHtml('afterBegin', html);
+ * var createdElement = document.body.children[0];
+ * print(createdElement.classes[0]); // Prints 'something'
+ *
+ * See also:
+ *
+ * * [insertAdjacentText]
+ * * [insertAdjacentElement]
+ */
+ void insertAdjacentHtml(String where, String html,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ if (treeSanitizer is _TrustedHtmlTreeSanitizer) {
+ _insertAdjacentHtml(where, html);
+ } else {
+ _insertAdjacentNode(
+ where,
+ createFragment(html,
+ validator: validator, treeSanitizer: treeSanitizer));
+ }
+ }
+
+ @JSName('insertAdjacentHTML')
+ void _insertAdjacentHtml(String where, String text) native;
+
+ /**
+ * Inserts [element] into the DOM at the specified location.
+ *
+ * To see the possible values for [where], read the doc for
+ * [insertAdjacentHtml].
+ *
+ * See also:
+ *
+ * * [insertAdjacentHtml]
+ */
+ Element insertAdjacentElement(String where, Element element) {
+ if (JS('bool', '!!#.insertAdjacentElement', this)) {
+ _insertAdjacentElement(where, element);
+ } else {
+ _insertAdjacentNode(where, element);
+ }
+ return element;
+ }
+
+ @JSName('insertAdjacentElement')
+ void _insertAdjacentElement(String where, Element element) native;
+
+ void _insertAdjacentNode(String where, Node node) {
+ switch (where.toLowerCase()) {
+ case 'beforebegin':
+ this.parentNode.insertBefore(node, this);
+ break;
+ case 'afterbegin':
+ var first = this.nodes.length > 0 ? this.nodes[0] : null;
+ this.insertBefore(node, first);
+ break;
+ case 'beforeend':
+ this.append(node);
+ break;
+ case 'afterend':
+ this.parentNode.insertBefore(node, this.nextNode);
+ break;
+ default:
+ throw new ArgumentError("Invalid position ${where}");
+ }
+ }
+
+ /**
+ * Checks if this element matches the CSS selectors.
+ */
+ bool matches(String selectors) {
+ if (JS('bool', '!!#.matches', this)) {
+ return JS('bool', '#.matches(#)', this, selectors);
+ } else if (JS('bool', '!!#.webkitMatchesSelector', this)) {
+ return JS('bool', '#.webkitMatchesSelector(#)', this, selectors);
+ } else if (JS('bool', '!!#.mozMatchesSelector', this)) {
+ return JS('bool', '#.mozMatchesSelector(#)', this, selectors);
+ } else if (JS('bool', '!!#.msMatchesSelector', this)) {
+ return JS('bool', '#.msMatchesSelector(#)', this, selectors);
+ } else if (JS('bool', '!!#.oMatchesSelector', this)) {
+ return JS('bool', '#.oMatchesSelector(#)', this, selectors);
+ } else {
+ throw new UnsupportedError("Not supported on this platform");
+ }
+ }
+
+ /** Checks if this element or any of its parents match the CSS selectors. */
+ bool matchesWithAncestors(String selectors) {
+ var elem = this;
+ do {
+ if (elem.matches(selectors)) return true;
+ elem = elem.parent;
+ } while (elem != null);
+ return false;
+ }
+
+ /**
+ * Creates a new shadow root for this shadow host.
+ *
+ * ## Other resources
+ *
+ * * [Shadow DOM 101](http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/)
+ * from HTML5Rocks.
+ * * [Shadow DOM specification](http://www.w3.org/TR/shadow-dom/) from W3C.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME, '25')
+ ShadowRoot createShadowRoot() {
+ return JS(
+ 'ShadowRoot',
+ '(#.createShadowRoot || #.webkitCreateShadowRoot).call(#)',
+ this,
+ this,
+ this);
+ }
+
+ /**
+ * The shadow root of this shadow host.
+ *
+ * ## Other resources
+ *
+ * * [Shadow DOM 101](http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/)
+ * from HTML5Rocks.
+ * * [Shadow DOM specification](http://www.w3.org/TR/shadow-dom/)
+ * from W3C.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME, '25')
+ ShadowRoot get shadowRoot =>
+ JS('ShadowRoot|Null', '#.shadowRoot || #.webkitShadowRoot', this, this);
+
+ /**
+ * Access this element's content position.
+ *
+ * This returns a rectangle with the dimensions actually available for content
+ * in this element, in pixels, regardless of this element's box-sizing
+ * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+ * will return the same numerical height if the element is hidden or not.
+ *
+ * _Important_ _note_: use of this method _will_ perform CSS calculations that
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
+ * [Browser Reflow](https://developers.google.com/speed/articles/reflow)
+ */
+ CssRect get contentEdge => new _ContentCssRect(this);
+
+ /**
+ * Access the dimensions and position of this element's content + padding box.
+ *
+ * This returns a rectangle with the dimensions actually available for content
+ * in this element, in pixels, regardless of this element's box-sizing
+ * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+ * will return the same numerical height if the element is hidden or not. This
+ * can be used to retrieve jQuery's
+ * [innerHeight](http://api.jquery.com/innerHeight/) value for an element.
+ * This is also a rectangle equalling the dimensions of clientHeight and
+ * clientWidth.
+ *
+ * _Important_ _note_: use of this method _will_ perform CSS calculations that
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
+ * [Browser Reflow](https://developers.google.com/speed/articles/reflow)
+ */
+ CssRect get paddingEdge => new _PaddingCssRect(this);
+
+ /**
+ * Access the dimensions and position of this element's content + padding +
+ * border box.
+ *
+ * This returns a rectangle with the dimensions actually available for content
+ * in this element, in pixels, regardless of this element's box-sizing
+ * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+ * will return the same numerical height if the element is hidden or not. This
+ * can be used to retrieve jQuery's
+ * [outerHeight](http://api.jquery.com/outerHeight/) value for an element.
+ *
+ * _Important_ _note_: use of this method _will_ perform CSS calculations that
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
+ * [Browser Reflow](https://developers.google.com/speed/articles/reflow)
+ */
+ CssRect get borderEdge => new _BorderCssRect(this);
+
+ /**
+ * Access the dimensions and position of this element's content + padding +
+ * border + margin box.
+ *
+ * This returns a rectangle with the dimensions actually available for content
+ * in this element, in pixels, regardless of this element's box-sizing
+ * property. Unlike [getBoundingClientRect], the dimensions of this rectangle
+ * will return the same numerical height if the element is hidden or not. This
+ * can be used to retrieve jQuery's
+ * [outerHeight](http://api.jquery.com/outerHeight/) value for an element.
+ *
+ * _Important_ _note_: use of this method will perform CSS calculations that
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
+ * [Browser Reflow](https://developers.google.com/speed/articles/reflow)
+ */
+ CssRect get marginEdge => new _MarginCssRect(this);
+
+ /**
+ * Provides the coordinates of the element relative to the top of the
+ * document.
+ *
+ * This method is the Dart equivalent to jQuery's
+ * [offset](http://api.jquery.com/offset/) method.
+ */
+ Point get documentOffset => offsetTo(document.documentElement);
+
+ /**
+ * Provides the offset of this element's [borderEdge] relative to the
+ * specified [parent].
+ *
+ * This is the Dart equivalent of jQuery's
+ * [position](http://api.jquery.com/position/) method. Unlike jQuery's
+ * position, however, [parent] can be any parent element of `this`,
+ * rather than only `this`'s immediate [offsetParent]. If the specified
+ * element is _not_ an offset parent or transitive offset parent to this
+ * element, an [ArgumentError] is thrown.
+ */
+ Point offsetTo(Element parent) {
+ return Element._offsetToHelper(this, parent);
+ }
+
+ static Point _offsetToHelper(Element current, Element parent) {
+ // We're hopping from _offsetParent_ to offsetParent (not just parent), so
+ // offsetParent, "tops out" at BODY. But people could conceivably pass in
+ // the document.documentElement and I want it to return an absolute offset,
+ // so we have the special case checking for HTML.
+ bool sameAsParent = identical(current, parent);
+ bool foundAsParent = sameAsParent || parent.tagName == 'HTML';
+ if (current == null || sameAsParent) {
+ if (foundAsParent) return new Point(0, 0);
+ throw new ArgumentError("Specified element is not a transitive offset "
+ "parent of this element.");
+ }
+ Element parentOffset = current.offsetParent;
+ Point p = Element._offsetToHelper(parentOffset, parent);
+ return new Point(p.x + current.offsetLeft, p.y + current.offsetTop);
+ }
+
+ static HtmlDocument _parseDocument;
+ static Range _parseRange;
+ static NodeValidatorBuilder _defaultValidator;
+ static _ValidatingTreeSanitizer _defaultSanitizer;
+
+ /**
+ * Create a DocumentFragment from the HTML fragment and ensure that it follows
+ * the sanitization rules specified by the validator or treeSanitizer.
+ *
+ * If the default validation behavior is too restrictive then a new
+ * NodeValidator should be created, either extending or wrapping a default
+ * validator and overriding the validation APIs.
+ *
+ * The treeSanitizer is used to walk the generated node tree and sanitize it.
+ * A custom treeSanitizer can also be provided to perform special validation
+ * rules but since the API is more complex to implement this is discouraged.
+ *
+ * The returned tree is guaranteed to only contain nodes and attributes which
+ * are allowed by the provided validator.
+ *
+ * See also:
+ *
+ * * [NodeValidator]
+ * * [NodeTreeSanitizer]
+ */
+ DocumentFragment createFragment(String html,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ if (treeSanitizer == null) {
+ if (validator == null) {
+ if (_defaultValidator == null) {
+ _defaultValidator = new NodeValidatorBuilder.common();
+ }
+ validator = _defaultValidator;
+ }
+ if (_defaultSanitizer == null) {
+ _defaultSanitizer = new _ValidatingTreeSanitizer(validator);
+ } else {
+ _defaultSanitizer.validator = validator;
+ }
+ treeSanitizer = _defaultSanitizer;
+ } else if (validator != null) {
+ throw new ArgumentError(
+ 'validator can only be passed if treeSanitizer is null');
+ }
+
+ if (_parseDocument == null) {
+ _parseDocument = document.implementation.createHtmlDocument('');
+ _parseRange = _parseDocument.createRange();
+
+ // Workaround for Safari bug. Was also previously Chrome bug 229142
+ // - URIs are not resolved in new doc.
+ BaseElement base = _parseDocument.createElement('base');
+ base.href = document.baseUri;
+ _parseDocument.head.append(base);
+ }
+
+ // TODO(terry): Fixes Chromium 50 change no body after createHtmlDocument()
+ if (_parseDocument.body == null) {
+ _parseDocument.body = _parseDocument.createElement("body");
+ }
+
+ var contextElement;
+ if (this is BodyElement) {
+ contextElement = _parseDocument.body;
+ } else {
+ contextElement = _parseDocument.createElement(tagName);
+ _parseDocument.body.append(contextElement);
+ }
+ var fragment;
+ if (Range.supportsCreateContextualFragment &&
+ _canBeUsedToCreateContextualFragment) {
+ _parseRange.selectNodeContents(contextElement);
+ fragment = _parseRange.createContextualFragment(html);
+ } else {
+ contextElement._innerHtml = html;
+
+ fragment = _parseDocument.createDocumentFragment();
+ while (contextElement.firstChild != null) {
+ fragment.append(contextElement.firstChild);
+ }
+ }
+ if (contextElement != _parseDocument.body) {
+ contextElement.remove();
+ }
+
+ treeSanitizer.sanitizeTree(fragment);
+ // Copy the fragment over to the main document (fix for 14184)
+ document.adoptNode(fragment);
+
+ return fragment;
+ }
+
+ /** Test if createContextualFragment is supported for this element type */
+ bool get _canBeUsedToCreateContextualFragment =>
+ !_cannotBeUsedToCreateContextualFragment;
+
+ /** Test if createContextualFragment is NOT supported for this element type */
+ bool get _cannotBeUsedToCreateContextualFragment =>
+ _tagsForWhichCreateContextualFragmentIsNotSupported.contains(tagName);
+
+ /**
+ * A hard-coded list of the tag names for which createContextualFragment
+ * isn't supported.
+ */
+ static const _tagsForWhichCreateContextualFragmentIsNotSupported = const [
+ 'HEAD',
+ 'AREA',
+ 'BASE',
+ 'BASEFONT',
+ 'BR',
+ 'COL',
+ 'COLGROUP',
+ 'EMBED',
+ 'FRAME',
+ 'FRAMESET',
+ 'HR',
+ 'IMAGE',
+ 'IMG',
+ 'INPUT',
+ 'ISINDEX',
+ 'LINK',
+ 'META',
+ 'PARAM',
+ 'SOURCE',
+ 'STYLE',
+ 'TITLE',
+ 'WBR'
+ ];
+
+ /**
+ * Parses the HTML fragment and sets it as the contents of this element.
+ *
+ * This uses the default sanitization behavior to sanitize the HTML fragment,
+ * use [setInnerHtml] to override the default behavior.
+ */
+ set innerHtml(String html) {
+ this.setInnerHtml(html);
+ }
+
+ /**
+ * Parses the HTML fragment and sets it as the contents of this element.
+ * This ensures that the generated content follows the sanitization rules
+ * specified by the validator or treeSanitizer.
+ *
+ * If the default validation behavior is too restrictive then a new
+ * NodeValidator should be created, either extending or wrapping a default
+ * validator and overriding the validation APIs.
+ *
+ * The treeSanitizer is used to walk the generated node tree and sanitize it.
+ * A custom treeSanitizer can also be provided to perform special validation
+ * rules but since the API is more complex to implement this is discouraged.
+ *
+ * The resulting tree is guaranteed to only contain nodes and attributes which
+ * are allowed by the provided validator.
+ *
+ * See also:
+ *
+ * * [NodeValidator]
+ * * [NodeTreeSanitizer]
+ */
+ void setInnerHtml(String html,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ text = null;
+ if (treeSanitizer is _TrustedHtmlTreeSanitizer) {
+ _innerHtml = html;
+ } else {
+ append(createFragment(html,
+ validator: validator, treeSanitizer: treeSanitizer));
+ }
+ }
+
+ String get innerHtml => _innerHtml;
+
+ @JSName('innerText')
+ String innerText;
+
+ /**
+ * This is an ease-of-use accessor for event streams which should only be
+ * used when an explicit accessor is not available.
+ */
+ ElementEvents get on => new ElementEvents(this);
+
+ /**
+ * Verify if any of the attributes that we use in the sanitizer look unexpected,
+ * possibly indicating DOM clobbering attacks.
+ *
+ * Those attributes are: attributes, lastChild, children, previousNode and tagName.
+ */
+ static bool _hasCorruptedAttributes(Element element) {
+ return JS(
+ 'bool',
+ r'''
+ (function(element) {
+ if (!(element.attributes instanceof NamedNodeMap)) {
+ return true;
+ }
+ var childNodes = element.childNodes;
+ if (element.lastChild &&
+ element.lastChild !== childNodes[childNodes.length -1]) {
+ return true;
+ }
+ if (element.children) { // On Safari, children can apparently be null.
+ if (!((element.children instanceof HTMLCollection) ||
+ (element.children instanceof NodeList))) {
+ return true;
+ }
+ }
+ var length = 0;
+ if (element.children) {
+ length = element.children.length;
+ }
+ for (var i = 0; i < length; i++) {
+ var child = element.children[i];
+ // On IE it seems like we sometimes don't see the clobbered attribute,
+ // perhaps as a result of an over-optimization. Also use another route
+ // to check of attributes, children, or lastChild are clobbered. It may
+ // seem silly to check children as we rely on children to do this iteration,
+ // but it seems possible that the access to children might see the real thing,
+ // allowing us to check for clobbering that may show up in other accesses.
+ if (child["id"] == 'attributes' || child["name"] == 'attributes' ||
+ child["id"] == 'lastChild' || child["name"] == 'lastChild' ||
+ child["id"] == 'children' || child["name"] == 'children') {
+ return true;
+ }
+ }
+ return false;
+ })(#)''',
+ element);
+ }
+
+ /// A secondary check for corruption, needed on IE
+ static bool _hasCorruptedAttributesAdditionalCheck(Element element) {
+ return JS('bool', r'!(#.attributes instanceof NamedNodeMap)', element);
+ }
+
+ static String _safeTagName(element) {
+ String result = 'element tag unavailable';
+ try {
+ if (element.tagName is String) {
+ result = element.tagName;
+ }
+ } catch (e) {}
+ return result;
+ }
+
+ final Element offsetParent;
+
+ int get offsetHeight => JS<num>('num', '#.offsetHeight', this).round();
+
+ int get offsetLeft => JS<num>('num', '#.offsetLeft', this).round();
+
+ int get offsetTop => JS<num>('num', '#.offsetTop', this).round();
+
+ int get offsetWidth => JS<num>('num', '#.offsetWidth', this).round();
+
+ int get scrollHeight => JS<num>('num', '#.scrollHeight', this).round();
+ int get scrollLeft => JS<num>('num', '#.scrollLeft', this).round();
+
+ set scrollLeft(int value) {
+ JS("void", "#.scrollLeft = #", this, value.round());
+ }
+
+ int get scrollTop => JS<num>('num', '#.scrollTop', this).round();
+
+ set scrollTop(int value) {
+ JS("void", "#.scrollTop = #", this, value.round());
+ }
+
+ int get scrollWidth => JS<num>('num', '#.scrollWidth', this).round();
+
+ // To suppress missing implicit constructor warnings.
+ factory Element._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `abort` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> abortEvent =
+ const EventStreamProvider<Event>('abort');
+
+ /**
+ * Static factory designed to expose `beforecopy` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> beforeCopyEvent =
+ const EventStreamProvider<Event>('beforecopy');
+
+ /**
+ * Static factory designed to expose `beforecut` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> beforeCutEvent =
+ const EventStreamProvider<Event>('beforecut');
+
+ /**
+ * Static factory designed to expose `beforepaste` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> beforePasteEvent =
+ const EventStreamProvider<Event>('beforepaste');
+
+ /**
+ * Static factory designed to expose `blur` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> blurEvent =
+ const EventStreamProvider<Event>('blur');
+
+ static const EventStreamProvider<Event> canPlayEvent =
+ const EventStreamProvider<Event>('canplay');
+
+ static const EventStreamProvider<Event> canPlayThroughEvent =
+ const EventStreamProvider<Event>('canplaythrough');
+
+ /**
+ * Static factory designed to expose `change` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> changeEvent =
+ const EventStreamProvider<Event>('change');
+
+ /**
+ * Static factory designed to expose `click` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MouseEvent> clickEvent =
+ const EventStreamProvider<MouseEvent>('click');
+
+ /**
+ * Static factory designed to expose `contextmenu` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MouseEvent> contextMenuEvent =
+ const EventStreamProvider<MouseEvent>('contextmenu');
+
+ /**
+ * Static factory designed to expose `copy` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ClipboardEvent> copyEvent =
+ const EventStreamProvider<ClipboardEvent>('copy');
+
+ /**
+ * Static factory designed to expose `cut` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ClipboardEvent> cutEvent =
+ const EventStreamProvider<ClipboardEvent>('cut');
+
+ /**
+ * Static factory designed to expose `doubleclick` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ @DomName('Element.dblclickEvent')
+ static const EventStreamProvider<Event> doubleClickEvent =
+ const EventStreamProvider<Event>('dblclick');
+
+ /**
+ * A stream of `drag` events fired when an element is currently being dragged.
+ *
+ * A `drag` event is added to this stream as soon as the drag begins.
+ * A `drag` event is also added to this stream at intervals while the drag
+ * operation is still ongoing.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ static const EventStreamProvider<MouseEvent> dragEvent =
+ const EventStreamProvider<MouseEvent>('drag');
+
+ /**
+ * A stream of `dragend` events fired when an element completes a drag
+ * operation.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ static const EventStreamProvider<MouseEvent> dragEndEvent =
+ const EventStreamProvider<MouseEvent>('dragend');
+
+ /**
+ * A stream of `dragenter` events fired when a dragged object is first dragged
+ * over an element.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ static const EventStreamProvider<MouseEvent> dragEnterEvent =
+ const EventStreamProvider<MouseEvent>('dragenter');
+
+ /**
+ * A stream of `dragleave` events fired when an object being dragged over an
+ * element leaves the element's target area.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ static const EventStreamProvider<MouseEvent> dragLeaveEvent =
+ const EventStreamProvider<MouseEvent>('dragleave');
+
+ /**
+ * A stream of `dragover` events fired when a dragged object is currently
+ * being dragged over an element.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ static const EventStreamProvider<MouseEvent> dragOverEvent =
+ const EventStreamProvider<MouseEvent>('dragover');
+
+ /**
+ * A stream of `dragstart` events for a dragged element whose drag has begun.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ static const EventStreamProvider<MouseEvent> dragStartEvent =
+ const EventStreamProvider<MouseEvent>('dragstart');
+
+ /**
+ * A stream of `drop` events fired when a dragged object is dropped on an
+ * element.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ static const EventStreamProvider<MouseEvent> dropEvent =
+ const EventStreamProvider<MouseEvent>('drop');
+
+ static const EventStreamProvider<Event> durationChangeEvent =
+ const EventStreamProvider<Event>('durationchange');
+
+ static const EventStreamProvider<Event> emptiedEvent =
+ const EventStreamProvider<Event>('emptied');
+
+ static const EventStreamProvider<Event> endedEvent =
+ const EventStreamProvider<Event>('ended');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /**
+ * Static factory designed to expose `focus` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> focusEvent =
+ const EventStreamProvider<Event>('focus');
+
+ /**
+ * Static factory designed to expose `input` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> inputEvent =
+ const EventStreamProvider<Event>('input');
+
+ /**
+ * Static factory designed to expose `invalid` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> invalidEvent =
+ const EventStreamProvider<Event>('invalid');
+
+ /**
+ * Static factory designed to expose `keydown` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<KeyboardEvent> keyDownEvent =
+ const EventStreamProvider<KeyboardEvent>('keydown');
+
+ /**
+ * Static factory designed to expose `keypress` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<KeyboardEvent> keyPressEvent =
+ const EventStreamProvider<KeyboardEvent>('keypress');
+
+ /**
+ * Static factory designed to expose `keyup` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<KeyboardEvent> keyUpEvent =
+ const EventStreamProvider<KeyboardEvent>('keyup');
+
+ /**
+ * Static factory designed to expose `load` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> loadEvent =
+ const EventStreamProvider<Event>('load');
+
+ static const EventStreamProvider<Event> loadedDataEvent =
+ const EventStreamProvider<Event>('loadeddata');
+
+ static const EventStreamProvider<Event> loadedMetadataEvent =
+ const EventStreamProvider<Event>('loadedmetadata');
+
+ /**
+ * Static factory designed to expose `mousedown` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MouseEvent> mouseDownEvent =
+ const EventStreamProvider<MouseEvent>('mousedown');
+
+ /**
+ * Static factory designed to expose `mouseenter` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MouseEvent> mouseEnterEvent =
+ const EventStreamProvider<MouseEvent>('mouseenter');
+
+ /**
+ * Static factory designed to expose `mouseleave` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MouseEvent> mouseLeaveEvent =
+ const EventStreamProvider<MouseEvent>('mouseleave');
+
+ /**
+ * Static factory designed to expose `mousemove` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MouseEvent> mouseMoveEvent =
+ const EventStreamProvider<MouseEvent>('mousemove');
+
+ /**
+ * Static factory designed to expose `mouseout` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MouseEvent> mouseOutEvent =
+ const EventStreamProvider<MouseEvent>('mouseout');
+
+ /**
+ * Static factory designed to expose `mouseover` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MouseEvent> mouseOverEvent =
+ const EventStreamProvider<MouseEvent>('mouseover');
+
+ /**
+ * Static factory designed to expose `mouseup` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MouseEvent> mouseUpEvent =
+ const EventStreamProvider<MouseEvent>('mouseup');
+
+ /**
+ * Static factory designed to expose `paste` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ClipboardEvent> pasteEvent =
+ const EventStreamProvider<ClipboardEvent>('paste');
+
+ static const EventStreamProvider<Event> pauseEvent =
+ const EventStreamProvider<Event>('pause');
+
+ static const EventStreamProvider<Event> playEvent =
+ const EventStreamProvider<Event>('play');
+
+ static const EventStreamProvider<Event> playingEvent =
+ const EventStreamProvider<Event>('playing');
+
+ static const EventStreamProvider<Event> rateChangeEvent =
+ const EventStreamProvider<Event>('ratechange');
+
+ /**
+ * Static factory designed to expose `reset` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> resetEvent =
+ const EventStreamProvider<Event>('reset');
+
+ static const EventStreamProvider<Event> resizeEvent =
+ const EventStreamProvider<Event>('resize');
+
+ /**
+ * Static factory designed to expose `scroll` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> scrollEvent =
+ const EventStreamProvider<Event>('scroll');
+
+ /**
+ * Static factory designed to expose `search` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> searchEvent =
+ const EventStreamProvider<Event>('search');
+
+ static const EventStreamProvider<Event> seekedEvent =
+ const EventStreamProvider<Event>('seeked');
+
+ static const EventStreamProvider<Event> seekingEvent =
+ const EventStreamProvider<Event>('seeking');
+
+ /**
+ * Static factory designed to expose `select` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> selectEvent =
+ const EventStreamProvider<Event>('select');
+
+ /**
+ * Static factory designed to expose `selectstart` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> selectStartEvent =
+ const EventStreamProvider<Event>('selectstart');
+
+ static const EventStreamProvider<Event> stalledEvent =
+ const EventStreamProvider<Event>('stalled');
+
+ /**
+ * Static factory designed to expose `submit` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> submitEvent =
+ const EventStreamProvider<Event>('submit');
+
+ static const EventStreamProvider<Event> suspendEvent =
+ const EventStreamProvider<Event>('suspend');
+
+ static const EventStreamProvider<Event> timeUpdateEvent =
+ const EventStreamProvider<Event>('timeupdate');
+
+ /**
+ * Static factory designed to expose `touchcancel` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<TouchEvent> touchCancelEvent =
+ const EventStreamProvider<TouchEvent>('touchcancel');
+
+ /**
+ * Static factory designed to expose `touchend` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<TouchEvent> touchEndEvent =
+ const EventStreamProvider<TouchEvent>('touchend');
+
+ /**
+ * Static factory designed to expose `touchenter` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<TouchEvent> touchEnterEvent =
+ const EventStreamProvider<TouchEvent>('touchenter');
+
+ /**
+ * Static factory designed to expose `touchleave` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<TouchEvent> touchLeaveEvent =
+ const EventStreamProvider<TouchEvent>('touchleave');
+
+ /**
+ * Static factory designed to expose `touchmove` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<TouchEvent> touchMoveEvent =
+ const EventStreamProvider<TouchEvent>('touchmove');
+
+ /**
+ * Static factory designed to expose `touchstart` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<TouchEvent> touchStartEvent =
+ const EventStreamProvider<TouchEvent>('touchstart');
+
+ static const EventStreamProvider<Event> volumeChangeEvent =
+ const EventStreamProvider<Event>('volumechange');
+
+ static const EventStreamProvider<Event> waitingEvent =
+ const EventStreamProvider<Event>('waiting');
+
+ /**
+ * Static factory designed to expose `fullscreenchange` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ static const EventStreamProvider<Event> fullscreenChangeEvent =
+ const EventStreamProvider<Event>('webkitfullscreenchange');
+
+ /**
+ * Static factory designed to expose `fullscreenerror` events to event
+ * handlers that are not necessarily instances of [Element].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ static const EventStreamProvider<Event> fullscreenErrorEvent =
+ const EventStreamProvider<Event>('webkitfullscreenerror');
+
+ static const EventStreamProvider<WheelEvent> wheelEvent =
+ const EventStreamProvider<WheelEvent>('wheel');
+
+ String contentEditable;
+
+ String dir;
+
+ /**
+ * Indicates whether the element can be dragged and dropped.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ bool draggable;
+
+ /**
+ * Indicates whether the element is not relevant to the page's current state.
+ *
+ * ## Other resources
+ *
+ * * [Hidden attribute
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#the-hidden-attribute)
+ * from WHATWG.
+ */
+ bool hidden;
+
+ bool inert;
+
+ String inputMode;
+
+ // Using property as subclass shadows.
+ bool get isContentEditable => JS("bool", "#.isContentEditable", this);
+
+ String lang;
+
+ bool spellcheck;
+
+ final CssStyleDeclaration style;
+
+ int tabIndex;
+
+ String title;
+
+ /**
+ * Specifies whether this element's text content changes when the page is
+ * localized.
+ *
+ * ## Other resources
+ *
+ * * [The translate
+ * attribute](https://html.spec.whatwg.org/multipage/dom.html#the-translate-attribute)
+ * from WHATWG.
+ */
+ bool translate;
+
+ void blur() native;
+
+ void click() native;
+
+ void focus() native;
+
+ final AccessibleNode accessibleNode;
+
+ final SlotElement assignedSlot;
+
+ @JSName('attributes')
+ final _NamedNodeMap _attributes;
+
+ String className;
+
+ final int clientHeight;
+
+ final int clientLeft;
+
+ final int clientTop;
+
+ final int clientWidth;
+
+ final String computedName;
+
+ final String computedRole;
+
+ String id;
+
+ @JSName('innerHTML')
+ String _innerHtml;
+
+ @JSName('localName')
+ final String _localName;
+
+ @JSName('namespaceURI')
+ final String _namespaceUri;
+
+ // Using property as subclass shadows.
+ String get outerHtml => JS("String", "#.outerHTML", this);
+
+ @JSName('scrollHeight')
+ final int _scrollHeight;
+
+ @JSName('scrollLeft')
+ num _scrollLeft;
+
+ @JSName('scrollTop')
+ num _scrollTop;
+
+ @JSName('scrollWidth')
+ final int _scrollWidth;
+
+ String slot;
+
+ final StylePropertyMap styleMap;
+
+ final String tagName;
+
+ ShadowRoot attachShadow(Map shadowRootInitDict) {
+ var shadowRootInitDict_1 =
+ convertDartToNative_Dictionary(shadowRootInitDict);
+ return _attachShadow_1(shadowRootInitDict_1);
+ }
+
+ @JSName('attachShadow')
+ ShadowRoot _attachShadow_1(shadowRootInitDict) native;
+
+ Element closest(String selectors) native;
+
+ List<Animation> getAnimations() native;
+
+ @JSName('getAttribute')
+ String _getAttribute(String name) native;
+
+ @JSName('getAttributeNS')
+ String _getAttributeNS(String namespaceURI, String localName) native;
+
+ List<String> getAttributeNames() native;
+
+ /**
+ * Returns the smallest bounding rectangle that encompasses this element's
+ * padding, scrollbar, and border.
+ *
+ * ## Other resources
+ *
+ * * [Element.getBoundingClientRect](https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect)
+ * from MDN.
+ * * [The getBoundingClientRect()
+ * method](http://www.w3.org/TR/cssom-view/#the-getclientrects()-and-getboundingclientrect()-methods)
+ * from W3C.
+ */
+ @Creates('_DomRect')
+ @Returns('_DomRect|Null')
+ Rectangle getBoundingClientRect() native;
+
+ @JSName('getClientRects')
+ /**
+ * Returns a list of bounding rectangles for each box associated with this
+ * element.
+ *
+ * ## Other resources
+ *
+ * * [Element.getClientRects](https://developer.mozilla.org/en-US/docs/Web/API/Element.getClientRects)
+ * from MDN.
+ * * [The getClientRects()
+ * method](http://www.w3.org/TR/cssom-view/#the-getclientrects()-and-getboundingclientrect()-methods)
+ * from W3C.
+ */
+ @Creates('DomRectList')
+ @Returns('DomRectList|Null')
+ List<Rectangle> _getClientRects() native;
+
+ /**
+ * Returns a list of shadow DOM insertion points to which this element is
+ * distributed.
+ *
+ * ## Other resources
+ *
+ * * [Shadow DOM
+ * specification](https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html)
+ * from W3C.
+ */
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ List<Node> getDestinationInsertionPoints() native;
+
+ /**
+ * Returns a list of nodes with the given class name inside this element.
+ *
+ * ## Other resources
+ *
+ * * [getElementsByClassName](https://developer.mozilla.org/en-US/docs/Web/API/document.getElementsByClassName)
+ * from MDN.
+ * * [DOM specification](http://www.w3.org/TR/domcore/) from W3C.
+ */
+ @Creates('NodeList|HtmlCollection')
+ @Returns('NodeList|HtmlCollection')
+ List<Node> getElementsByClassName(String classNames) native;
+
+ @JSName('getElementsByTagName')
+ @Creates('NodeList|HtmlCollection')
+ @Returns('NodeList|HtmlCollection')
+ List<Node> _getElementsByTagName(String localName) native;
+
+ @JSName('hasAttribute')
+ bool _hasAttribute(String name) native;
+
+ @JSName('hasAttributeNS')
+ bool _hasAttributeNS(String namespaceURI, String localName) native;
+
+ bool hasPointerCapture(int pointerId) native;
+
+ void releasePointerCapture(int pointerId) native;
+
+ @JSName('removeAttribute')
+ void _removeAttribute(String name) native;
+
+ @JSName('removeAttributeNS')
+ void _removeAttributeNS(String namespaceURI, String localName) native;
+
+ void requestPointerLock() native;
+
+ void scroll([options_OR_x, num y]) {
+ if (options_OR_x == null && y == null) {
+ _scroll_1();
+ return;
+ }
+ if ((options_OR_x is Map) && y == null) {
+ var options_1 = convertDartToNative_Dictionary(options_OR_x);
+ _scroll_2(options_1);
+ return;
+ }
+ if (y != null && (options_OR_x is num)) {
+ _scroll_3(options_OR_x, y);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('scroll')
+ void _scroll_1() native;
+ @JSName('scroll')
+ void _scroll_2(options) native;
+ @JSName('scroll')
+ void _scroll_3(num x, y) native;
+
+ void scrollBy([options_OR_x, num y]) {
+ if (options_OR_x == null && y == null) {
+ _scrollBy_1();
+ return;
+ }
+ if ((options_OR_x is Map) && y == null) {
+ var options_1 = convertDartToNative_Dictionary(options_OR_x);
+ _scrollBy_2(options_1);
+ return;
+ }
+ if (y != null && (options_OR_x is num)) {
+ _scrollBy_3(options_OR_x, y);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('scrollBy')
+ void _scrollBy_1() native;
+ @JSName('scrollBy')
+ void _scrollBy_2(options) native;
+ @JSName('scrollBy')
+ void _scrollBy_3(num x, y) native;
+
+ @JSName('scrollIntoView')
+ void _scrollIntoView([Object arg]) native;
+
+ @JSName('scrollIntoViewIfNeeded')
+ void _scrollIntoViewIfNeeded([bool centerIfNeeded]) native;
+
+ void scrollTo([options_OR_x, num y]) {
+ if (options_OR_x == null && y == null) {
+ _scrollTo_1();
+ return;
+ }
+ if ((options_OR_x is Map) && y == null) {
+ var options_1 = convertDartToNative_Dictionary(options_OR_x);
+ _scrollTo_2(options_1);
+ return;
+ }
+ if (y != null && (options_OR_x is num)) {
+ _scrollTo_3(options_OR_x, y);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('scrollTo')
+ void _scrollTo_1() native;
+ @JSName('scrollTo')
+ void _scrollTo_2(options) native;
+ @JSName('scrollTo')
+ void _scrollTo_3(num x, y) native;
+
+ @JSName('setAttribute')
+ void _setAttribute(String name, String value) native;
+
+ @JSName('setAttributeNS')
+ void _setAttributeNS(String namespaceURI, String name, String value) native;
+
+ void setPointerCapture(int pointerId) native;
+
+ @JSName('webkitRequestFullscreen')
+ /**
+ * Displays this element fullscreen.
+ *
+ * ## Other resources
+ *
+ * * [Fullscreen
+ * API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API)
+ * from MDN.
+ * * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void requestFullscreen() native;
+
+ // From ChildNode
+
+ void after(Object nodes) native;
+
+ void before(Object nodes) native;
+
+ // From NonDocumentTypeChildNode
+
+ final Element nextElementSibling;
+
+ final Element previousElementSibling;
+
+ // From ParentNode
+
+ @JSName('childElementCount')
+ final int _childElementCount;
+
+ @JSName('children')
+ @Returns('HtmlCollection|Null')
+ @Creates('HtmlCollection')
+ final List<Node> _children;
+
+ @JSName('firstElementChild')
+ final Element _firstElementChild;
+
+ @JSName('lastElementChild')
+ final Element _lastElementChild;
+
+ /**
+ * Finds the first descendant element of this element that matches the
+ * specified group of selectors.
+ *
+ * [selectors] should be a string using CSS selector syntax.
+ *
+ * // Gets the first descendant with the class 'classname'
+ * var element = element.querySelector('.className');
+ * // Gets the element with id 'id'
+ * var element = element.querySelector('#id');
+ * // Gets the first descendant [ImageElement]
+ * var img = element.querySelector('img');
+ *
+ * For details about CSS selector syntax, see the
+ * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+ */
+ Element querySelector(String selectors) native;
+
+ @JSName('querySelectorAll')
+ @Creates('NodeList')
+ @Returns('NodeList')
+ List<Node> _querySelectorAll(String selectors) native;
+
+ /// Stream of `abort` events handled by this [Element].
+ ElementStream<Event> get onAbort => abortEvent.forElement(this);
+
+ /// Stream of `beforecopy` events handled by this [Element].
+ ElementStream<Event> get onBeforeCopy => beforeCopyEvent.forElement(this);
+
+ /// Stream of `beforecut` events handled by this [Element].
+ ElementStream<Event> get onBeforeCut => beforeCutEvent.forElement(this);
+
+ /// Stream of `beforepaste` events handled by this [Element].
+ ElementStream<Event> get onBeforePaste => beforePasteEvent.forElement(this);
+
+ /// Stream of `blur` events handled by this [Element].
+ ElementStream<Event> get onBlur => blurEvent.forElement(this);
+
+ ElementStream<Event> get onCanPlay => canPlayEvent.forElement(this);
+
+ ElementStream<Event> get onCanPlayThrough =>
+ canPlayThroughEvent.forElement(this);
+
+ /// Stream of `change` events handled by this [Element].
+ ElementStream<Event> get onChange => changeEvent.forElement(this);
+
+ /// Stream of `click` events handled by this [Element].
+ ElementStream<MouseEvent> get onClick => clickEvent.forElement(this);
+
+ /// Stream of `contextmenu` events handled by this [Element].
+ ElementStream<MouseEvent> get onContextMenu =>
+ contextMenuEvent.forElement(this);
+
+ /// Stream of `copy` events handled by this [Element].
+ ElementStream<ClipboardEvent> get onCopy => copyEvent.forElement(this);
+
+ /// Stream of `cut` events handled by this [Element].
+ ElementStream<ClipboardEvent> get onCut => cutEvent.forElement(this);
+
+ /// Stream of `doubleclick` events handled by this [Element].
+ @DomName('Element.ondblclick')
+ ElementStream<Event> get onDoubleClick => doubleClickEvent.forElement(this);
+
+ /**
+ * A stream of `drag` events fired when this element currently being dragged.
+ *
+ * A `drag` event is added to this stream as soon as the drag begins.
+ * A `drag` event is also added to this stream at intervals while the drag
+ * operation is still ongoing.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDrag => dragEvent.forElement(this);
+
+ /**
+ * A stream of `dragend` events fired when this element completes a drag
+ * operation.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragEnd => dragEndEvent.forElement(this);
+
+ /**
+ * A stream of `dragenter` events fired when a dragged object is first dragged
+ * over this element.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragEnter => dragEnterEvent.forElement(this);
+
+ /**
+ * A stream of `dragleave` events fired when an object being dragged over this
+ * element leaves this element's target area.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragLeave => dragLeaveEvent.forElement(this);
+
+ /**
+ * A stream of `dragover` events fired when a dragged object is currently
+ * being dragged over this element.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragOver => dragOverEvent.forElement(this);
+
+ /**
+ * A stream of `dragstart` events fired when this element starts being
+ * dragged.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDragStart => dragStartEvent.forElement(this);
+
+ /**
+ * A stream of `drop` events fired when a dragged object is dropped on this
+ * element.
+ *
+ * ## Other resources
+ *
+ * * [Drag and drop
+ * sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/dnd/basics)
+ * based on [the tutorial](http://www.html5rocks.com/en/tutorials/dnd/basics/)
+ * from HTML5Rocks.
+ * * [Drag and drop
+ * specification](https://html.spec.whatwg.org/multipage/interaction.html#dnd)
+ * from WHATWG.
+ */
+ ElementStream<MouseEvent> get onDrop => dropEvent.forElement(this);
+
+ ElementStream<Event> get onDurationChange =>
+ durationChangeEvent.forElement(this);
+
+ ElementStream<Event> get onEmptied => emptiedEvent.forElement(this);
+
+ ElementStream<Event> get onEnded => endedEvent.forElement(this);
+
+ /// Stream of `error` events handled by this [Element].
+ ElementStream<Event> get onError => errorEvent.forElement(this);
+
+ /// Stream of `focus` events handled by this [Element].
+ ElementStream<Event> get onFocus => focusEvent.forElement(this);
+
+ /// Stream of `input` events handled by this [Element].
+ ElementStream<Event> get onInput => inputEvent.forElement(this);
+
+ /// Stream of `invalid` events handled by this [Element].
+ ElementStream<Event> get onInvalid => invalidEvent.forElement(this);
+
+ /// Stream of `keydown` events handled by this [Element].
+ ElementStream<KeyboardEvent> get onKeyDown => keyDownEvent.forElement(this);
+
+ /// Stream of `keypress` events handled by this [Element].
+ ElementStream<KeyboardEvent> get onKeyPress => keyPressEvent.forElement(this);
+
+ /// Stream of `keyup` events handled by this [Element].
+ ElementStream<KeyboardEvent> get onKeyUp => keyUpEvent.forElement(this);
+
+ /// Stream of `load` events handled by this [Element].
+ ElementStream<Event> get onLoad => loadEvent.forElement(this);
+
+ ElementStream<Event> get onLoadedData => loadedDataEvent.forElement(this);
+
+ ElementStream<Event> get onLoadedMetadata =>
+ loadedMetadataEvent.forElement(this);
+
+ /// Stream of `mousedown` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseDown => mouseDownEvent.forElement(this);
+
+ /// Stream of `mouseenter` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseEnter =>
+ mouseEnterEvent.forElement(this);
+
+ /// Stream of `mouseleave` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseLeave =>
+ mouseLeaveEvent.forElement(this);
+
+ /// Stream of `mousemove` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseMove => mouseMoveEvent.forElement(this);
+
+ /// Stream of `mouseout` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseOut => mouseOutEvent.forElement(this);
+
+ /// Stream of `mouseover` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseOver => mouseOverEvent.forElement(this);
+
+ /// Stream of `mouseup` events handled by this [Element].
+ ElementStream<MouseEvent> get onMouseUp => mouseUpEvent.forElement(this);
+
+ /// Stream of `mousewheel` events handled by this [Element].
+ ElementStream<WheelEvent> get onMouseWheel =>
+ mouseWheelEvent.forElement(this);
+
+ /// Stream of `paste` events handled by this [Element].
+ ElementStream<ClipboardEvent> get onPaste => pasteEvent.forElement(this);
+
+ ElementStream<Event> get onPause => pauseEvent.forElement(this);
+
+ ElementStream<Event> get onPlay => playEvent.forElement(this);
+
+ ElementStream<Event> get onPlaying => playingEvent.forElement(this);
+
+ ElementStream<Event> get onRateChange => rateChangeEvent.forElement(this);
+
+ /// Stream of `reset` events handled by this [Element].
+ ElementStream<Event> get onReset => resetEvent.forElement(this);
+
+ ElementStream<Event> get onResize => resizeEvent.forElement(this);
+
+ /// Stream of `scroll` events handled by this [Element].
+ ElementStream<Event> get onScroll => scrollEvent.forElement(this);
+
+ /// Stream of `search` events handled by this [Element].
+ ElementStream<Event> get onSearch => searchEvent.forElement(this);
+
+ ElementStream<Event> get onSeeked => seekedEvent.forElement(this);
+
+ ElementStream<Event> get onSeeking => seekingEvent.forElement(this);
+
+ /// Stream of `select` events handled by this [Element].
+ ElementStream<Event> get onSelect => selectEvent.forElement(this);
+
+ /// Stream of `selectstart` events handled by this [Element].
+ ElementStream<Event> get onSelectStart => selectStartEvent.forElement(this);
+
+ ElementStream<Event> get onStalled => stalledEvent.forElement(this);
+
+ /// Stream of `submit` events handled by this [Element].
+ ElementStream<Event> get onSubmit => submitEvent.forElement(this);
+
+ ElementStream<Event> get onSuspend => suspendEvent.forElement(this);
+
+ ElementStream<Event> get onTimeUpdate => timeUpdateEvent.forElement(this);
+
+ /// Stream of `touchcancel` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchCancel =>
+ touchCancelEvent.forElement(this);
+
+ /// Stream of `touchend` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchEnd => touchEndEvent.forElement(this);
+
+ /// Stream of `touchenter` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchEnter =>
+ touchEnterEvent.forElement(this);
+
+ /// Stream of `touchleave` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchLeave =>
+ touchLeaveEvent.forElement(this);
+
+ /// Stream of `touchmove` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchMove => touchMoveEvent.forElement(this);
+
+ /// Stream of `touchstart` events handled by this [Element].
+ ElementStream<TouchEvent> get onTouchStart =>
+ touchStartEvent.forElement(this);
+
+ /// Stream of `transitionend` events handled by this [Element].
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ ElementStream<TransitionEvent> get onTransitionEnd =>
+ transitionEndEvent.forElement(this);
+
+ ElementStream<Event> get onVolumeChange => volumeChangeEvent.forElement(this);
+
+ ElementStream<Event> get onWaiting => waitingEvent.forElement(this);
+
+ /// Stream of `fullscreenchange` events handled by this [Element].
+ ElementStream<Event> get onFullscreenChange =>
+ fullscreenChangeEvent.forElement(this);
+
+ /// Stream of `fullscreenerror` events handled by this [Element].
+ ElementStream<Event> get onFullscreenError =>
+ fullscreenErrorEvent.forElement(this);
+
+ ElementStream<WheelEvent> get onWheel => wheelEvent.forElement(this);
+}
+
+class _ElementFactoryProvider {
+ // Optimization to improve performance until the dart2js compiler inlines this
+ // method.
+ static dynamic createElement_tag(String tag, String typeExtension) {
+ // Firefox may return a JS function for some types (Embed, Object).
+ if (typeExtension != null) {
+ return JS('Element|=Object', 'document.createElement(#, #)', tag,
+ typeExtension);
+ }
+ // Should be able to eliminate this and just call the two-arg version above
+ // with null typeExtension, but Chrome treats the tag as case-sensitive if
+ // typeExtension is null.
+ // https://code.google.com/p/chromium/issues/detail?id=282467
+ return JS('Element|=Object', 'document.createElement(#)', tag);
+ }
+}
+
+/**
+ * Options for Element.scrollIntoView.
+ */
+class ScrollAlignment {
+ final _value;
+ const ScrollAlignment._internal(this._value);
+ toString() => 'ScrollAlignment.$_value';
+
+ /// Attempt to align the element to the top of the scrollable area.
+ static const TOP = const ScrollAlignment._internal('TOP');
+
+ /// Attempt to center the element in the scrollable area.
+ static const CENTER = const ScrollAlignment._internal('CENTER');
+
+ /// Attempt to align the element to the bottom of the scrollable area.
+ static const BOTTOM = const ScrollAlignment._internal('BOTTOM');
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.IE)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("HTMLEmbedElement")
+class EmbedElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory EmbedElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory EmbedElement() => document.createElement("embed");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ EmbedElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Element.isTagSupported('embed');
+
+ String height;
+
+ String name;
+
+ String src;
+
+ String type;
+
+ String width;
+
+ Node __getter__(String name) native;
+
+ void __setter__(String name, Node value) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _EntriesCallback(List entries);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Entry")
+class Entry extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Entry._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final FileSystem filesystem;
+
+ final String fullPath;
+
+ final bool isDirectory;
+
+ final bool isFile;
+
+ final String name;
+
+ @JSName('copyTo')
+ void _copyTo(DirectoryEntry parent,
+ [String name,
+ _EntryCallback successCallback,
+ _ErrorCallback errorCallback]) native;
+
+ @JSName('copyTo')
+ Future<Entry> copyTo(DirectoryEntry parent, {String name}) {
+ var completer = new Completer<Entry>();
+ _copyTo(parent, name, (value) {
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ @JSName('getMetadata')
+ void _getMetadata(MetadataCallback successCallback,
+ [_ErrorCallback errorCallback]) native;
+
+ @JSName('getMetadata')
+ Future<Metadata> getMetadata() {
+ var completer = new Completer<Metadata>();
+ _getMetadata((value) {
+ applyExtension('Metadata', value);
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ @JSName('getParent')
+ void _getParent(
+ [_EntryCallback successCallback, _ErrorCallback errorCallback]) native;
+
+ @JSName('getParent')
+ Future<Entry> getParent() {
+ var completer = new Completer<Entry>();
+ _getParent((value) {
+ applyExtension('Entry', value);
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ @JSName('moveTo')
+ void _moveTo(DirectoryEntry parent,
+ [String name,
+ _EntryCallback successCallback,
+ _ErrorCallback errorCallback]) native;
+
+ @JSName('moveTo')
+ Future<Entry> moveTo(DirectoryEntry parent, {String name}) {
+ var completer = new Completer<Entry>();
+ _moveTo(parent, name, (value) {
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ @JSName('remove')
+ void _remove(VoidCallback successCallback, [_ErrorCallback errorCallback])
+ native;
+
+ @JSName('remove')
+ Future remove() {
+ var completer = new Completer();
+ _remove(() {
+ completer.complete();
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ @JSName('toURL')
+ String toUrl() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _EntryCallback(Entry entry);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _ErrorCallback(DomException error);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("ErrorEvent")
+class ErrorEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory ErrorEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ErrorEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return ErrorEvent._create_1(type, eventInitDict_1);
+ }
+ return ErrorEvent._create_2(type);
+ }
+ static ErrorEvent _create_1(type, eventInitDict) =>
+ JS('ErrorEvent', 'new ErrorEvent(#,#)', type, eventInitDict);
+ static ErrorEvent _create_2(type) =>
+ JS('ErrorEvent', 'new ErrorEvent(#)', type);
+
+ final int colno;
+
+ @Creates('Null')
+ final Object error;
+
+ final String filename;
+
+ final int lineno;
+
+ final String message;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("Event,InputEvent")
+class Event extends Interceptor {
+ // In JS, canBubble and cancelable are technically required parameters to
+ // init*Event. In practice, though, if they aren't provided they simply
+ // default to false (since that's Boolean(undefined)).
+ //
+ // Contrary to JS, we default canBubble and cancelable to true, since that's
+ // what people want most of the time anyway.
+ factory Event(String type, {bool canBubble: true, bool cancelable: true}) {
+ return new Event.eventType('Event', type,
+ canBubble: canBubble, cancelable: cancelable);
+ }
+
+ /**
+ * Creates a new Event object of the specified type.
+ *
+ * This is analogous to document.createEvent.
+ * Normally events should be created via their constructors, if available.
+ *
+ * var e = new Event.type('MouseEvent', 'mousedown', true, true);
+ */
+ factory Event.eventType(String type, String name,
+ {bool canBubble: true, bool cancelable: true}) {
+ final Event e = document._createEvent(type);
+ e._initEvent(name, canBubble, cancelable);
+ return e;
+ }
+
+ /** The CSS selector involved with event delegation. */
+ String _selector;
+
+ /**
+ * A pointer to the element whose CSS selector matched within which an event
+ * was fired. If this Event was not associated with any Event delegation,
+ * accessing this value will throw an [UnsupportedError].
+ */
+ Element get matchingTarget {
+ if (_selector == null) {
+ throw new UnsupportedError('Cannot call matchingTarget if this Event did'
+ ' not arise as a result of event delegation.');
+ }
+ Element currentTarget = this.currentTarget;
+ Element target = this.target;
+ var matchedTarget;
+ do {
+ if (target.matches(_selector)) return target;
+ target = target.parent;
+ } while (target != null && target != currentTarget.parent);
+ throw new StateError('No selector matched for populating matchedTarget.');
+ }
+
+ List<EventTarget> get path =>
+ JS('bool', '!!#.composedPath', this) ? composedPath() : [];
+
+ factory Event._(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return Event._create_1(type, eventInitDict_1);
+ }
+ return Event._create_2(type);
+ }
+ static Event _create_1(type, eventInitDict) =>
+ JS('Event', 'new Event(#,#)', type, eventInitDict);
+ static Event _create_2(type) => JS('Event', 'new Event(#)', type);
+
+ /**
+ * This event is being handled by the event target.
+ *
+ * ## Other resources
+ *
+ * * [Target phase](http://www.w3.org/TR/DOM-Level-3-Events/#target-phase)
+ * from W3C.
+ */
+ static const int AT_TARGET = 2;
+
+ /**
+ * This event is bubbling up through the target's ancestors.
+ *
+ * ## Other resources
+ *
+ * * [Bubble phase](http://www.w3.org/TR/DOM-Level-3-Events/#bubble-phase)
+ * from W3C.
+ */
+ static const int BUBBLING_PHASE = 3;
+
+ /**
+ * This event is propagating through the target's ancestors, starting from the
+ * document.
+ *
+ * ## Other resources
+ *
+ * * [Bubble phase](http://www.w3.org/TR/DOM-Level-3-Events/#bubble-phase)
+ * from W3C.
+ */
+ static const int CAPTURING_PHASE = 1;
+
+ final bool bubbles;
+
+ final bool cancelable;
+
+ final bool composed;
+
+ EventTarget get currentTarget =>
+ _convertNativeToDart_EventTarget(this._get_currentTarget);
+ @JSName('currentTarget')
+ @Creates('Null')
+ @Returns('EventTarget|=Object|Null')
+ final dynamic _get_currentTarget;
+
+ final bool defaultPrevented;
+
+ final int eventPhase;
+
+ final bool isTrusted;
+
+ EventTarget get target => _convertNativeToDart_EventTarget(this._get_target);
+ @JSName('target')
+ @Creates('Node')
+ @Returns('EventTarget|=Object')
+ final dynamic _get_target;
+
+ final num timeStamp;
+
+ final String type;
+
+ List<EventTarget> composedPath() native;
+
+ @JSName('initEvent')
+ void _initEvent(String type, [bool bubbles, bool cancelable]) native;
+
+ void preventDefault() native;
+
+ void stopImmediatePropagation() native;
+
+ void stopPropagation() native;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EventSource")
+class EventSource extends EventTarget {
+ factory EventSource(String url, {withCredentials: false}) {
+ var parsedOptions = {
+ 'withCredentials': withCredentials,
+ };
+ return EventSource._factoryEventSource(url, parsedOptions);
+ }
+ // To suppress missing implicit constructor warnings.
+ factory EventSource._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [EventSource].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /**
+ * Static factory designed to expose `message` events to event
+ * handlers that are not necessarily instances of [EventSource].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ /**
+ * Static factory designed to expose `open` events to event
+ * handlers that are not necessarily instances of [EventSource].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> openEvent =
+ const EventStreamProvider<Event>('open');
+
+ static EventSource _factoryEventSource(String url,
+ [Map eventSourceInitDict]) {
+ if (eventSourceInitDict != null) {
+ var eventSourceInitDict_1 =
+ convertDartToNative_Dictionary(eventSourceInitDict);
+ return EventSource._create_1(url, eventSourceInitDict_1);
+ }
+ return EventSource._create_2(url);
+ }
+
+ static EventSource _create_1(url, eventSourceInitDict) =>
+ JS('EventSource', 'new EventSource(#,#)', url, eventSourceInitDict);
+ static EventSource _create_2(url) =>
+ JS('EventSource', 'new EventSource(#)', url);
+
+ static const int CLOSED = 2;
+
+ static const int CONNECTING = 0;
+
+ static const int OPEN = 1;
+
+ final int readyState;
+
+ final String url;
+
+ final bool withCredentials;
+
+ void close() native;
+
+ /// Stream of `error` events handled by this [EventSource].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `message` events handled by this [EventSource].
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+ /// Stream of `open` events handled by this [EventSource].
+ Stream<Event> get onOpen => openEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Base class that supports listening for and dispatching browser events.
+ *
+ * Normally events are accessed via the Stream getter:
+ *
+ * element.onMouseOver.listen((e) => print('Mouse over!'));
+ *
+ * To access bubbling events which are declared on one element, but may bubble
+ * up to another element type (common for MediaElement events):
+ *
+ * MediaElement.pauseEvent.forTarget(document.body).listen(...);
+ *
+ * To useCapture on events:
+ *
+ * Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
+ *
+ * Custom events can be declared as:
+ *
+ * class DataGenerator {
+ * static EventStreamProvider<Event> dataEvent =
+ * new EventStreamProvider('data');
+ * }
+ *
+ * Then listeners should access the event with:
+ *
+ * DataGenerator.dataEvent.forTarget(element).listen(...);
+ *
+ * Custom events can also be accessed as:
+ *
+ * element.on['some_event'].listen(...);
+ *
+ * This approach is generally discouraged as it loses the event typing and
+ * some DOM events may have multiple platform-dependent event names under the
+ * covers. By using the standard Stream getters you will get the platform
+ * specific event name automatically.
+ */
+class Events {
+ /* Raw event target. */
+ final EventTarget _ptr;
+
+ Events(this._ptr);
+
+ Stream<Event> operator [](String type) {
+ return new _EventStream(_ptr, type, false);
+ }
+}
+
+class ElementEvents extends Events {
+ static final webkitEvents = {
+ 'animationend': 'webkitAnimationEnd',
+ 'animationiteration': 'webkitAnimationIteration',
+ 'animationstart': 'webkitAnimationStart',
+ 'fullscreenchange': 'webkitfullscreenchange',
+ 'fullscreenerror': 'webkitfullscreenerror',
+ 'keyadded': 'webkitkeyadded',
+ 'keyerror': 'webkitkeyerror',
+ 'keymessage': 'webkitkeymessage',
+ 'needkey': 'webkitneedkey',
+ 'pointerlockchange': 'webkitpointerlockchange',
+ 'pointerlockerror': 'webkitpointerlockerror',
+ 'resourcetimingbufferfull': 'webkitresourcetimingbufferfull',
+ 'transitionend': 'webkitTransitionEnd',
+ 'speechchange': 'webkitSpeechChange'
+ };
+
+ ElementEvents(Element ptr) : super(ptr);
+
+ Stream<Event> operator [](String type) {
+ if (webkitEvents.keys.contains(type.toLowerCase())) {
+ if (Device.isWebKit) {
+ return new _ElementEventStreamImpl(
+ _ptr, webkitEvents[type.toLowerCase()], false);
+ }
+ }
+ return new _ElementEventStreamImpl(_ptr, type, false);
+ }
+}
+
+/**
+ * Base class for all browser objects that support events.
+ *
+ * Use the [on] property to add, and remove events
+ * for compile-time type checks and a more concise API.
+ */
+@Native("EventTarget")
+class EventTarget extends Interceptor {
+ // Custom element created callback.
+ EventTarget._created();
+
+ /**
+ * This is an ease-of-use accessor for event streams which should only be
+ * used when an explicit accessor is not available.
+ */
+ Events get on => new Events(this);
+
+ void addEventListener(String type, EventListener listener,
+ [bool useCapture]) {
+ // TODO(leafp): This check is avoid a bug in our dispatch code when
+ // listener is null. The browser treats this call as a no-op in this
+ // case, so it's fine to short-circuit it, but we should not have to.
+ if (listener != null) {
+ _addEventListener(type, listener, useCapture);
+ }
+ }
+
+ void removeEventListener(String type, EventListener listener,
+ [bool useCapture]) {
+ // TODO(leafp): This check is avoid a bug in our dispatch code when
+ // listener is null. The browser treats this call as a no-op in this
+ // case, so it's fine to short-circuit it, but we should not have to.
+ if (listener != null) {
+ _removeEventListener(type, listener, useCapture);
+ }
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory EventTarget._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('addEventListener')
+ void _addEventListener(String type, EventListener listener, [bool options])
+ native;
+
+ bool dispatchEvent(Event event) native;
+
+ @JSName('removeEventListener')
+ void _removeEventListener(String type, EventListener listener, [bool options])
+ native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ExtendableEvent")
+class ExtendableEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory ExtendableEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ExtendableEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return ExtendableEvent._create_1(type, eventInitDict_1);
+ }
+ return ExtendableEvent._create_2(type);
+ }
+ static ExtendableEvent _create_1(type, eventInitDict) =>
+ JS('ExtendableEvent', 'new ExtendableEvent(#,#)', type, eventInitDict);
+ static ExtendableEvent _create_2(type) =>
+ JS('ExtendableEvent', 'new ExtendableEvent(#)', type);
+
+ void waitUntil(Future f) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ExtendableMessageEvent")
+class ExtendableMessageEvent extends ExtendableEvent {
+ // To suppress missing implicit constructor warnings.
+ factory ExtendableMessageEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @annotation_Creates_SerializedScriptValue
+ @annotation_Returns_SerializedScriptValue
+ final Object data;
+
+ final String lastEventId;
+
+ final String origin;
+
+ final List<MessagePort> ports;
+
+ @Creates('Client|ServiceWorker|MessagePort')
+ @Returns('Client|ServiceWorker|MessagePort|Null')
+ final Object source;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("External")
+class External extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory External._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void AddSearchProvider() native;
+
+ void IsSearchProviderInstalled() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FaceDetector")
+class FaceDetector extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory FaceDetector._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FaceDetector([Map faceDetectorOptions]) {
+ if (faceDetectorOptions != null) {
+ var faceDetectorOptions_1 =
+ convertDartToNative_Dictionary(faceDetectorOptions);
+ return FaceDetector._create_1(faceDetectorOptions_1);
+ }
+ return FaceDetector._create_2();
+ }
+ static FaceDetector _create_1(faceDetectorOptions) =>
+ JS('FaceDetector', 'new FaceDetector(#)', faceDetectorOptions);
+ static FaceDetector _create_2() => JS('FaceDetector', 'new FaceDetector()');
+
+ Future<List<DetectedFace>> detect(/*ImageBitmapSource*/ image) =>
+ promiseToFuture<List<DetectedFace>>(JS("", "#.detect(#)", this, image));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FederatedCredential")
+class FederatedCredential extends Credential implements CredentialUserData {
+ // To suppress missing implicit constructor warnings.
+ factory FederatedCredential._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FederatedCredential(Map data) {
+ var data_1 = convertDartToNative_Dictionary(data);
+ return FederatedCredential._create_1(data_1);
+ }
+ static FederatedCredential _create_1(data) =>
+ JS('FederatedCredential', 'new FederatedCredential(#)', data);
+
+ final String protocol;
+
+ final String provider;
+
+ // From CredentialUserData
+
+ @JSName('iconURL')
+ final String iconUrl;
+
+ final String name;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FetchEvent")
+class FetchEvent extends ExtendableEvent {
+ // To suppress missing implicit constructor warnings.
+ factory FetchEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FetchEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return FetchEvent._create_1(type, eventInitDict_1);
+ }
+ static FetchEvent _create_1(type, eventInitDict) =>
+ JS('FetchEvent', 'new FetchEvent(#,#)', type, eventInitDict);
+
+ final String clientId;
+
+ final bool isReload;
+
+ Future get preloadResponse =>
+ promiseToFuture(JS("", "#.preloadResponse", this));
+
+ final _Request request;
+
+ void respondWith(Future r) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("HTMLFieldSetElement")
+class FieldSetElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory FieldSetElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FieldSetElement() => JS(
+ 'returns:FieldSetElement;creates:FieldSetElement;new:true',
+ '#.createElement(#)',
+ document,
+ "fieldset");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FieldSetElement.created() : super.created();
+
+ bool disabled;
+
+ @Returns('HtmlCollection|Null')
+ @Creates('HtmlCollection')
+ final List<Node> elements;
+
+ final FormElement form;
+
+ String name;
+
+ final String type;
+
+ final String validationMessage;
+
+ final ValidityState validity;
+
+ final bool willValidate;
+
+ bool checkValidity() native;
+
+ bool reportValidity() native;
+
+ void setCustomValidity(String error) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("File")
+class File extends Blob {
+ // To suppress missing implicit constructor warnings.
+ factory File._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory File(List<Object> fileBits, String fileName, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return File._create_1(fileBits, fileName, options_1);
+ }
+ return File._create_2(fileBits, fileName);
+ }
+ static File _create_1(fileBits, fileName, options) =>
+ JS('File', 'new File(#,#,#)', fileBits, fileName, options);
+ static File _create_2(fileBits, fileName) =>
+ JS('File', 'new File(#,#)', fileBits, fileName);
+
+ final int lastModified;
+
+ DateTime get lastModifiedDate =>
+ convertNativeToDart_DateTime(this._get_lastModifiedDate);
+ @JSName('lastModifiedDate')
+ @Creates('Null')
+ final dynamic _get_lastModifiedDate;
+
+ final String name;
+
+ @JSName('webkitRelativePath')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ final String relativePath;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _FileCallback(File file);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileEntry")
+class FileEntry extends Entry {
+ // To suppress missing implicit constructor warnings.
+ factory FileEntry._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('createWriter')
+ void _createWriter(_FileWriterCallback successCallback,
+ [_ErrorCallback errorCallback]) native;
+
+ @JSName('createWriter')
+ Future<FileWriter> createWriter() {
+ var completer = new Completer<FileWriter>();
+ _createWriter((value) {
+ applyExtension('FileWriter', value);
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ @JSName('file')
+ void _file(_FileCallback successCallback, [_ErrorCallback errorCallback])
+ native;
+
+ @JSName('file')
+ Future<File> file() {
+ var completer = new Completer<File>();
+ _file((value) {
+ applyExtension('File', value);
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileList")
+class FileList extends Interceptor
+ with ListMixin<File>, ImmutableListMixin<File>
+ implements List<File>, JavaScriptIndexingBehavior<File> {
+ // To suppress missing implicit constructor warnings.
+ factory FileList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ File operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("File", "#[#]", this, index);
+ }
+
+ void operator []=(int index, File value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<File> mixins.
+ // File is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ File get first {
+ if (this.length > 0) {
+ return JS('File', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ File get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('File', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ File get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('File', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ File elementAt(int index) => this[index];
+ // -- end List<File> mixins.
+
+ File item(int index) native;
+}
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileReader")
+class FileReader extends EventTarget {
+ Object get result {
+ var res = JS('Null|String|NativeByteBuffer', '#.result', this);
+ if (res is ByteBuffer) {
+ return new Uint8List.view(res);
+ }
+ return res;
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory FileReader._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `abort` events to event
+ * handlers that are not necessarily instances of [FileReader].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> abortEvent =
+ const EventStreamProvider<ProgressEvent>('abort');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [FileReader].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> errorEvent =
+ const EventStreamProvider<ProgressEvent>('error');
+
+ /**
+ * Static factory designed to expose `load` events to event
+ * handlers that are not necessarily instances of [FileReader].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> loadEvent =
+ const EventStreamProvider<ProgressEvent>('load');
+
+ /**
+ * Static factory designed to expose `loadend` events to event
+ * handlers that are not necessarily instances of [FileReader].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> loadEndEvent =
+ const EventStreamProvider<ProgressEvent>('loadend');
+
+ /**
+ * Static factory designed to expose `loadstart` events to event
+ * handlers that are not necessarily instances of [FileReader].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> loadStartEvent =
+ const EventStreamProvider<ProgressEvent>('loadstart');
+
+ /**
+ * Static factory designed to expose `progress` events to event
+ * handlers that are not necessarily instances of [FileReader].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> progressEvent =
+ const EventStreamProvider<ProgressEvent>('progress');
+
+ factory FileReader() {
+ return FileReader._create_1();
+ }
+ static FileReader _create_1() => JS('FileReader', 'new FileReader()');
+
+ static const int DONE = 2;
+
+ static const int EMPTY = 0;
+
+ static const int LOADING = 1;
+
+ final DomException error;
+
+ final int readyState;
+
+ void abort() native;
+
+ void readAsArrayBuffer(Blob blob) native;
+
+ @JSName('readAsDataURL')
+ void readAsDataUrl(Blob blob) native;
+
+ void readAsText(Blob blob, [String label]) native;
+
+ /// Stream of `abort` events handled by this [FileReader].
+ Stream<ProgressEvent> get onAbort => abortEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [FileReader].
+ Stream<ProgressEvent> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `load` events handled by this [FileReader].
+ Stream<ProgressEvent> get onLoad => loadEvent.forTarget(this);
+
+ /// Stream of `loadend` events handled by this [FileReader].
+ Stream<ProgressEvent> get onLoadEnd => loadEndEvent.forTarget(this);
+
+ /// Stream of `loadstart` events handled by this [FileReader].
+ Stream<ProgressEvent> get onLoadStart => loadStartEvent.forTarget(this);
+
+ /// Stream of `progress` events handled by this [FileReader].
+ Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("DOMFileSystem")
+class FileSystem extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory FileSystem._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => JS('bool', '!!(window.webkitRequestFileSystem)');
+
+ final String name;
+
+ final DirectoryEntry root;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _FileSystemCallback(FileSystem fileSystem);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileWriter")
+class FileWriter extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory FileWriter._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `abort` events to event
+ * handlers that are not necessarily instances of [FileWriter].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> abortEvent =
+ const EventStreamProvider<ProgressEvent>('abort');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [FileWriter].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /**
+ * Static factory designed to expose `progress` events to event
+ * handlers that are not necessarily instances of [FileWriter].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> progressEvent =
+ const EventStreamProvider<ProgressEvent>('progress');
+
+ /**
+ * Static factory designed to expose `write` events to event
+ * handlers that are not necessarily instances of [FileWriter].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> writeEvent =
+ const EventStreamProvider<ProgressEvent>('write');
+
+ /**
+ * Static factory designed to expose `writeend` events to event
+ * handlers that are not necessarily instances of [FileWriter].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> writeEndEvent =
+ const EventStreamProvider<ProgressEvent>('writeend');
+
+ /**
+ * Static factory designed to expose `writestart` events to event
+ * handlers that are not necessarily instances of [FileWriter].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> writeStartEvent =
+ const EventStreamProvider<ProgressEvent>('writestart');
+
+ static const int DONE = 2;
+
+ static const int INIT = 0;
+
+ static const int WRITING = 1;
+
+ final DomException error;
+
+ final int length;
+
+ final int position;
+
+ final int readyState;
+
+ void abort() native;
+
+ void seek(int position) native;
+
+ void truncate(int size) native;
+
+ void write(Blob data) native;
+
+ /// Stream of `abort` events handled by this [FileWriter].
+ Stream<ProgressEvent> get onAbort => abortEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [FileWriter].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `progress` events handled by this [FileWriter].
+ Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
+
+ /// Stream of `write` events handled by this [FileWriter].
+ Stream<ProgressEvent> get onWrite => writeEvent.forTarget(this);
+
+ /// Stream of `writeend` events handled by this [FileWriter].
+ Stream<ProgressEvent> get onWriteEnd => writeEndEvent.forTarget(this);
+
+ /// Stream of `writestart` events handled by this [FileWriter].
+ Stream<ProgressEvent> get onWriteStart => writeStartEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _FileWriterCallback(FileWriter fileWriter);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FocusEvent")
+class FocusEvent extends UIEvent {
+ // To suppress missing implicit constructor warnings.
+ factory FocusEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FocusEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return FocusEvent._create_1(type, eventInitDict_1);
+ }
+ return FocusEvent._create_2(type);
+ }
+ static FocusEvent _create_1(type, eventInitDict) =>
+ JS('FocusEvent', 'new FocusEvent(#,#)', type, eventInitDict);
+ static FocusEvent _create_2(type) =>
+ JS('FocusEvent', 'new FocusEvent(#)', type);
+
+ EventTarget get relatedTarget =>
+ _convertNativeToDart_EventTarget(this._get_relatedTarget);
+ @JSName('relatedTarget')
+ @Creates('Null')
+ final dynamic _get_relatedTarget;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FontFace")
+class FontFace extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory FontFace._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FontFace(String family, Object source, [Map descriptors]) {
+ if (descriptors != null) {
+ var descriptors_1 = convertDartToNative_Dictionary(descriptors);
+ return FontFace._create_1(family, source, descriptors_1);
+ }
+ return FontFace._create_2(family, source);
+ }
+ static FontFace _create_1(family, source, descriptors) =>
+ JS('FontFace', 'new FontFace(#,#,#)', family, source, descriptors);
+ static FontFace _create_2(family, source) =>
+ JS('FontFace', 'new FontFace(#,#)', family, source);
+
+ String display;
+
+ String family;
+
+ String featureSettings;
+
+ Future<FontFace> get loaded =>
+ promiseToFuture<FontFace>(JS("", "#.loaded", this));
+
+ final String status;
+
+ String stretch;
+
+ String style;
+
+ String unicodeRange;
+
+ String variant;
+
+ String weight;
+
+ Future<FontFace> load() =>
+ promiseToFuture<FontFace>(JS("", "#.load()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FontFaceSet")
+class FontFaceSet extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory FontFaceSet._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<FontFaceSetLoadEvent> loadingEvent =
+ const EventStreamProvider<FontFaceSetLoadEvent>('loading');
+
+ static const EventStreamProvider<FontFaceSetLoadEvent> loadingDoneEvent =
+ const EventStreamProvider<FontFaceSetLoadEvent>('loadingdone');
+
+ static const EventStreamProvider<FontFaceSetLoadEvent> loadingErrorEvent =
+ const EventStreamProvider<FontFaceSetLoadEvent>('loadingerror');
+
+ final String status;
+
+ FontFaceSet add(FontFace arg) native;
+
+ bool check(String font, [String text]) native;
+
+ void clear() native;
+
+ bool delete(FontFace arg) native;
+
+ void forEach(FontFaceSetForEachCallback callback, [Object thisArg]) native;
+
+ bool has(FontFace arg) native;
+
+ Stream<FontFaceSetLoadEvent> get onLoading => loadingEvent.forTarget(this);
+
+ Stream<FontFaceSetLoadEvent> get onLoadingDone =>
+ loadingDoneEvent.forTarget(this);
+
+ Stream<FontFaceSetLoadEvent> get onLoadingError =>
+ loadingErrorEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FontFaceSetLoadEvent")
+class FontFaceSetLoadEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory FontFaceSetLoadEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FontFaceSetLoadEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return FontFaceSetLoadEvent._create_1(type, eventInitDict_1);
+ }
+ return FontFaceSetLoadEvent._create_2(type);
+ }
+ static FontFaceSetLoadEvent _create_1(type, eventInitDict) => JS(
+ 'FontFaceSetLoadEvent',
+ 'new FontFaceSetLoadEvent(#,#)',
+ type,
+ eventInitDict);
+ static FontFaceSetLoadEvent _create_2(type) =>
+ JS('FontFaceSetLoadEvent', 'new FontFaceSetLoadEvent(#)', type);
+
+ final List<FontFace> fontfaces;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FontFaceSource")
+class FontFaceSource extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory FontFaceSource._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final FontFaceSet fonts;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ForeignFetchEvent")
+class ForeignFetchEvent extends ExtendableEvent {
+ // To suppress missing implicit constructor warnings.
+ factory ForeignFetchEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ForeignFetchEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return ForeignFetchEvent._create_1(type, eventInitDict_1);
+ }
+ static ForeignFetchEvent _create_1(type, eventInitDict) => JS(
+ 'ForeignFetchEvent', 'new ForeignFetchEvent(#,#)', type, eventInitDict);
+
+ final String origin;
+
+ final _Request request;
+
+ void respondWith(Future r) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("FormData")
+class FormData extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory FormData._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FormData([FormElement form]) {
+ if (form != null) {
+ return FormData._create_1(form);
+ }
+ return FormData._create_2();
+ }
+ static FormData _create_1(form) => JS('FormData', 'new FormData(#)', form);
+ static FormData _create_2() => JS('FormData', 'new FormData()');
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => JS('bool', '!!(window.FormData)');
+
+ void append(String name, String value) native;
+
+ @JSName('append')
+ void appendBlob(String name, Blob value, [String filename]) native;
+
+ void delete(String name) native;
+
+ Object get(String name) native;
+
+ List<Object> getAll(String name) native;
+
+ bool has(String name) native;
+
+ void set(String name, value, [String filename]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLFormElement")
+class FormElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory FormElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FormElement() => JS(
+ 'returns:FormElement;creates:FormElement;new:true',
+ '#.createElement(#)',
+ document,
+ "form");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FormElement.created() : super.created();
+
+ String acceptCharset;
+
+ String action;
+
+ String autocomplete;
+
+ String encoding;
+
+ String enctype;
+
+ final int length;
+
+ String method;
+
+ String name;
+
+ bool noValidate;
+
+ String target;
+
+ Object __getter__(String name) native;
+
+ bool checkValidity() native;
+
+ Element item(int index) native;
+
+ bool reportValidity() native;
+
+ void requestAutocomplete(Map details) {
+ var details_1 = convertDartToNative_Dictionary(details);
+ _requestAutocomplete_1(details_1);
+ return;
+ }
+
+ @JSName('requestAutocomplete')
+ void _requestAutocomplete_1(details) native;
+
+ void reset() native;
+
+ void submit() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void FrameRequestCallback(num highResTime);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void FunctionStringCallback(String data);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Gamepad")
+class Gamepad extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Gamepad._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final List<num> axes;
+
+ @Creates('JSExtendableArray|GamepadButton')
+ @Returns('JSExtendableArray')
+ final List<GamepadButton> buttons;
+
+ final bool connected;
+
+ final int displayId;
+
+ final String hand;
+
+ final String id;
+
+ final int index;
+
+ final String mapping;
+
+ final GamepadPose pose;
+
+ final int timestamp;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("GamepadButton")
+class GamepadButton extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory GamepadButton._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool pressed;
+
+ final bool touched;
+
+ final num value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("GamepadEvent")
+class GamepadEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory GamepadEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory GamepadEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return GamepadEvent._create_1(type, eventInitDict_1);
+ }
+ return GamepadEvent._create_2(type);
+ }
+ static GamepadEvent _create_1(type, eventInitDict) =>
+ JS('GamepadEvent', 'new GamepadEvent(#,#)', type, eventInitDict);
+ static GamepadEvent _create_2(type) =>
+ JS('GamepadEvent', 'new GamepadEvent(#)', type);
+
+ final Gamepad gamepad;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("GamepadPose")
+class GamepadPose extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory GamepadPose._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Float32List angularAcceleration;
+
+ final Float32List angularVelocity;
+
+ final bool hasOrientation;
+
+ final bool hasPosition;
+
+ final Float32List linearAcceleration;
+
+ final Float32List linearVelocity;
+
+ final Float32List orientation;
+
+ final Float32List position;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("Geolocation")
+class Geolocation extends Interceptor {
+ Future<Geoposition> getCurrentPosition(
+ {bool enableHighAccuracy, Duration timeout, Duration maximumAge}) {
+ var options = {};
+ if (enableHighAccuracy != null) {
+ options['enableHighAccuracy'] = enableHighAccuracy;
+ }
+ if (timeout != null) {
+ options['timeout'] = timeout.inMilliseconds;
+ }
+ if (maximumAge != null) {
+ options['maximumAge'] = maximumAge.inMilliseconds;
+ }
+ var completer = new Completer<Geoposition>();
+ try {
+ _getCurrentPosition((position) {
+ completer.complete(_ensurePosition(position));
+ }, (error) {
+ completer.completeError(error);
+ }, options);
+ } catch (e, stacktrace) {
+ completer.completeError(e, stacktrace);
+ }
+ return completer.future;
+ }
+
+ Stream<Geoposition> watchPosition(
+ {bool enableHighAccuracy, Duration timeout, Duration maximumAge}) {
+ var options = {};
+ if (enableHighAccuracy != null) {
+ options['enableHighAccuracy'] = enableHighAccuracy;
+ }
+ if (timeout != null) {
+ options['timeout'] = timeout.inMilliseconds;
+ }
+ if (maximumAge != null) {
+ options['maximumAge'] = maximumAge.inMilliseconds;
+ }
+
+ int watchId;
+ // TODO(jacobr): it seems like a bug that we have to specifiy the static
+ // type here for controller.stream to have the right type.
+ // dartbug.com/26278
+ StreamController<Geoposition> controller;
+ controller = new StreamController<Geoposition>(
+ sync: true,
+ onListen: () {
+ assert(watchId == null);
+ watchId = _watchPosition((position) {
+ controller.add(_ensurePosition(position));
+ }, (error) {
+ controller.addError(error);
+ }, options);
+ },
+ onCancel: () {
+ assert(watchId != null);
+ _clearWatch(watchId);
+ });
+
+ return controller.stream;
+ }
+
+ Geoposition _ensurePosition(domPosition) {
+ try {
+ // Firefox may throw on this.
+ if (domPosition is Geoposition) {
+ return domPosition;
+ }
+ } catch (e) {}
+ return new _GeopositionWrapper(domPosition);
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory Geolocation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('clearWatch')
+ void _clearWatch(int watchID) native;
+
+ void _getCurrentPosition(_PositionCallback successCallback,
+ [_PositionErrorCallback errorCallback, Map options]) {
+ if (options != null) {
+ var successCallback_1 = convertDartClosureToJS(successCallback, 1);
+ var options_2 = convertDartToNative_Dictionary(options);
+ _getCurrentPosition_1(successCallback_1, errorCallback, options_2);
+ return;
+ }
+ if (errorCallback != null) {
+ var successCallback_1 = convertDartClosureToJS(successCallback, 1);
+ _getCurrentPosition_2(successCallback_1, errorCallback);
+ return;
+ }
+ var successCallback_1 = convertDartClosureToJS(successCallback, 1);
+ _getCurrentPosition_3(successCallback_1);
+ return;
+ }
+
+ @JSName('getCurrentPosition')
+ void _getCurrentPosition_1(
+ successCallback, _PositionErrorCallback errorCallback, options) native;
+ @JSName('getCurrentPosition')
+ void _getCurrentPosition_2(
+ successCallback, _PositionErrorCallback errorCallback) native;
+ @JSName('getCurrentPosition')
+ void _getCurrentPosition_3(successCallback) native;
+
+ int _watchPosition(_PositionCallback successCallback,
+ [_PositionErrorCallback errorCallback, Map options]) {
+ if (options != null) {
+ var successCallback_1 = convertDartClosureToJS(successCallback, 1);
+ var options_2 = convertDartToNative_Dictionary(options);
+ return _watchPosition_1(successCallback_1, errorCallback, options_2);
+ }
+ if (errorCallback != null) {
+ var successCallback_1 = convertDartClosureToJS(successCallback, 1);
+ return _watchPosition_2(successCallback_1, errorCallback);
+ }
+ var successCallback_1 = convertDartClosureToJS(successCallback, 1);
+ return _watchPosition_3(successCallback_1);
+ }
+
+ @JSName('watchPosition')
+ int _watchPosition_1(
+ successCallback, _PositionErrorCallback errorCallback, options) native;
+ @JSName('watchPosition')
+ int _watchPosition_2(successCallback, _PositionErrorCallback errorCallback)
+ native;
+ @JSName('watchPosition')
+ int _watchPosition_3(successCallback) native;
+}
+
+/**
+ * Wrapper for Firefox- it returns an object which we cannot map correctly.
+ * Basically Firefox was returning a [xpconnect wrapped nsIDOMGeoPosition] but
+ * which has further oddities.
+ */
+class _GeopositionWrapper implements Geoposition {
+ var _ptr;
+ _GeopositionWrapper(this._ptr);
+
+ Coordinates get coords => JS('Coordinates', '#.coords', _ptr);
+ int get timestamp => JS('int', '#.timestamp', _ptr);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Position")
+class Geoposition extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Geoposition._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Coordinates coords;
+
+ final int timestamp;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// We implement EventTarget and have stubs for its methods because it's tricky to
+// convince the scripts to make our instance methods abstract, and the bodies that
+// get generated require `this` to be an EventTarget.
+abstract class GlobalEventHandlers implements EventTarget {
+ void addEventListener(String type, dynamic listener(Event event),
+ [bool useCapture]);
+ bool dispatchEvent(Event event);
+ void removeEventListener(String type, dynamic listener(Event event),
+ [bool useCapture]);
+ Events get on;
+
+ // To suppress missing implicit constructor warnings.
+ factory GlobalEventHandlers._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> abortEvent =
+ const EventStreamProvider<Event>('abort');
+
+ static const EventStreamProvider<Event> blurEvent =
+ const EventStreamProvider<Event>('blur');
+
+ static const EventStreamProvider<Event> canPlayEvent =
+ const EventStreamProvider<Event>('canplay');
+
+ static const EventStreamProvider<Event> canPlayThroughEvent =
+ const EventStreamProvider<Event>('canplaythrough');
+
+ static const EventStreamProvider<Event> changeEvent =
+ const EventStreamProvider<Event>('change');
+
+ static const EventStreamProvider<MouseEvent> clickEvent =
+ const EventStreamProvider<MouseEvent>('click');
+
+ static const EventStreamProvider<MouseEvent> contextMenuEvent =
+ const EventStreamProvider<MouseEvent>('contextmenu');
+
+ @DomName('GlobalEventHandlers.dblclickEvent')
+ static const EventStreamProvider<Event> doubleClickEvent =
+ const EventStreamProvider<Event>('dblclick');
+
+ static const EventStreamProvider<MouseEvent> dragEvent =
+ const EventStreamProvider<MouseEvent>('drag');
+
+ static const EventStreamProvider<MouseEvent> dragEndEvent =
+ const EventStreamProvider<MouseEvent>('dragend');
+
+ static const EventStreamProvider<MouseEvent> dragEnterEvent =
+ const EventStreamProvider<MouseEvent>('dragenter');
+
+ static const EventStreamProvider<MouseEvent> dragLeaveEvent =
+ const EventStreamProvider<MouseEvent>('dragleave');
+
+ static const EventStreamProvider<MouseEvent> dragOverEvent =
+ const EventStreamProvider<MouseEvent>('dragover');
+
+ static const EventStreamProvider<MouseEvent> dragStartEvent =
+ const EventStreamProvider<MouseEvent>('dragstart');
+
+ static const EventStreamProvider<MouseEvent> dropEvent =
+ const EventStreamProvider<MouseEvent>('drop');
+
+ static const EventStreamProvider<Event> durationChangeEvent =
+ const EventStreamProvider<Event>('durationchange');
+
+ static const EventStreamProvider<Event> emptiedEvent =
+ const EventStreamProvider<Event>('emptied');
+
+ static const EventStreamProvider<Event> endedEvent =
+ const EventStreamProvider<Event>('ended');
+
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ static const EventStreamProvider<Event> focusEvent =
+ const EventStreamProvider<Event>('focus');
+
+ static const EventStreamProvider<Event> inputEvent =
+ const EventStreamProvider<Event>('input');
+
+ static const EventStreamProvider<Event> invalidEvent =
+ const EventStreamProvider<Event>('invalid');
+
+ static const EventStreamProvider<KeyboardEvent> keyDownEvent =
+ const EventStreamProvider<KeyboardEvent>('keydown');
+
+ static const EventStreamProvider<KeyboardEvent> keyPressEvent =
+ const EventStreamProvider<KeyboardEvent>('keypress');
+
+ static const EventStreamProvider<KeyboardEvent> keyUpEvent =
+ const EventStreamProvider<KeyboardEvent>('keyup');
+
+ static const EventStreamProvider<Event> loadEvent =
+ const EventStreamProvider<Event>('load');
+
+ static const EventStreamProvider<Event> loadedDataEvent =
+ const EventStreamProvider<Event>('loadeddata');
+
+ static const EventStreamProvider<Event> loadedMetadataEvent =
+ const EventStreamProvider<Event>('loadedmetadata');
+
+ static const EventStreamProvider<MouseEvent> mouseDownEvent =
+ const EventStreamProvider<MouseEvent>('mousedown');
+
+ static const EventStreamProvider<MouseEvent> mouseEnterEvent =
+ const EventStreamProvider<MouseEvent>('mouseenter');
+
+ static const EventStreamProvider<MouseEvent> mouseLeaveEvent =
+ const EventStreamProvider<MouseEvent>('mouseleave');
+
+ static const EventStreamProvider<MouseEvent> mouseMoveEvent =
+ const EventStreamProvider<MouseEvent>('mousemove');
+
+ static const EventStreamProvider<MouseEvent> mouseOutEvent =
+ const EventStreamProvider<MouseEvent>('mouseout');
+
+ static const EventStreamProvider<MouseEvent> mouseOverEvent =
+ const EventStreamProvider<MouseEvent>('mouseover');
+
+ static const EventStreamProvider<MouseEvent> mouseUpEvent =
+ const EventStreamProvider<MouseEvent>('mouseup');
+
+ static const EventStreamProvider<WheelEvent> mouseWheelEvent =
+ const EventStreamProvider<WheelEvent>('mousewheel');
+
+ static const EventStreamProvider<Event> pauseEvent =
+ const EventStreamProvider<Event>('pause');
+
+ static const EventStreamProvider<Event> playEvent =
+ const EventStreamProvider<Event>('play');
+
+ static const EventStreamProvider<Event> playingEvent =
+ const EventStreamProvider<Event>('playing');
+
+ static const EventStreamProvider<Event> rateChangeEvent =
+ const EventStreamProvider<Event>('ratechange');
+
+ static const EventStreamProvider<Event> resetEvent =
+ const EventStreamProvider<Event>('reset');
+
+ static const EventStreamProvider<Event> resizeEvent =
+ const EventStreamProvider<Event>('resize');
+
+ static const EventStreamProvider<Event> scrollEvent =
+ const EventStreamProvider<Event>('scroll');
+
+ static const EventStreamProvider<Event> seekedEvent =
+ const EventStreamProvider<Event>('seeked');
+
+ static const EventStreamProvider<Event> seekingEvent =
+ const EventStreamProvider<Event>('seeking');
+
+ static const EventStreamProvider<Event> selectEvent =
+ const EventStreamProvider<Event>('select');
+
+ static const EventStreamProvider<Event> stalledEvent =
+ const EventStreamProvider<Event>('stalled');
+
+ static const EventStreamProvider<Event> submitEvent =
+ const EventStreamProvider<Event>('submit');
+
+ static const EventStreamProvider<Event> suspendEvent =
+ const EventStreamProvider<Event>('suspend');
+
+ static const EventStreamProvider<Event> timeUpdateEvent =
+ const EventStreamProvider<Event>('timeupdate');
+
+ static const EventStreamProvider<TouchEvent> touchCancelEvent =
+ const EventStreamProvider<TouchEvent>('touchcancel');
+
+ static const EventStreamProvider<TouchEvent> touchEndEvent =
+ const EventStreamProvider<TouchEvent>('touchend');
+
+ static const EventStreamProvider<TouchEvent> touchMoveEvent =
+ const EventStreamProvider<TouchEvent>('touchmove');
+
+ static const EventStreamProvider<TouchEvent> touchStartEvent =
+ const EventStreamProvider<TouchEvent>('touchstart');
+
+ static const EventStreamProvider<Event> volumeChangeEvent =
+ const EventStreamProvider<Event>('volumechange');
+
+ static const EventStreamProvider<Event> waitingEvent =
+ const EventStreamProvider<Event>('waiting');
+
+ static const EventStreamProvider<WheelEvent> wheelEvent =
+ const EventStreamProvider<WheelEvent>('wheel');
+
+ Stream<Event> get onAbort => abortEvent.forTarget(this);
+
+ Stream<Event> get onBlur => blurEvent.forTarget(this);
+
+ Stream<Event> get onCanPlay => canPlayEvent.forTarget(this);
+
+ Stream<Event> get onCanPlayThrough => canPlayThroughEvent.forTarget(this);
+
+ Stream<Event> get onChange => changeEvent.forTarget(this);
+
+ Stream<MouseEvent> get onClick => clickEvent.forTarget(this);
+
+ Stream<MouseEvent> get onContextMenu => contextMenuEvent.forTarget(this);
+
+ @DomName('GlobalEventHandlers.ondblclick')
+ Stream<Event> get onDoubleClick => doubleClickEvent.forTarget(this);
+
+ Stream<MouseEvent> get onDrag => dragEvent.forTarget(this);
+
+ Stream<MouseEvent> get onDragEnd => dragEndEvent.forTarget(this);
+
+ Stream<MouseEvent> get onDragEnter => dragEnterEvent.forTarget(this);
+
+ Stream<MouseEvent> get onDragLeave => dragLeaveEvent.forTarget(this);
+
+ Stream<MouseEvent> get onDragOver => dragOverEvent.forTarget(this);
+
+ Stream<MouseEvent> get onDragStart => dragStartEvent.forTarget(this);
+
+ Stream<MouseEvent> get onDrop => dropEvent.forTarget(this);
+
+ Stream<Event> get onDurationChange => durationChangeEvent.forTarget(this);
+
+ Stream<Event> get onEmptied => emptiedEvent.forTarget(this);
+
+ Stream<Event> get onEnded => endedEvent.forTarget(this);
+
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ Stream<Event> get onFocus => focusEvent.forTarget(this);
+
+ Stream<Event> get onInput => inputEvent.forTarget(this);
+
+ Stream<Event> get onInvalid => invalidEvent.forTarget(this);
+
+ Stream<KeyboardEvent> get onKeyDown => keyDownEvent.forTarget(this);
+
+ Stream<KeyboardEvent> get onKeyPress => keyPressEvent.forTarget(this);
+
+ Stream<KeyboardEvent> get onKeyUp => keyUpEvent.forTarget(this);
+
+ Stream<Event> get onLoad => loadEvent.forTarget(this);
+
+ Stream<Event> get onLoadedData => loadedDataEvent.forTarget(this);
+
+ Stream<Event> get onLoadedMetadata => loadedMetadataEvent.forTarget(this);
+
+ Stream<MouseEvent> get onMouseDown => mouseDownEvent.forTarget(this);
+
+ Stream<MouseEvent> get onMouseEnter => mouseEnterEvent.forTarget(this);
+
+ Stream<MouseEvent> get onMouseLeave => mouseLeaveEvent.forTarget(this);
+
+ Stream<MouseEvent> get onMouseMove => mouseMoveEvent.forTarget(this);
+
+ Stream<MouseEvent> get onMouseOut => mouseOutEvent.forTarget(this);
+
+ Stream<MouseEvent> get onMouseOver => mouseOverEvent.forTarget(this);
+
+ Stream<MouseEvent> get onMouseUp => mouseUpEvent.forTarget(this);
+
+ Stream<WheelEvent> get onMouseWheel => mouseWheelEvent.forTarget(this);
+
+ Stream<Event> get onPause => pauseEvent.forTarget(this);
+
+ Stream<Event> get onPlay => playEvent.forTarget(this);
+
+ Stream<Event> get onPlaying => playingEvent.forTarget(this);
+
+ Stream<Event> get onRateChange => rateChangeEvent.forTarget(this);
+
+ Stream<Event> get onReset => resetEvent.forTarget(this);
+
+ Stream<Event> get onResize => resizeEvent.forTarget(this);
+
+ Stream<Event> get onScroll => scrollEvent.forTarget(this);
+
+ Stream<Event> get onSeeked => seekedEvent.forTarget(this);
+
+ Stream<Event> get onSeeking => seekingEvent.forTarget(this);
+
+ Stream<Event> get onSelect => selectEvent.forTarget(this);
+
+ Stream<Event> get onStalled => stalledEvent.forTarget(this);
+
+ Stream<Event> get onSubmit => submitEvent.forTarget(this);
+
+ Stream<Event> get onSuspend => suspendEvent.forTarget(this);
+
+ Stream<Event> get onTimeUpdate => timeUpdateEvent.forTarget(this);
+
+ Stream<TouchEvent> get onTouchCancel => touchCancelEvent.forTarget(this);
+
+ Stream<TouchEvent> get onTouchEnd => touchEndEvent.forTarget(this);
+
+ Stream<TouchEvent> get onTouchMove => touchMoveEvent.forTarget(this);
+
+ Stream<TouchEvent> get onTouchStart => touchStartEvent.forTarget(this);
+
+ Stream<Event> get onVolumeChange => volumeChangeEvent.forTarget(this);
+
+ Stream<Event> get onWaiting => waitingEvent.forTarget(this);
+
+ Stream<WheelEvent> get onWheel => wheelEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Gyroscope")
+class Gyroscope extends Sensor {
+ // To suppress missing implicit constructor warnings.
+ factory Gyroscope._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory Gyroscope([Map sensorOptions]) {
+ if (sensorOptions != null) {
+ var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+ return Gyroscope._create_1(sensorOptions_1);
+ }
+ return Gyroscope._create_2();
+ }
+ static Gyroscope _create_1(sensorOptions) =>
+ JS('Gyroscope', 'new Gyroscope(#)', sensorOptions);
+ static Gyroscope _create_2() => JS('Gyroscope', 'new Gyroscope()');
+
+ final num x;
+
+ final num y;
+
+ final num z;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An `<hr>` tag.
+ */
+@Native("HTMLHRElement")
+class HRElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory HRElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory HRElement() => JS('returns:HRElement;creates:HRElement;new:true',
+ '#.createElement(#)', document, "hr");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ HRElement.created() : super.created();
+
+ String color;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("HashChangeEvent")
+class HashChangeEvent extends Event {
+ factory HashChangeEvent(String type,
+ {bool canBubble: true,
+ bool cancelable: true,
+ String oldUrl,
+ String newUrl}) {
+ var options = {
+ 'canBubble': canBubble,
+ 'cancelable': cancelable,
+ 'oldURL': oldUrl,
+ 'newURL': newUrl,
+ };
+ return JS('HashChangeEvent', 'new HashChangeEvent(#, #)', type,
+ convertDartToNative_Dictionary(options));
+ }
+
+ factory HashChangeEvent._(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return HashChangeEvent._create_1(type, eventInitDict_1);
+ }
+ return HashChangeEvent._create_2(type);
+ }
+ static HashChangeEvent _create_1(type, eventInitDict) =>
+ JS('HashChangeEvent', 'new HashChangeEvent(#,#)', type, eventInitDict);
+ static HashChangeEvent _create_2(type) =>
+ JS('HashChangeEvent', 'new HashChangeEvent(#)', type);
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Device.isEventTypeSupported('HashChangeEvent');
+
+ @JSName('newURL')
+ final String newUrl;
+
+ @JSName('oldURL')
+ final String oldUrl;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLHeadElement")
+class HeadElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory HeadElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory HeadElement() => JS(
+ 'returns:HeadElement;creates:HeadElement;new:true',
+ '#.createElement(#)',
+ document,
+ "head");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ HeadElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Headers")
+class Headers extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Headers._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory Headers([Object init]) {
+ if (init != null) {
+ return Headers._create_1(init);
+ }
+ return Headers._create_2();
+ }
+ static Headers _create_1(init) => JS('Headers', 'new Headers(#)', init);
+ static Headers _create_2() => JS('Headers', 'new Headers()');
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLHeadingElement")
+class HeadingElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory HeadingElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory HeadingElement.h1() => JS(
+ 'returns:HeadingElement;creates:HeadingElement;new:true',
+ '#.createElement(#)',
+ document,
+ "h1");
+
+ factory HeadingElement.h2() => JS(
+ 'returns:HeadingElement;creates:HeadingElement;new:true',
+ '#.createElement(#)',
+ document,
+ "h2");
+
+ factory HeadingElement.h3() => JS(
+ 'returns:HeadingElement;creates:HeadingElement;new:true',
+ '#.createElement(#)',
+ document,
+ "h3");
+
+ factory HeadingElement.h4() => JS(
+ 'returns:HeadingElement;creates:HeadingElement;new:true',
+ '#.createElement(#)',
+ document,
+ "h4");
+
+ factory HeadingElement.h5() => JS(
+ 'returns:HeadingElement;creates:HeadingElement;new:true',
+ '#.createElement(#)',
+ document,
+ "h5");
+
+ factory HeadingElement.h6() => JS(
+ 'returns:HeadingElement;creates:HeadingElement;new:true',
+ '#.createElement(#)',
+ document,
+ "h6");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ HeadingElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("History")
+class History extends Interceptor implements HistoryBase {
+ /**
+ * Checks if the State APIs are supported on the current platform.
+ *
+ * See also:
+ *
+ * * [pushState]
+ * * [replaceState]
+ * * [state]
+ */
+ static bool get supportsState => JS('bool', '!!window.history.pushState');
+ // To suppress missing implicit constructor warnings.
+ factory History._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int length;
+
+ String scrollRestoration;
+
+ dynamic get state =>
+ convertNativeToDart_SerializedScriptValue(this._get_state);
+ @JSName('state')
+ @annotation_Creates_SerializedScriptValue
+ @annotation_Returns_SerializedScriptValue
+ final dynamic _get_state;
+
+ void back() native;
+
+ void forward() native;
+
+ void go([int delta]) native;
+
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void pushState(/*SerializedScriptValue*/ data, String title, String url) {
+ var data_1 = convertDartToNative_SerializedScriptValue(data);
+ _pushState_1(data_1, title, url);
+ return;
+ }
+
+ @JSName('pushState')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void _pushState_1(data, title, url) native;
+
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void replaceState(/*SerializedScriptValue*/ data, String title, String url) {
+ var data_1 = convertDartToNative_SerializedScriptValue(data);
+ _replaceState_1(data_1, title, url);
+ return;
+ }
+
+ @JSName('replaceState')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void _replaceState_1(data, title, url) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLCollection")
+class HtmlCollection extends Interceptor
+ with ListMixin<Node>, ImmutableListMixin<Node>
+ implements JavaScriptIndexingBehavior<Node>, List<Node> {
+ // To suppress missing implicit constructor warnings.
+ factory HtmlCollection._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ Node operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("Node", "#[#]", this, index);
+ }
+
+ void operator []=(int index, Node value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<Node> mixins.
+ // Node is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ Node get first {
+ if (this.length > 0) {
+ return JS('Node', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ Node get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('Node', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ Node get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('Node', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ Node elementAt(int index) => this[index];
+ // -- end List<Node> mixins.
+
+ Node item(int index) native;
+
+ Object namedItem(String name) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("HTMLDocument")
+class HtmlDocument extends Document {
+ // To suppress missing implicit constructor warnings.
+ factory HtmlDocument._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ BodyElement body;
+
+ /// UNSTABLE: Chrome-only - create a Range from the given point.
+ @Unstable()
+ Range caretRangeFromPoint(int x, int y) {
+ return _caretRangeFromPoint(x, y);
+ }
+
+ Element elementFromPoint(int x, int y) {
+ return _elementFromPoint(x, y);
+ }
+
+ HeadElement get head => _head;
+
+ String get lastModified => _lastModified;
+
+ String get preferredStylesheetSet => _preferredStylesheetSet;
+
+ String get referrer => _referrer;
+
+ String get selectedStylesheetSet => _selectedStylesheetSet;
+ set selectedStylesheetSet(String value) {
+ _selectedStylesheetSet = value;
+ }
+
+ List<StyleSheet> get styleSheets => _styleSheets;
+
+ String get title => _title;
+
+ set title(String value) {
+ _title = value;
+ }
+
+ /**
+ * Returns page to standard layout.
+ *
+ * Has no effect if the page is not in fullscreen mode.
+ *
+ * ## Other resources
+ *
+ * * [Fullscreen
+ * API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API)
+ * from MDN.
+ * * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void exitFullscreen() {
+ _webkitExitFullscreen();
+ }
+
+ /**
+ * Register a custom subclass of Element to be instantiatable by the DOM.
+ *
+ * This is necessary to allow the construction of any custom elements.
+ *
+ * The class being registered must either subclass HtmlElement or SvgElement.
+ * If they subclass these directly then they can be used as:
+ *
+ * class FooElement extends HtmlElement{
+ * void created() {
+ * print('FooElement created!');
+ * }
+ * }
+ *
+ * main() {
+ * document.registerElement('x-foo', FooElement);
+ * var myFoo = new Element.tag('x-foo');
+ * // prints 'FooElement created!' to the console.
+ * }
+ *
+ * The custom element can also be instantiated via HTML using the syntax
+ * `<x-foo></x-foo>`
+ *
+ * Other elements can be subclassed as well:
+ *
+ * class BarElement extends InputElement{
+ * void created() {
+ * print('BarElement created!');
+ * }
+ * }
+ *
+ * main() {
+ * document.registerElement('x-bar', BarElement);
+ * var myBar = new Element.tag('input', 'x-bar');
+ * // prints 'BarElement created!' to the console.
+ * }
+ *
+ * This custom element can also be instantiated via HTML using the syntax
+ * `<input is="x-bar"></input>`
+ *
+ */
+ Function registerElement2(String tag, [Map options]) {
+ return _registerCustomElement(JS('', 'window'), this, tag, options);
+ }
+
+ /** *Deprecated*: use [registerElement] instead. */
+ @deprecated
+ void register(String tag, Type customElementClass, {String extendsTag}) {
+ return registerElement(tag, customElementClass, extendsTag: extendsTag);
+ }
+
+ /**
+ * Static factory designed to expose `visibilitychange` events to event
+ * handlers that are not necessarily instances of [Document].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ static const EventStreamProvider<Event> visibilityChangeEvent =
+ const _CustomEventStreamProvider<Event>(
+ _determineVisibilityChangeEventType);
+
+ static String _determineVisibilityChangeEventType(EventTarget e) {
+ if (JS('bool', '(typeof #.hidden !== "undefined")', e)) {
+ // Opera 12.10 and Firefox 18 and later support
+ return 'visibilitychange';
+ } else if (JS('bool', '(typeof #.mozHidden !== "undefined")', e)) {
+ return 'mozvisibilitychange';
+ } else if (JS('bool', '(typeof #.msHidden !== "undefined")', e)) {
+ return 'msvisibilitychange';
+ } else if (JS('bool', '(typeof #.webkitHidden !== "undefined")', e)) {
+ return 'webkitvisibilitychange';
+ }
+ return 'visibilitychange';
+ }
+
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ Stream<Event> get onVisibilityChange => visibilityChangeEvent.forTarget(this);
+
+ /// Creates an element upgrader which can be used to change the Dart wrapper
+ /// type for elements.
+ ///
+ /// The type specified must be a subclass of HtmlElement, when an element is
+ /// upgraded then the created constructor will be invoked on that element.
+ ///
+ /// If the type is not a direct subclass of HtmlElement then the extendsTag
+ /// parameter must be provided.
+ ElementUpgrader createElementUpgrader(Type type, {String extendsTag}) {
+ return new _JSElementUpgrader(this, type, extendsTag);
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLFormControlsCollection")
+class HtmlFormControlsCollection extends HtmlCollection {
+ // To suppress missing implicit constructor warnings.
+ factory HtmlFormControlsCollection._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Node item(int index) native;
+
+ Object namedItem(String name) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLHtmlElement")
+class HtmlHtmlElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory HtmlHtmlElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory HtmlHtmlElement() => JS(
+ 'returns:HtmlHtmlElement;creates:HtmlHtmlElement;new:true',
+ '#.createElement(#)',
+ document,
+ "html");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ HtmlHtmlElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLHyperlinkElementUtils")
+class HtmlHyperlinkElementUtils extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory HtmlHyperlinkElementUtils._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String hash;
+
+ String host;
+
+ String hostname;
+
+ String href;
+
+ final String origin;
+
+ String password;
+
+ String pathname;
+
+ String port;
+
+ String protocol;
+
+ String search;
+
+ String username;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLOptionsCollection")
+class HtmlOptionsCollection extends HtmlCollection {
+ // To suppress missing implicit constructor warnings.
+ factory HtmlOptionsCollection._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('item')
+ Element _item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A client-side XHR request for getting data from a URL,
+ * formally known as XMLHttpRequest.
+ *
+ * HttpRequest can be used to obtain data from HTTP and FTP protocols,
+ * and is useful for AJAX-style page updates.
+ *
+ * The simplest way to get the contents of a text file, such as a
+ * JSON-formatted file, is with [getString].
+ * For example, the following code gets the contents of a JSON file
+ * and prints its length:
+ *
+ * var path = 'myData.json';
+ * HttpRequest.getString(path).then((String fileContents) {
+ * print(fileContents.length);
+ * }).catchError((error) {
+ * print(error.toString());
+ * });
+ *
+ * ## Fetching data from other servers
+ *
+ * For security reasons, browsers impose restrictions on requests
+ * made by embedded apps.
+ * With the default behavior of this class,
+ * the code making the request must be served from the same origin
+ * (domain name, port, and application layer protocol)
+ * as the requested resource.
+ * In the example above, the myData.json file must be co-located with the
+ * app that uses it.
+ * You might be able to
+ * [get around this restriction](http://www.dartlang.org/articles/json-web-service/#a-note-on-cors-and-httprequest)
+ * by using CORS headers or JSONP.
+ *
+ * ## Other resources
+ *
+ * * [Fetch Data Dynamically](https://www.dartlang.org/docs/tutorials/fetchdata/),
+ * a tutorial from _A Game of Darts_,
+ * shows two different ways to use HttpRequest to get a JSON file.
+ * * [Get Input from a Form](https://www.dartlang.org/docs/tutorials/forms/),
+ * another tutorial from _A Game of Darts_,
+ * shows using HttpRequest with a custom server.
+ * * [Dart article on using HttpRequests](http://www.dartlang.org/articles/json-web-service/#getting-data)
+ * * [JS XMLHttpRequest](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest)
+ * * [Using XMLHttpRequest](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest)
+ */
+@Native("XMLHttpRequest")
+class HttpRequest extends HttpRequestEventTarget {
+ /**
+ * Creates a GET request for the specified [url].
+ *
+ * This is similar to [request] but specialized for HTTP GET requests which
+ * return text content.
+ *
+ * To add query parameters, append them to the [url] following a `?`,
+ * joining each key to its value with `=` and separating key-value pairs with
+ * `&`.
+ *
+ * var name = Uri.encodeQueryComponent('John');
+ * var id = Uri.encodeQueryComponent('42');
+ * HttpRequest.getString('users.json?name=$name&id=$id')
+ * .then((String resp) {
+ * // Do something with the response.
+ * });
+ *
+ * See also:
+ *
+ * * [request]
+ */
+ static Future<String> getString(String url,
+ {bool withCredentials, void onProgress(ProgressEvent e)}) {
+ return request(url,
+ withCredentials: withCredentials, onProgress: onProgress)
+ .then((HttpRequest xhr) => xhr.responseText);
+ }
+
+ /**
+ * Makes a server POST request with the specified data encoded as form data.
+ *
+ * This is roughly the POST equivalent of [getString]. This method is similar
+ * to sending a [FormData] object with broader browser support but limited to
+ * String values.
+ *
+ * If [data] is supplied, the key/value pairs are URI encoded with
+ * [Uri.encodeQueryComponent] and converted into an HTTP query string.
+ *
+ * Unless otherwise specified, this method appends the following header:
+ *
+ * Content-Type: application/x-www-form-urlencoded; charset=UTF-8
+ *
+ * Here's an example of using this method:
+ *
+ * var data = { 'firstName' : 'John', 'lastName' : 'Doe' };
+ * HttpRequest.postFormData('/send', data).then((HttpRequest resp) {
+ * // Do something with the response.
+ * });
+ *
+ * See also:
+ *
+ * * [request]
+ */
+ static Future<HttpRequest> postFormData(String url, Map<String, String> data,
+ {bool withCredentials,
+ String responseType,
+ Map<String, String> requestHeaders,
+ void onProgress(ProgressEvent e)}) {
+ var parts = [];
+ data.forEach((key, value) {
+ parts.add('${Uri.encodeQueryComponent(key)}='
+ '${Uri.encodeQueryComponent(value)}');
+ });
+ var formData = parts.join('&');
+
+ if (requestHeaders == null) {
+ requestHeaders = <String, String>{};
+ }
+ requestHeaders.putIfAbsent('Content-Type',
+ () => 'application/x-www-form-urlencoded; charset=UTF-8');
+
+ return request(url,
+ method: 'POST',
+ withCredentials: withCredentials,
+ responseType: responseType,
+ requestHeaders: requestHeaders,
+ sendData: formData,
+ onProgress: onProgress);
+ }
+
+ /**
+ * Creates and sends a URL request for the specified [url].
+ *
+ * By default `request` will perform an HTTP GET request, but a different
+ * method (`POST`, `PUT`, `DELETE`, etc) can be used by specifying the
+ * [method] parameter. (See also [HttpRequest.postFormData] for `POST`
+ * requests only.
+ *
+ * The Future is completed when the response is available.
+ *
+ * If specified, `sendData` will send data in the form of a [ByteBuffer],
+ * [Blob], [Document], [String], or [FormData] along with the HttpRequest.
+ *
+ * If specified, [responseType] sets the desired response format for the
+ * request. By default it is [String], but can also be 'arraybuffer', 'blob',
+ * 'document', 'json', or 'text'. See also [HttpRequest.responseType]
+ * for more information.
+ *
+ * The [withCredentials] parameter specified that credentials such as a cookie
+ * (already) set in the header or
+ * [authorization headers](http://tools.ietf.org/html/rfc1945#section-10.2)
+ * should be specified for the request. Details to keep in mind when using
+ * credentials:
+ *
+ * * Using credentials is only useful for cross-origin requests.
+ * * The `Access-Control-Allow-Origin` header of `url` cannot contain a wildcard (*).
+ * * The `Access-Control-Allow-Credentials` header of `url` must be set to true.
+ * * If `Access-Control-Expose-Headers` has not been set to true, only a subset of all the response headers will be returned when calling [getAllRequestHeaders].
+ *
+ * The following is equivalent to the [getString] sample above:
+ *
+ * var name = Uri.encodeQueryComponent('John');
+ * var id = Uri.encodeQueryComponent('42');
+ * HttpRequest.request('users.json?name=$name&id=$id')
+ * .then((HttpRequest resp) {
+ * // Do something with the response.
+ * });
+ *
+ * Here's an example of submitting an entire form with [FormData].
+ *
+ * var myForm = querySelector('form#myForm');
+ * var data = new FormData(myForm);
+ * HttpRequest.request('/submit', method: 'POST', sendData: data)
+ * .then((HttpRequest resp) {
+ * // Do something with the response.
+ * });
+ *
+ * Note that requests for file:// URIs are only supported by Chrome extensions
+ * with appropriate permissions in their manifest. Requests to file:// URIs
+ * will also never fail- the Future will always complete successfully, even
+ * when the file cannot be found.
+ *
+ * See also: [authorization headers](http://en.wikipedia.org/wiki/Basic_access_authentication).
+ */
+ static Future<HttpRequest> request(String url,
+ {String method,
+ bool withCredentials,
+ String responseType,
+ String mimeType,
+ Map<String, String> requestHeaders,
+ sendData,
+ void onProgress(ProgressEvent e)}) {
+ var completer = new Completer<HttpRequest>();
+
+ var xhr = new HttpRequest();
+ if (method == null) {
+ method = 'GET';
+ }
+ xhr.open(method, url, async: true);
+
+ if (withCredentials != null) {
+ xhr.withCredentials = withCredentials;
+ }
+
+ if (responseType != null) {
+ xhr.responseType = responseType;
+ }
+
+ if (mimeType != null) {
+ xhr.overrideMimeType(mimeType);
+ }
+
+ if (requestHeaders != null) {
+ requestHeaders.forEach((header, value) {
+ xhr.setRequestHeader(header, value);
+ });
+ }
+
+ if (onProgress != null) {
+ xhr.onProgress.listen(onProgress);
+ }
+
+ xhr.onLoad.listen((e) {
+ var accepted = xhr.status >= 200 && xhr.status < 300;
+ var fileUri = xhr.status == 0; // file:// URIs have status of 0.
+ var notModified = xhr.status == 304;
+ // Redirect status is specified up to 307, but others have been used in
+ // practice. Notably Google Drive uses 308 Resume Incomplete for
+ // resumable uploads, and it's also been used as a redirect. The
+ // redirect case will be handled by the browser before it gets to us,
+ // so if we see it we should pass it through to the user.
+ var unknownRedirect = xhr.status > 307 && xhr.status < 400;
+
+ if (accepted || fileUri || notModified || unknownRedirect) {
+ completer.complete(xhr);
+ } else {
+ completer.completeError(e);
+ }
+ });
+
+ xhr.onError.listen(completer.completeError);
+
+ if (sendData != null) {
+ xhr.send(sendData);
+ } else {
+ xhr.send();
+ }
+
+ return completer.future;
+ }
+
+ /**
+ * Checks to see if the Progress event is supported on the current platform.
+ */
+ static bool get supportsProgressEvent {
+ var xhr = new HttpRequest();
+ return JS('bool', '("onprogress" in #)', xhr);
+ }
+
+ /**
+ * Checks to see if the current platform supports making cross origin
+ * requests.
+ *
+ * Note that even if cross origin requests are supported, they still may fail
+ * if the destination server does not support CORS requests.
+ */
+ static bool get supportsCrossOrigin {
+ var xhr = new HttpRequest();
+ return JS('bool', '("withCredentials" in #)', xhr);
+ }
+
+ /**
+ * Checks to see if the LoadEnd event is supported on the current platform.
+ */
+ static bool get supportsLoadEndEvent {
+ var xhr = new HttpRequest();
+ return JS('bool', '("onloadend" in #)', xhr);
+ }
+
+ /**
+ * Checks to see if the overrideMimeType method is supported on the current
+ * platform.
+ */
+ static bool get supportsOverrideMimeType {
+ var xhr = new HttpRequest();
+ return JS('bool', '("overrideMimeType" in #)', xhr);
+ }
+
+ /**
+ * Makes a cross-origin request to the specified URL.
+ *
+ * This API provides a subset of [request] which works on IE9. If IE9
+ * cross-origin support is not required then [request] should be used instead.
+ */
+ static Future<String> requestCrossOrigin(String url,
+ {String method, String sendData}) {
+ if (supportsCrossOrigin) {
+ return request(url, method: method, sendData: sendData).then((xhr) {
+ return xhr.responseText;
+ });
+ }
+ var completer = new Completer<String>();
+ if (method == null) {
+ method = 'GET';
+ }
+ var xhr = JS('var', 'new XDomainRequest()');
+ JS('', '#.open(#, #)', xhr, method, url);
+ JS(
+ '',
+ '#.onload = #',
+ xhr,
+ convertDartClosureToJS((e) {
+ var response = JS('String', '#.responseText', xhr);
+ completer.complete(response);
+ }, 1));
+ JS(
+ '',
+ '#.onerror = #',
+ xhr,
+ convertDartClosureToJS((e) {
+ completer.completeError(e);
+ }, 1));
+
+ // IE9 RTM - XDomainRequest issued requests may abort if all event handlers
+ // not specified
+ // http://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified
+ JS('', '#.onprogress = {}', xhr);
+ JS('', '#.ontimeout = {}', xhr);
+ JS('', '#.timeout = Number.MAX_VALUE', xhr);
+
+ if (sendData != null) {
+ JS('', '#.send(#)', xhr, sendData);
+ } else {
+ JS('', '#.send()', xhr);
+ }
+
+ return completer.future;
+ }
+
+ /**
+ * Returns all response headers as a key-value map.
+ *
+ * Multiple values for the same header key can be combined into one,
+ * separated by a comma and a space.
+ *
+ * See: http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method
+ */
+ Map<String, String> get responseHeaders {
+ // from Closure's goog.net.Xhrio.getResponseHeaders.
+ var headers = <String, String>{};
+ var headersString = this.getAllResponseHeaders();
+ if (headersString == null) {
+ return headers;
+ }
+ var headersList = headersString.split('\r\n');
+ for (var header in headersList) {
+ if (header.isEmpty) {
+ continue;
+ }
+
+ var splitIdx = header.indexOf(': ');
+ if (splitIdx == -1) {
+ continue;
+ }
+ var key = header.substring(0, splitIdx).toLowerCase();
+ var value = header.substring(splitIdx + 2);
+ if (headers.containsKey(key)) {
+ headers[key] = '${headers[key]}, $value';
+ } else {
+ headers[key] = value;
+ }
+ }
+ return headers;
+ }
+
+ /**
+ * Specify the desired `url`, and `method` to use in making the request.
+ *
+ * By default the request is done asyncronously, with no user or password
+ * authentication information. If `async` is false, the request will be sent
+ * synchronously.
+ *
+ * Calling `open` again on a currently active request is equivalent to
+ * calling [abort].
+ *
+ * Note: Most simple HTTP requests can be accomplished using the [getString],
+ * [request], [requestCrossOrigin], or [postFormData] methods. Use of this
+ * `open` method is intended only for more complex HTTP requests where
+ * finer-grained control is needed.
+ */
+ void open(String method, String url,
+ {bool async, String user, String password}) native;
+
+ // To suppress missing implicit constructor warnings.
+ factory HttpRequest._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `readystatechange` events to event
+ * handlers that are not necessarily instances of [HttpRequest].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> readyStateChangeEvent =
+ const EventStreamProvider<Event>('readystatechange');
+
+ /**
+ * General constructor for any type of request (GET, POST, etc).
+ *
+ * This call is used in conjunction with [open]:
+ *
+ * var request = new HttpRequest();
+ * request.open('GET', 'http://dartlang.org');
+ * request.onLoad.listen((event) => print(
+ * 'Request complete ${event.target.reponseText}'));
+ * request.send();
+ *
+ * is the (more verbose) equivalent of
+ *
+ * HttpRequest.getString('http://dartlang.org').then(
+ * (result) => print('Request complete: $result'));
+ */
+ factory HttpRequest() {
+ return HttpRequest._create_1();
+ }
+ static HttpRequest _create_1() => JS('HttpRequest', 'new XMLHttpRequest()');
+
+ static const int DONE = 4;
+
+ static const int HEADERS_RECEIVED = 2;
+
+ static const int LOADING = 3;
+
+ static const int OPENED = 1;
+
+ static const int UNSENT = 0;
+
+ /**
+ * Indicator of the current state of the request:
+ *
+ * <table>
+ * <tr>
+ * <td>Value</td>
+ * <td>State</td>
+ * <td>Meaning</td>
+ * </tr>
+ * <tr>
+ * <td>0</td>
+ * <td>unsent</td>
+ * <td><code>open()</code> has not yet been called</td>
+ * </tr>
+ * <tr>
+ * <td>1</td>
+ * <td>opened</td>
+ * <td><code>send()</code> has not yet been called</td>
+ * </tr>
+ * <tr>
+ * <td>2</td>
+ * <td>headers received</td>
+ * <td><code>sent()</code> has been called; response headers and <code>status</code> are available</td>
+ * </tr>
+ * <tr>
+ * <td>3</td> <td>loading</td> <td><code>responseText</code> holds some data</td>
+ * </tr>
+ * <tr>
+ * <td>4</td> <td>done</td> <td>request is complete</td>
+ * </tr>
+ * </table>
+ */
+ final int readyState;
+
+ /**
+ * The data received as a reponse from the request.
+ *
+ * The data could be in the
+ * form of a [String], [ByteBuffer], [Document], [Blob], or json (also a
+ * [String]). `null` indicates request failure.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ dynamic get response => _convertNativeToDart_XHR_Response(this._get_response);
+ @JSName('response')
+ /**
+ * The data received as a reponse from the request.
+ *
+ * The data could be in the
+ * form of a [String], [ByteBuffer], [Document], [Blob], or json (also a
+ * [String]). `null` indicates request failure.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @Creates(
+ 'NativeByteBuffer|Blob|Document|=Object|JSExtendableArray|String|num')
+ final dynamic _get_response;
+
+ /**
+ * The response in String form or empty String on failure.
+ */
+ final String responseText;
+
+ /**
+ * [String] telling the server the desired response format.
+ *
+ * Default is `String`.
+ * Other options are one of 'arraybuffer', 'blob', 'document', 'json',
+ * 'text'. Some newer browsers will throw NS_ERROR_DOM_INVALID_ACCESS_ERR if
+ * `responseType` is set while performing a synchronous request.
+ *
+ * See also: [MDN
+ * responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype)
+ */
+ String responseType;
+
+ @JSName('responseURL')
+ final String responseUrl;
+
+ @JSName('responseXML')
+ /**
+ * The request response, or null on failure.
+ *
+ * The response is processed as
+ * `text/xml` stream, unless responseType = 'document' and the request is
+ * synchronous.
+ */
+ final Document responseXml;
+
+ /**
+ * The HTTP result code from the request (200, 404, etc).
+ * See also: [HTTP Status Codes](http://en.wikipedia.org/wiki/List_of_HTTP_status_codes)
+ */
+ final int status;
+
+ /**
+ * The request response string (such as \"OK\").
+ * See also: [HTTP Status Codes](http://en.wikipedia.org/wiki/List_of_HTTP_status_codes)
+ */
+ final String statusText;
+
+ /**
+ * Length of time in milliseconds before a request is automatically
+ * terminated.
+ *
+ * When the time has passed, a [TimeoutEvent] is dispatched.
+ *
+ * If [timeout] is set to 0, then the request will not time out.
+ *
+ * ## Other resources
+ *
+ * * [XMLHttpRequest.timeout](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-timeout)
+ * from MDN.
+ * * [The timeout attribute](http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute)
+ * from W3C.
+ */
+ int timeout;
+
+ /**
+ * [EventTarget] that can hold listeners to track the progress of the request.
+ * The events fired will be members of [HttpRequestUploadEvents].
+ */
+ @Unstable()
+ final HttpRequestUpload upload;
+
+ /**
+ * True if cross-site requests should use credentials such as cookies
+ * or authorization headers; false otherwise.
+ *
+ * This value is ignored for same-site requests.
+ */
+ bool withCredentials;
+
+ /**
+ * Stop the current request.
+ *
+ * The request can only be stopped if readyState is `HEADERS_RECEIVED` or
+ * `LOADING`. If this method is not in the process of being sent, the method
+ * has no effect.
+ */
+ void abort() native;
+
+ /**
+ * Retrieve all the response headers from a request.
+ *
+ * `null` if no headers have been received. For multipart requests,
+ * `getAllResponseHeaders` will return the response headers for the current
+ * part of the request.
+ *
+ * See also [HTTP response
+ * headers](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields)
+ * for a list of common response headers.
+ */
+ @Unstable()
+ String getAllResponseHeaders() native;
+
+ /**
+ * Return the response header named `header`, or null if not found.
+ *
+ * See also [HTTP response
+ * headers](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields)
+ * for a list of common response headers.
+ */
+ @Unstable()
+ String getResponseHeader(String name) native;
+
+ /**
+ * Specify a particular MIME type (such as `text/xml`) desired for the
+ * response.
+ *
+ * This value must be set before the request has been sent. See also the list
+ * of [IANA Official MIME types](https://www.iana.org/assignments/media-types/media-types.xhtml).
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void overrideMimeType(String mime) native;
+
+ /**
+ * Send the request with any given `data`.
+ *
+ * Note: Most simple HTTP requests can be accomplished using the [getString],
+ * [request], [requestCrossOrigin], or [postFormData] methods. Use of this
+ * `send` method is intended only for more complex HTTP requests where
+ * finer-grained control is needed.
+ *
+ * ## Other resources
+ *
+ * * [XMLHttpRequest.send](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#send%28%29)
+ * from MDN.
+ */
+ void send([body_OR_data]) native;
+
+ /**
+ * Sets the value of an HTTP request header.
+ *
+ * This method should be called after the request is opened, but before
+ * the request is sent.
+ *
+ * Multiple calls with the same header will combine all their values into a
+ * single header.
+ *
+ * ## Other resources
+ *
+ * * [XMLHttpRequest.setRequestHeader](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#setRequestHeader())
+ * from MDN.
+ * * [The setRequestHeader()
+ * method](http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method)
+ * from W3C.
+ */
+ void setRequestHeader(String name, String value) native;
+
+ /// Stream of `readystatechange` events handled by this [HttpRequest].
+/**
+ * Event listeners to be notified every time the [HttpRequest]
+ * object's `readyState` changes values.
+ */
+ Stream<Event> get onReadyStateChange => readyStateChangeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("XMLHttpRequestEventTarget")
+class HttpRequestEventTarget extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory HttpRequestEventTarget._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `abort` events to event
+ * handlers that are not necessarily instances of [HttpRequestEventTarget].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> abortEvent =
+ const EventStreamProvider<ProgressEvent>('abort');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [HttpRequestEventTarget].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> errorEvent =
+ const EventStreamProvider<ProgressEvent>('error');
+
+ /**
+ * Static factory designed to expose `load` events to event
+ * handlers that are not necessarily instances of [HttpRequestEventTarget].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> loadEvent =
+ const EventStreamProvider<ProgressEvent>('load');
+
+ /**
+ * Static factory designed to expose `loadend` events to event
+ * handlers that are not necessarily instances of [HttpRequestEventTarget].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> loadEndEvent =
+ const EventStreamProvider<ProgressEvent>('loadend');
+
+ /**
+ * Static factory designed to expose `loadstart` events to event
+ * handlers that are not necessarily instances of [HttpRequestEventTarget].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> loadStartEvent =
+ const EventStreamProvider<ProgressEvent>('loadstart');
+
+ /**
+ * Static factory designed to expose `progress` events to event
+ * handlers that are not necessarily instances of [HttpRequestEventTarget].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> progressEvent =
+ const EventStreamProvider<ProgressEvent>('progress');
+
+ /**
+ * Static factory designed to expose `timeout` events to event
+ * handlers that are not necessarily instances of [HttpRequestEventTarget].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<ProgressEvent> timeoutEvent =
+ const EventStreamProvider<ProgressEvent>('timeout');
+
+ /// Stream of `abort` events handled by this [HttpRequestEventTarget].
+ Stream<ProgressEvent> get onAbort => abortEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [HttpRequestEventTarget].
+ Stream<ProgressEvent> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `load` events handled by this [HttpRequestEventTarget].
+ Stream<ProgressEvent> get onLoad => loadEvent.forTarget(this);
+
+ /// Stream of `loadend` events handled by this [HttpRequestEventTarget].
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ Stream<ProgressEvent> get onLoadEnd => loadEndEvent.forTarget(this);
+
+ /// Stream of `loadstart` events handled by this [HttpRequestEventTarget].
+ Stream<ProgressEvent> get onLoadStart => loadStartEvent.forTarget(this);
+
+ /// Stream of `progress` events handled by this [HttpRequestEventTarget].
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
+
+ /// Stream of `timeout` events handled by this [HttpRequestEventTarget].
+ Stream<ProgressEvent> get onTimeout => timeoutEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("XMLHttpRequestUpload")
+class HttpRequestUpload extends HttpRequestEventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory HttpRequestUpload._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLIFrameElement")
+class IFrameElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory IFrameElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory IFrameElement() => JS(
+ 'returns:IFrameElement;creates:IFrameElement;new:true',
+ '#.createElement(#)',
+ document,
+ "iframe");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ IFrameElement.created() : super.created();
+
+ String allow;
+
+ bool allowFullscreen;
+
+ bool allowPaymentRequest;
+
+ WindowBase get contentWindow =>
+ _convertNativeToDart_Window(this._get_contentWindow);
+ @JSName('contentWindow')
+ @Creates('Window|=Object')
+ @Returns('Window|=Object')
+ final dynamic _get_contentWindow;
+
+ String csp;
+
+ String height;
+
+ String name;
+
+ String referrerPolicy;
+
+ final DomTokenList sandbox;
+
+ String src;
+
+ String srcdoc;
+
+ String width;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IdleDeadline")
+class IdleDeadline extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory IdleDeadline._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool didTimeout;
+
+ double timeRemaining() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void IdleRequestCallback(IdleDeadline deadline);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ImageBitmap")
+class ImageBitmap extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ImageBitmap._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int height;
+
+ final int width;
+
+ void close() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ImageBitmapRenderingContext")
+class ImageBitmapRenderingContext extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ImageBitmapRenderingContext._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final CanvasElement canvas;
+
+ void transferFromImageBitmap(ImageBitmap bitmap) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ImageCapture")
+class ImageCapture extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ImageCapture._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ImageCapture(MediaStreamTrack track) {
+ return ImageCapture._create_1(track);
+ }
+ static ImageCapture _create_1(track) =>
+ JS('ImageCapture', 'new ImageCapture(#)', track);
+
+ final MediaStreamTrack track;
+
+ Future<PhotoCapabilities> getPhotoCapabilities() =>
+ promiseToFuture<PhotoCapabilities>(
+ JS("", "#.getPhotoCapabilities()", this));
+
+ Future<Map<String, dynamic>> getPhotoSettings() =>
+ promiseToFutureAsMap(JS("", "#.getPhotoSettings()", this));
+
+ Future<ImageBitmap> grabFrame() =>
+ promiseToFuture<ImageBitmap>(JS("", "#.grabFrame()", this));
+
+ Future setOptions(Map photoSettings) {
+ var photoSettings_dict = convertDartToNative_Dictionary(photoSettings);
+ return promiseToFuture(JS("", "#.setOptions(#)", this, photoSettings_dict));
+ }
+
+ Future<Blob> takePhoto([Map photoSettings]) {
+ var photoSettings_dict = null;
+ if (photoSettings != null) {
+ photoSettings_dict = convertDartToNative_Dictionary(photoSettings);
+ }
+ return promiseToFuture<Blob>(
+ JS("", "#.takePhoto(#)", this, photoSettings_dict));
+ }
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ImageData")
+class ImageData extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ImageData._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ImageData(data_OR_sw, int sh_OR_sw, [int sh]) {
+ if ((sh_OR_sw is int) && (data_OR_sw is int) && sh == null) {
+ return ImageData._create_1(data_OR_sw, sh_OR_sw);
+ }
+ if ((sh_OR_sw is int) && (data_OR_sw is Uint8ClampedList) && sh == null) {
+ return ImageData._create_2(data_OR_sw, sh_OR_sw);
+ }
+ if ((sh is int) && (sh_OR_sw is int) && (data_OR_sw is Uint8ClampedList)) {
+ return ImageData._create_3(data_OR_sw, sh_OR_sw, sh);
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+ static ImageData _create_1(data_OR_sw, sh_OR_sw) =>
+ JS('ImageData', 'new ImageData(#,#)', data_OR_sw, sh_OR_sw);
+ static ImageData _create_2(data_OR_sw, sh_OR_sw) =>
+ JS('ImageData', 'new ImageData(#,#)', data_OR_sw, sh_OR_sw);
+ static ImageData _create_3(data_OR_sw, sh_OR_sw, sh) =>
+ JS('ImageData', 'new ImageData(#,#,#)', data_OR_sw, sh_OR_sw, sh);
+
+ @Creates('NativeUint8ClampedList')
+ @Returns('NativeUint8ClampedList')
+ final Uint8ClampedList data;
+
+ final int height;
+
+ final int width;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLImageElement")
+class ImageElement extends HtmlElement implements CanvasImageSource {
+ // To suppress missing implicit constructor warnings.
+ factory ImageElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ImageElement({String src, int width, int height}) {
+ ImageElement e = JS('returns:ImageElement;creates:ImageElement;new:true',
+ '#.createElement(#)', document, "img");
+ if (src != null) e.src = src;
+ if (width != null) e.width = width;
+ if (height != null) e.height = height;
+ return e;
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ImageElement.created() : super.created();
+
+ String alt;
+
+ String async;
+
+ final bool complete;
+
+ String crossOrigin;
+
+ final String currentSrc;
+
+ int height;
+
+ bool isMap;
+
+ final int naturalHeight;
+
+ final int naturalWidth;
+
+ String referrerPolicy;
+
+ String sizes;
+
+ String src;
+
+ String srcset;
+
+ String useMap;
+
+ int width;
+
+ Future decode() => promiseToFuture(JS("", "#.decode()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("InputDeviceCapabilities")
+class InputDeviceCapabilities extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory InputDeviceCapabilities._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory InputDeviceCapabilities([Map deviceInitDict]) {
+ if (deviceInitDict != null) {
+ var deviceInitDict_1 = convertDartToNative_Dictionary(deviceInitDict);
+ return InputDeviceCapabilities._create_1(deviceInitDict_1);
+ }
+ return InputDeviceCapabilities._create_2();
+ }
+ static InputDeviceCapabilities _create_1(deviceInitDict) => JS(
+ 'InputDeviceCapabilities',
+ 'new InputDeviceCapabilities(#)',
+ deviceInitDict);
+ static InputDeviceCapabilities _create_2() =>
+ JS('InputDeviceCapabilities', 'new InputDeviceCapabilities()');
+
+ final bool firesTouchEvents;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLInputElement")
+class InputElement extends HtmlElement
+ implements
+ HiddenInputElement,
+ SearchInputElement,
+ TextInputElement,
+ UrlInputElement,
+ TelephoneInputElement,
+ EmailInputElement,
+ PasswordInputElement,
+ DateInputElement,
+ MonthInputElement,
+ WeekInputElement,
+ TimeInputElement,
+ LocalDateTimeInputElement,
+ NumberInputElement,
+ RangeInputElement,
+ CheckboxInputElement,
+ RadioButtonInputElement,
+ FileUploadInputElement,
+ SubmitButtonInputElement,
+ ImageButtonInputElement,
+ ResetButtonInputElement,
+ ButtonInputElement {
+ factory InputElement({String type}) {
+ InputElement e = document.createElement("input");
+ if (type != null) {
+ try {
+ // IE throws an exception for unknown types.
+ e.type = type;
+ } catch (_) {}
+ }
+ return e;
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory InputElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ InputElement.created() : super.created();
+
+ String accept;
+
+ String alt;
+
+ String autocapitalize;
+
+ String autocomplete;
+
+ bool autofocus;
+
+ String capture;
+
+ bool checked;
+
+ bool defaultChecked;
+
+ String defaultValue;
+
+ String dirName;
+
+ bool disabled;
+
+ @Returns('FileList|Null')
+ @Creates('FileList')
+ List<File> files;
+
+ final FormElement form;
+
+ String formAction;
+
+ String formEnctype;
+
+ String formMethod;
+
+ bool formNoValidate;
+
+ String formTarget;
+
+ int height;
+
+ bool incremental;
+
+ bool indeterminate;
+
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ final List<Node> labels;
+
+ final HtmlElement list;
+
+ String max;
+
+ int maxLength;
+
+ String min;
+
+ int minLength;
+
+ bool multiple;
+
+ String name;
+
+ String pattern;
+
+ String placeholder;
+
+ bool readOnly;
+
+ bool required;
+
+ String selectionDirection;
+
+ int selectionEnd;
+
+ int selectionStart;
+
+ int size;
+
+ String src;
+
+ String step;
+
+ String type;
+
+ final String validationMessage;
+
+ final ValidityState validity;
+
+ String value;
+
+ DateTime get valueAsDate =>
+ convertNativeToDart_DateTime(this._get_valueAsDate);
+ @JSName('valueAsDate')
+ @Creates('Null')
+ final dynamic _get_valueAsDate;
+
+ set valueAsDate(DateTime value) {
+ this._set_valueAsDate = convertDartToNative_DateTime(value);
+ }
+
+ set _set_valueAsDate(/*dynamic*/ value) {
+ JS("void", "#.valueAsDate = #", this, value);
+ }
+
+ num valueAsNumber;
+
+ @JSName('webkitEntries')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ final List<Entry> entries;
+
+ @JSName('webkitdirectory')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ bool directory;
+
+ int width;
+
+ final bool willValidate;
+
+ bool checkValidity() native;
+
+ bool reportValidity() native;
+
+ void select() native;
+
+ void setCustomValidity(String error) native;
+
+ void setRangeText(String replacement,
+ {int start, int end, String selectionMode}) native;
+
+ void setSelectionRange(int start, int end, [String direction]) native;
+
+ void stepDown([int n]) native;
+
+ void stepUp([int n]) native;
+}
+
+// Interfaces representing the InputElement APIs which are supported
+// for the various types of InputElement. From:
+// https://w3c.github.io/html/sec-forms.html#the-input-element.
+
+/**
+ * Exposes the functionality common between all InputElement types.
+ */
+abstract class InputElementBase implements Element {
+ bool autofocus;
+
+ bool disabled;
+
+ bool incremental;
+
+ bool indeterminate;
+
+ List<Node> get labels;
+
+ String name;
+
+ String get validationMessage;
+
+ ValidityState get validity;
+
+ String value;
+
+ bool get willValidate;
+
+ bool checkValidity();
+
+ void setCustomValidity(String error);
+}
+
+/**
+ * Hidden input which is not intended to be seen or edited by the user.
+ */
+abstract class HiddenInputElement implements InputElementBase {
+ factory HiddenInputElement() => new InputElement(type: 'hidden');
+}
+
+/**
+ * Base interface for all inputs which involve text editing.
+ */
+abstract class TextInputElementBase implements InputElementBase {
+ String autocomplete;
+
+ int maxLength;
+
+ String pattern;
+
+ String placeholder;
+
+ bool readOnly;
+
+ bool required;
+
+ int size;
+
+ void select();
+
+ String selectionDirection;
+
+ int selectionEnd;
+
+ int selectionStart;
+
+ void setSelectionRange(int start, int end, [String direction]);
+}
+
+/**
+ * Similar to [TextInputElement], but on platforms where search is styled
+ * differently this will get the search style.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+abstract class SearchInputElement implements TextInputElementBase {
+ factory SearchInputElement() => new InputElement(type: 'search');
+
+ String dirName;
+
+ Element get list;
+
+ /// Returns true if this input type is supported on the current platform.
+ static bool get supported {
+ return (new InputElement(type: 'search')).type == 'search';
+ }
+}
+
+/**
+ * A basic text input editor control.
+ */
+abstract class TextInputElement implements TextInputElementBase {
+ factory TextInputElement() => new InputElement(type: 'text');
+
+ String dirName;
+
+ Element get list;
+}
+
+/**
+ * A control for editing an absolute URL.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+abstract class UrlInputElement implements TextInputElementBase {
+ factory UrlInputElement() => new InputElement(type: 'url');
+
+ Element get list;
+
+ /// Returns true if this input type is supported on the current platform.
+ static bool get supported {
+ return (new InputElement(type: 'url')).type == 'url';
+ }
+}
+
+/**
+ * Represents a control for editing a telephone number.
+ *
+ * This provides a single line of text with minimal formatting help since
+ * there is a wide variety of telephone numbers.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+abstract class TelephoneInputElement implements TextInputElementBase {
+ factory TelephoneInputElement() => new InputElement(type: 'tel');
+
+ Element get list;
+
+ /// Returns true if this input type is supported on the current platform.
+ static bool get supported {
+ return (new InputElement(type: 'tel')).type == 'tel';
+ }
+}
+
+/**
+ * An e-mail address or list of e-mail addresses.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+abstract class EmailInputElement implements TextInputElementBase {
+ factory EmailInputElement() => new InputElement(type: 'email');
+
+ String autocomplete;
+
+ bool autofocus;
+
+ Element get list;
+
+ int maxLength;
+
+ bool multiple;
+
+ String pattern;
+
+ String placeholder;
+
+ bool readOnly;
+
+ bool required;
+
+ int size;
+
+ /// Returns true if this input type is supported on the current platform.
+ static bool get supported {
+ return (new InputElement(type: 'email')).type == 'email';
+ }
+}
+
+/**
+ * Text with no line breaks (sensitive information).
+ */
+abstract class PasswordInputElement implements TextInputElementBase {
+ factory PasswordInputElement() => new InputElement(type: 'password');
+}
+
+/**
+ * Base interface for all input element types which involve ranges.
+ */
+abstract class RangeInputElementBase implements InputElementBase {
+ Element get list;
+
+ String max;
+
+ String min;
+
+ String step;
+
+ num valueAsNumber;
+
+ void stepDown([int n]);
+
+ void stepUp([int n]);
+}
+
+/**
+ * A date (year, month, day) with no time zone.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+abstract class DateInputElement implements RangeInputElementBase {
+ factory DateInputElement() => new InputElement(type: 'date');
+
+ DateTime valueAsDate;
+
+ bool readOnly;
+
+ bool required;
+
+ /// Returns true if this input type is supported on the current platform.
+ static bool get supported {
+ return (new InputElement(type: 'date')).type == 'date';
+ }
+}
+
+/**
+ * A date consisting of a year and a month with no time zone.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+abstract class MonthInputElement implements RangeInputElementBase {
+ factory MonthInputElement() => new InputElement(type: 'month');
+
+ DateTime valueAsDate;
+
+ bool readOnly;
+
+ bool required;
+
+ /// Returns true if this input type is supported on the current platform.
+ static bool get supported {
+ return (new InputElement(type: 'month')).type == 'month';
+ }
+}
+
+/**
+ * A date consisting of a week-year number and a week number with no time zone.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+abstract class WeekInputElement implements RangeInputElementBase {
+ factory WeekInputElement() => new InputElement(type: 'week');
+
+ DateTime valueAsDate;
+
+ bool readOnly;
+
+ bool required;
+
+ /// Returns true if this input type is supported on the current platform.
+ static bool get supported {
+ return (new InputElement(type: 'week')).type == 'week';
+ }
+}
+
+/**
+ * A time (hour, minute, seconds, fractional seconds) with no time zone.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+abstract class TimeInputElement implements RangeInputElementBase {
+ factory TimeInputElement() => new InputElement(type: 'time');
+
+ DateTime valueAsDate;
+
+ bool readOnly;
+
+ bool required;
+
+ /// Returns true if this input type is supported on the current platform.
+ static bool get supported {
+ return (new InputElement(type: 'time')).type == 'time';
+ }
+}
+
+/**
+ * A date and time (year, month, day, hour, minute, second, fraction of a
+ * second) with no time zone.
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+abstract class LocalDateTimeInputElement implements RangeInputElementBase {
+ factory LocalDateTimeInputElement() =>
+ new InputElement(type: 'datetime-local');
+
+ bool readOnly;
+
+ bool required;
+
+ /// Returns true if this input type is supported on the current platform.
+ static bool get supported {
+ return (new InputElement(type: 'datetime-local')).type == 'datetime-local';
+ }
+}
+
+/**
+ * A numeric editor control.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.IE)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+abstract class NumberInputElement implements RangeInputElementBase {
+ factory NumberInputElement() => new InputElement(type: 'number');
+
+ String placeholder;
+
+ bool readOnly;
+
+ bool required;
+
+ /// Returns true if this input type is supported on the current platform.
+ static bool get supported {
+ return (new InputElement(type: 'number')).type == 'number';
+ }
+}
+
+/**
+ * Similar to [NumberInputElement] but the browser may provide more optimal
+ * styling (such as a slider control).
+ *
+ * Use [supported] to check if this is supported on the current platform.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+abstract class RangeInputElement implements RangeInputElementBase {
+ factory RangeInputElement() => new InputElement(type: 'range');
+
+ /// Returns true if this input type is supported on the current platform.
+ static bool get supported {
+ return (new InputElement(type: 'range')).type == 'range';
+ }
+}
+
+/**
+ * A boolean editor control.
+ *
+ * Note that if [indeterminate] is set then this control is in a third
+ * indeterminate state.
+ */
+abstract class CheckboxInputElement implements InputElementBase {
+ factory CheckboxInputElement() => new InputElement(type: 'checkbox');
+
+ bool checked;
+
+ bool required;
+}
+
+/**
+ * A control that when used with other [ReadioButtonInputElement] controls
+ * forms a radio button group in which only one control can be checked at a
+ * time.
+ *
+ * Radio buttons are considered to be in the same radio button group if:
+ *
+ * * They are all of type 'radio'.
+ * * They all have either the same [FormElement] owner, or no owner.
+ * * Their name attributes contain the same name.
+ */
+abstract class RadioButtonInputElement implements InputElementBase {
+ factory RadioButtonInputElement() => new InputElement(type: 'radio');
+
+ bool checked;
+
+ bool required;
+}
+
+/**
+ * A control for picking files from the user's computer.
+ */
+abstract class FileUploadInputElement implements InputElementBase {
+ factory FileUploadInputElement() => new InputElement(type: 'file');
+
+ String accept;
+
+ bool multiple;
+
+ bool required;
+
+ List<File> files;
+}
+
+/**
+ * A button, which when clicked, submits the form.
+ */
+abstract class SubmitButtonInputElement implements InputElementBase {
+ factory SubmitButtonInputElement() => new InputElement(type: 'submit');
+
+ String formAction;
+
+ String formEnctype;
+
+ String formMethod;
+
+ bool formNoValidate;
+
+ String formTarget;
+}
+
+/**
+ * Either an image which the user can select a coordinate to or a form
+ * submit button.
+ */
+abstract class ImageButtonInputElement implements InputElementBase {
+ factory ImageButtonInputElement() => new InputElement(type: 'image');
+
+ String alt;
+
+ String formAction;
+
+ String formEnctype;
+
+ String formMethod;
+
+ bool formNoValidate;
+
+ String formTarget;
+
+ int height;
+
+ String src;
+
+ int width;
+}
+
+/**
+ * A button, which when clicked, resets the form.
+ */
+abstract class ResetButtonInputElement implements InputElementBase {
+ factory ResetButtonInputElement() => new InputElement(type: 'reset');
+}
+
+/**
+ * A button, with no default behavior.
+ */
+abstract class ButtonInputElement implements InputElementBase {
+ factory ButtonInputElement() => new InputElement(type: 'button');
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("InstallEvent")
+class InstallEvent extends ExtendableEvent {
+ // To suppress missing implicit constructor warnings.
+ factory InstallEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory InstallEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return InstallEvent._create_1(type, eventInitDict_1);
+ }
+ return InstallEvent._create_2(type);
+ }
+ static InstallEvent _create_1(type, eventInitDict) =>
+ JS('InstallEvent', 'new InstallEvent(#,#)', type, eventInitDict);
+ static InstallEvent _create_2(type) =>
+ JS('InstallEvent', 'new InstallEvent(#)', type);
+
+ void registerForeignFetch(Map options) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ _registerForeignFetch_1(options_1);
+ return;
+ }
+
+ @JSName('registerForeignFetch')
+ void _registerForeignFetch_1(options) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IntersectionObserver")
+class IntersectionObserver extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory IntersectionObserver._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory IntersectionObserver(IntersectionObserverCallback callback,
+ [Map options]) {
+ if (options != null) {
+ var callback_1 = convertDartClosureToJS(callback, 2);
+ var options_2 = convertDartToNative_Dictionary(options);
+ return IntersectionObserver._create_1(callback_1, options_2);
+ }
+ var callback_1 = convertDartClosureToJS(callback, 2);
+ return IntersectionObserver._create_2(callback_1);
+ }
+ static IntersectionObserver _create_1(callback, options) => JS(
+ 'IntersectionObserver',
+ 'new IntersectionObserver(#,#)',
+ callback,
+ options);
+ static IntersectionObserver _create_2(callback) =>
+ JS('IntersectionObserver', 'new IntersectionObserver(#)', callback);
+
+ final Element root;
+
+ final String rootMargin;
+
+ final List<num> thresholds;
+
+ void disconnect() native;
+
+ void observe(Element target) native;
+
+ List<IntersectionObserverEntry> takeRecords() native;
+
+ void unobserve(Element target) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void IntersectionObserverCallback(
+ List entries, IntersectionObserver observer);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IntersectionObserverEntry")
+class IntersectionObserverEntry extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory IntersectionObserverEntry._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final DomRectReadOnly boundingClientRect;
+
+ final num intersectionRatio;
+
+ final DomRectReadOnly intersectionRect;
+
+ final bool isIntersecting;
+
+ final DomRectReadOnly rootBounds;
+
+ final Element target;
+
+ final num time;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("InterventionReport")
+class InterventionReport extends ReportBody {
+ // To suppress missing implicit constructor warnings.
+ factory InterventionReport._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int lineNumber;
+
+ final String message;
+
+ final String sourceFile;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An event that describes user interaction with the keyboard.
+ *
+ * The [type] of the event identifies what kind of interaction occurred.
+ *
+ * See also:
+ *
+ * * [KeyboardEvent](https://developer.mozilla.org/en/DOM/KeyboardEvent) at MDN.
+ */
+@Native("KeyboardEvent")
+class KeyboardEvent extends UIEvent {
+ /**
+ * Programmatically create a KeyboardEvent.
+ *
+ * Due to browser differences, keyCode, charCode, or keyIdentifier values
+ * cannot be specified in this base level constructor. This constructor
+ * enables the user to programmatically create and dispatch a [KeyboardEvent],
+ * but it will not contain any particular key content. For programmatically
+ * creating keyboard events with specific key value contents, see the custom
+ * Event [KeyEvent].
+ */
+ factory KeyboardEvent(String type,
+ {Window view,
+ bool canBubble: true,
+ bool cancelable: true,
+ int location,
+ int keyLocation, // Legacy alias for location
+ bool ctrlKey: false,
+ bool altKey: false,
+ bool shiftKey: false,
+ bool metaKey: false}) {
+ if (view == null) {
+ view = window;
+ }
+ location ??= keyLocation ?? 1;
+ KeyboardEvent e = document._createEvent("KeyboardEvent");
+ e._initKeyboardEvent(type, canBubble, cancelable, view, "", location,
+ ctrlKey, altKey, shiftKey, metaKey);
+ return e;
+ }
+
+ void _initKeyboardEvent(
+ String type,
+ bool canBubble,
+ bool cancelable,
+ Window view,
+ String keyIdentifier,
+ int location,
+ bool ctrlKey,
+ bool altKey,
+ bool shiftKey,
+ bool metaKey) {
+ if (JS('bool', 'typeof(#.initKeyEvent) == "function"', this)) {
+ // initKeyEvent is only in Firefox (instead of initKeyboardEvent). It has
+ // a slightly different signature, and allows you to specify keyCode and
+ // charCode as the last two arguments, but we just set them as the default
+ // since they can't be specified in other browsers.
+ JS('void', '#.initKeyEvent(#, #, #, #, #, #, #, #, 0, 0)', this, type,
+ canBubble, cancelable, view, ctrlKey, altKey, shiftKey, metaKey);
+ } else {
+ // initKeyboardEvent is for all other browsers.
+ JS(
+ 'void',
+ '#.initKeyboardEvent(#, #, #, #, #, #, #, #, #, #)',
+ this,
+ type,
+ canBubble,
+ cancelable,
+ view,
+ keyIdentifier,
+ location,
+ ctrlKey,
+ altKey,
+ shiftKey,
+ metaKey);
+ }
+ }
+
+ final int keyCode;
+
+ final int charCode;
+
+ int get which => _which;
+
+ factory KeyboardEvent._(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return KeyboardEvent._create_1(type, eventInitDict_1);
+ }
+ return KeyboardEvent._create_2(type);
+ }
+ static KeyboardEvent _create_1(type, eventInitDict) =>
+ JS('KeyboardEvent', 'new KeyboardEvent(#,#)', type, eventInitDict);
+ static KeyboardEvent _create_2(type) =>
+ JS('KeyboardEvent', 'new KeyboardEvent(#)', type);
+
+ static const int DOM_KEY_LOCATION_LEFT = 0x01;
+
+ static const int DOM_KEY_LOCATION_NUMPAD = 0x03;
+
+ static const int DOM_KEY_LOCATION_RIGHT = 0x02;
+
+ static const int DOM_KEY_LOCATION_STANDARD = 0x00;
+
+ final bool altKey;
+
+ @JSName('charCode')
+ final int _charCode;
+
+ final String code;
+
+ final bool ctrlKey;
+
+ final bool isComposing;
+
+ final String key;
+
+ @JSName('keyCode')
+ final int _keyCode;
+
+ final int location;
+
+ final bool metaKey;
+
+ final bool repeat;
+
+ final bool shiftKey;
+
+ bool getModifierState(String keyArg) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("KeyframeEffect")
+class KeyframeEffect extends KeyframeEffectReadOnly {
+ // To suppress missing implicit constructor warnings.
+ factory KeyframeEffect._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory KeyframeEffect(Element target, Object effect, [Object options]) {
+ if (options != null) {
+ return KeyframeEffect._create_1(target, effect, options);
+ }
+ return KeyframeEffect._create_2(target, effect);
+ }
+ static KeyframeEffect _create_1(target, effect, options) => JS(
+ 'KeyframeEffect', 'new KeyframeEffect(#,#,#)', target, effect, options);
+ static KeyframeEffect _create_2(target, effect) =>
+ JS('KeyframeEffect', 'new KeyframeEffect(#,#)', target, effect);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("KeyframeEffectReadOnly")
+class KeyframeEffectReadOnly extends AnimationEffectReadOnly {
+ // To suppress missing implicit constructor warnings.
+ factory KeyframeEffectReadOnly._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory KeyframeEffectReadOnly(Element target, Object effect,
+ [Object options]) {
+ if (options != null) {
+ return KeyframeEffectReadOnly._create_1(target, effect, options);
+ }
+ return KeyframeEffectReadOnly._create_2(target, effect);
+ }
+ static KeyframeEffectReadOnly _create_1(target, effect, options) => JS(
+ 'KeyframeEffectReadOnly',
+ 'new KeyframeEffectReadOnly(#,#,#)',
+ target,
+ effect,
+ options);
+ static KeyframeEffectReadOnly _create_2(target, effect) => JS(
+ 'KeyframeEffectReadOnly',
+ 'new KeyframeEffectReadOnly(#,#)',
+ target,
+ effect);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLLIElement")
+class LIElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory LIElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory LIElement() => JS('returns:LIElement;creates:LIElement;new:true',
+ '#.createElement(#)', document, "li");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ LIElement.created() : super.created();
+
+ int value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLLabelElement")
+class LabelElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory LabelElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory LabelElement() => JS(
+ 'returns:LabelElement;creates:LabelElement;new:true',
+ '#.createElement(#)',
+ document,
+ "label");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ LabelElement.created() : super.created();
+
+ final HtmlElement control;
+
+ final FormElement form;
+
+ String htmlFor;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLLegendElement")
+class LegendElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory LegendElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory LegendElement() => JS(
+ 'returns:LegendElement;creates:LegendElement;new:true',
+ '#.createElement(#)',
+ document,
+ "legend");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ LegendElement.created() : super.created();
+
+ final FormElement form;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("LinearAccelerationSensor")
+class LinearAccelerationSensor extends Accelerometer {
+ // To suppress missing implicit constructor warnings.
+ factory LinearAccelerationSensor._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory LinearAccelerationSensor([Map sensorOptions]) {
+ if (sensorOptions != null) {
+ var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+ return LinearAccelerationSensor._create_1(sensorOptions_1);
+ }
+ return LinearAccelerationSensor._create_2();
+ }
+ static LinearAccelerationSensor _create_1(sensorOptions) => JS(
+ 'LinearAccelerationSensor',
+ 'new LinearAccelerationSensor(#)',
+ sensorOptions);
+ static LinearAccelerationSensor _create_2() =>
+ JS('LinearAccelerationSensor', 'new LinearAccelerationSensor()');
+}
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLLinkElement")
+class LinkElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory LinkElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory LinkElement() => JS(
+ 'returns:LinkElement;creates:LinkElement;new:true',
+ '#.createElement(#)',
+ document,
+ "link");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ LinkElement.created() : super.created();
+
+ String as;
+
+ String crossOrigin;
+
+ bool disabled;
+
+ String href;
+
+ String hreflang;
+
+ final Document import;
+
+ String integrity;
+
+ String media;
+
+ String referrerPolicy;
+
+ String rel;
+
+ final DomTokenList relList;
+
+ String scope;
+
+ final StyleSheet sheet;
+
+ final DomTokenList sizes;
+
+ String type;
+
+ /// Checks if HTML imports are supported on the current platform.
+ bool get supportsImport {
+ return JS('bool', '("import" in #)', this);
+ }
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Location")
+class Location extends Interceptor implements LocationBase {
+ // To suppress missing implicit constructor warnings.
+ factory Location._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @Returns('DomStringList|Null')
+ @Creates('DomStringList')
+ final List<String> ancestorOrigins;
+
+ String hash;
+
+ String host;
+
+ String hostname;
+
+ String href;
+
+ String pathname;
+
+ String port;
+
+ String protocol;
+
+ String search;
+
+ TrustedUrl trustedHref;
+
+ void assign([String url]) native;
+
+ void reload() native;
+
+ void replace(String url) native;
+
+ String get origin {
+ if (JS('bool', '("origin" in #)', this)) {
+ return JS('String', '#.origin', this);
+ }
+ return '${this.protocol}//${this.host}';
+ }
+
+ String toString() => JS('String', 'String(#)', this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Magnetometer")
+class Magnetometer extends Sensor {
+ // To suppress missing implicit constructor warnings.
+ factory Magnetometer._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory Magnetometer([Map sensorOptions]) {
+ if (sensorOptions != null) {
+ var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+ return Magnetometer._create_1(sensorOptions_1);
+ }
+ return Magnetometer._create_2();
+ }
+ static Magnetometer _create_1(sensorOptions) =>
+ JS('Magnetometer', 'new Magnetometer(#)', sensorOptions);
+ static Magnetometer _create_2() => JS('Magnetometer', 'new Magnetometer()');
+
+ final num x;
+
+ final num y;
+
+ final num z;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLMapElement")
+class MapElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory MapElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MapElement() => JS('returns:MapElement;creates:MapElement;new:true',
+ '#.createElement(#)', document, "map");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ MapElement.created() : super.created();
+
+ @Returns('HtmlCollection|Null')
+ @Creates('HtmlCollection')
+ final List<Node> areas;
+
+ String name;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaCapabilities")
+class MediaCapabilities extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MediaCapabilities._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future<MediaCapabilitiesInfo> decodingInfo(Map configuration) {
+ var configuration_dict = convertDartToNative_Dictionary(configuration);
+ return promiseToFuture<MediaCapabilitiesInfo>(
+ JS("", "#.decodingInfo(#)", this, configuration_dict));
+ }
+
+ Future<MediaCapabilitiesInfo> encodingInfo(Map configuration) {
+ var configuration_dict = convertDartToNative_Dictionary(configuration);
+ return promiseToFuture<MediaCapabilitiesInfo>(
+ JS("", "#.encodingInfo(#)", this, configuration_dict));
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaCapabilitiesInfo")
+class MediaCapabilitiesInfo extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MediaCapabilitiesInfo._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool powerEfficient;
+
+ final bool smooth;
+
+ final bool supported;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaDeviceInfo")
+class MediaDeviceInfo extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MediaDeviceInfo._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String deviceId;
+
+ final String groupId;
+
+ final String kind;
+
+ final String label;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaDevices")
+class MediaDevices extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory MediaDevices._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future<List<MediaDeviceInfo>> enumerateDevices() =>
+ promiseToFuture<List<MediaDeviceInfo>>(
+ JS("", "#.enumerateDevices()", this));
+
+ Map getSupportedConstraints() {
+ return convertNativeToDart_Dictionary(_getSupportedConstraints_1());
+ }
+
+ @JSName('getSupportedConstraints')
+ _getSupportedConstraints_1() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("HTMLMediaElement")
+class MediaElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory MediaElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ MediaElement.created() : super.created();
+
+ static const int HAVE_CURRENT_DATA = 2;
+
+ static const int HAVE_ENOUGH_DATA = 4;
+
+ static const int HAVE_FUTURE_DATA = 3;
+
+ static const int HAVE_METADATA = 1;
+
+ static const int HAVE_NOTHING = 0;
+
+ static const int NETWORK_EMPTY = 0;
+
+ static const int NETWORK_IDLE = 1;
+
+ static const int NETWORK_LOADING = 2;
+
+ static const int NETWORK_NO_SOURCE = 3;
+
+ final AudioTrackList audioTracks;
+
+ bool autoplay;
+
+ final TimeRanges buffered;
+
+ bool controls;
+
+ final DomTokenList controlsList;
+
+ String crossOrigin;
+
+ final String currentSrc;
+
+ num currentTime;
+
+ bool defaultMuted;
+
+ num defaultPlaybackRate;
+
+ bool disableRemotePlayback;
+
+ final num duration;
+
+ final bool ended;
+
+ final MediaError error;
+
+ bool loop;
+
+ final MediaKeys mediaKeys;
+
+ bool muted;
+
+ final int networkState;
+
+ final bool paused;
+
+ num playbackRate;
+
+ final TimeRanges played;
+
+ String preload;
+
+ final int readyState;
+
+ final RemotePlayback remote;
+
+ final TimeRanges seekable;
+
+ final bool seeking;
+
+ final String sinkId;
+
+ String src;
+
+ MediaStream srcObject;
+
+ final TextTrackList textTracks;
+
+ final VideoTrackList videoTracks;
+
+ num volume;
+
+ @JSName('webkitAudioDecodedByteCount')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ final int audioDecodedByteCount;
+
+ @JSName('webkitVideoDecodedByteCount')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ final int videoDecodedByteCount;
+
+ TextTrack addTextTrack(String kind, [String label, String language]) native;
+
+ @Unstable()
+ String canPlayType(String type, [String keySystem]) native;
+
+ MediaStream captureStream() native;
+
+ void load() native;
+
+ void pause() native;
+
+ Future play() => promiseToFuture(JS("", "#.play()", this));
+
+ Future setMediaKeys(MediaKeys mediaKeys) =>
+ promiseToFuture(JS("", "#.setMediaKeys(#)", this, mediaKeys));
+
+ Future setSinkId(String sinkId) =>
+ promiseToFuture(JS("", "#.setSinkId(#)", this, sinkId));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaEncryptedEvent")
+class MediaEncryptedEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory MediaEncryptedEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MediaEncryptedEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return MediaEncryptedEvent._create_1(type, eventInitDict_1);
+ }
+ return MediaEncryptedEvent._create_2(type);
+ }
+ static MediaEncryptedEvent _create_1(type, eventInitDict) => JS(
+ 'MediaEncryptedEvent',
+ 'new MediaEncryptedEvent(#,#)',
+ type,
+ eventInitDict);
+ static MediaEncryptedEvent _create_2(type) =>
+ JS('MediaEncryptedEvent', 'new MediaEncryptedEvent(#)', type);
+
+ final ByteBuffer initData;
+
+ final String initDataType;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("MediaError")
+class MediaError extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MediaError._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int MEDIA_ERR_ABORTED = 1;
+
+ static const int MEDIA_ERR_DECODE = 3;
+
+ static const int MEDIA_ERR_NETWORK = 2;
+
+ static const int MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
+
+ final int code;
+
+ final String message;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaKeyMessageEvent")
+class MediaKeyMessageEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory MediaKeyMessageEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MediaKeyMessageEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return MediaKeyMessageEvent._create_1(type, eventInitDict_1);
+ }
+ static MediaKeyMessageEvent _create_1(type, eventInitDict) => JS(
+ 'MediaKeyMessageEvent',
+ 'new MediaKeyMessageEvent(#,#)',
+ type,
+ eventInitDict);
+
+ final ByteBuffer message;
+
+ final String messageType;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaKeySession")
+class MediaKeySession extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory MediaKeySession._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ Future<void> get closed => promiseToFuture<void>(JS("", "#.closed", this));
+
+ final num expiration;
+
+ final MediaKeyStatusMap keyStatuses;
+
+ final String sessionId;
+
+ Future close() => promiseToFuture(JS("", "#.close()", this));
+
+ Future generateRequest(String initDataType, /*BufferSource*/ initData) =>
+ promiseToFuture(
+ JS("", "#.generateRequest(#, #)", this, initDataType, initData));
+
+ Future load(String sessionId) =>
+ promiseToFuture(JS("", "#.load(#)", this, sessionId));
+
+ Future remove() => promiseToFuture(JS("", "#.remove()", this));
+
+ @JSName('update')
+ Future _update(/*BufferSource*/ response) native;
+
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaKeyStatusMap")
+class MediaKeyStatusMap extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MediaKeyStatusMap._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int size;
+
+ Object get(/*BufferSource*/ keyId) native;
+
+ bool has(/*BufferSource*/ keyId) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaKeySystemAccess")
+class MediaKeySystemAccess extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MediaKeySystemAccess._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String keySystem;
+
+ Future createMediaKeys() =>
+ promiseToFuture(JS("", "#.createMediaKeys()", this));
+
+ Map getConfiguration() {
+ return convertNativeToDart_Dictionary(_getConfiguration_1());
+ }
+
+ @JSName('getConfiguration')
+ _getConfiguration_1() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaKeys")
+class MediaKeys extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MediaKeys._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('createSession')
+ MediaKeySession _createSession([String sessionType]) native;
+
+ Future getStatusForPolicy(MediaKeysPolicy policy) =>
+ promiseToFuture(JS("", "#.getStatusForPolicy(#)", this, policy));
+
+ Future setServerCertificate(/*BufferSource*/ serverCertificate) =>
+ promiseToFuture(
+ JS("", "#.setServerCertificate(#)", this, serverCertificate));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaKeysPolicy")
+class MediaKeysPolicy extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MediaKeysPolicy._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MediaKeysPolicy(Map init) {
+ var init_1 = convertDartToNative_Dictionary(init);
+ return MediaKeysPolicy._create_1(init_1);
+ }
+ static MediaKeysPolicy _create_1(init) =>
+ JS('MediaKeysPolicy', 'new MediaKeysPolicy(#)', init);
+
+ final String minHdcpVersion;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("MediaList")
+class MediaList extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MediaList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int length;
+
+ String mediaText;
+
+ void appendMedium(String medium) native;
+
+ void deleteMedium(String medium) native;
+
+ String item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaMetadata")
+class MediaMetadata extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MediaMetadata._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MediaMetadata([Map metadata]) {
+ if (metadata != null) {
+ var metadata_1 = convertDartToNative_Dictionary(metadata);
+ return MediaMetadata._create_1(metadata_1);
+ }
+ return MediaMetadata._create_2();
+ }
+ static MediaMetadata _create_1(metadata) =>
+ JS('MediaMetadata', 'new MediaMetadata(#)', metadata);
+ static MediaMetadata _create_2() =>
+ JS('MediaMetadata', 'new MediaMetadata()');
+
+ String album;
+
+ String artist;
+
+ List artwork;
+
+ String title;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("MediaQueryList")
+class MediaQueryList extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory MediaQueryList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> changeEvent =
+ const EventStreamProvider<Event>('change');
+
+ final bool matches;
+
+ final String media;
+
+ void addListener(EventListener listener) native;
+
+ void removeListener(EventListener listener) native;
+
+ Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaQueryListEvent")
+class MediaQueryListEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory MediaQueryListEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MediaQueryListEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return MediaQueryListEvent._create_1(type, eventInitDict_1);
+ }
+ return MediaQueryListEvent._create_2(type);
+ }
+ static MediaQueryListEvent _create_1(type, eventInitDict) => JS(
+ 'MediaQueryListEvent',
+ 'new MediaQueryListEvent(#,#)',
+ type,
+ eventInitDict);
+ static MediaQueryListEvent _create_2(type) =>
+ JS('MediaQueryListEvent', 'new MediaQueryListEvent(#)', type);
+
+ final bool matches;
+
+ final String media;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaRecorder")
+class MediaRecorder extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory MediaRecorder._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ static const EventStreamProvider<Event> pauseEvent =
+ const EventStreamProvider<Event>('pause');
+
+ factory MediaRecorder(MediaStream stream, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return MediaRecorder._create_1(stream, options_1);
+ }
+ return MediaRecorder._create_2(stream);
+ }
+ static MediaRecorder _create_1(stream, options) =>
+ JS('MediaRecorder', 'new MediaRecorder(#,#)', stream, options);
+ static MediaRecorder _create_2(stream) =>
+ JS('MediaRecorder', 'new MediaRecorder(#)', stream);
+
+ final int audioBitsPerSecond;
+
+ final String mimeType;
+
+ final String state;
+
+ final MediaStream stream;
+
+ final int videoBitsPerSecond;
+
+ static bool isTypeSupported(String type) native;
+
+ void pause() native;
+
+ void requestData() native;
+
+ void resume() native;
+
+ void start([int timeslice]) native;
+
+ void stop() native;
+
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ Stream<Event> get onPause => pauseEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaSession")
+class MediaSession extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MediaSession._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ MediaMetadata metadata;
+
+ String playbackState;
+
+ void setActionHandler(String action, MediaSessionActionHandler handler)
+ native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void MediaSessionActionHandler();
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaSettingsRange")
+class MediaSettingsRange extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MediaSettingsRange._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num max;
+
+ final num min;
+
+ final num step;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.IE, '11')
+@Native("MediaSource")
+class MediaSource extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory MediaSource._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MediaSource() {
+ return MediaSource._create_1();
+ }
+ static MediaSource _create_1() => JS('MediaSource', 'new MediaSource()');
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => JS('bool', '!!(window.MediaSource)');
+
+ final SourceBufferList activeSourceBuffers;
+
+ num duration;
+
+ final String readyState;
+
+ final SourceBufferList sourceBuffers;
+
+ SourceBuffer addSourceBuffer(String type) native;
+
+ void clearLiveSeekableRange() native;
+
+ void endOfStream([String error]) native;
+
+ static bool isTypeSupported(String type) native;
+
+ void removeSourceBuffer(SourceBuffer buffer) native;
+
+ void setLiveSeekableRange(num start, num end) native;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("MediaStream")
+class MediaStream extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory MediaStream._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `addtrack` events to event
+ * handlers that are not necessarily instances of [MediaStream].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> addTrackEvent =
+ const EventStreamProvider<Event>('addtrack');
+
+ /**
+ * Static factory designed to expose `removetrack` events to event
+ * handlers that are not necessarily instances of [MediaStream].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> removeTrackEvent =
+ const EventStreamProvider<Event>('removetrack');
+
+ factory MediaStream([stream_OR_tracks]) {
+ if (stream_OR_tracks == null) {
+ return MediaStream._create_1();
+ }
+ if ((stream_OR_tracks is MediaStream)) {
+ return MediaStream._create_2(stream_OR_tracks);
+ }
+ if ((stream_OR_tracks is List<MediaStreamTrack>)) {
+ return MediaStream._create_3(stream_OR_tracks);
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+ static MediaStream _create_1() => JS('MediaStream', 'new MediaStream()');
+ static MediaStream _create_2(stream_OR_tracks) =>
+ JS('MediaStream', 'new MediaStream(#)', stream_OR_tracks);
+ static MediaStream _create_3(stream_OR_tracks) =>
+ JS('MediaStream', 'new MediaStream(#)', stream_OR_tracks);
+
+ final bool active;
+
+ final String id;
+
+ void addTrack(MediaStreamTrack track) native;
+
+ MediaStream clone() native;
+
+ @Creates('JSExtendableArray|MediaStreamTrack')
+ @Returns('JSExtendableArray')
+ List<MediaStreamTrack> getAudioTracks() native;
+
+ MediaStreamTrack getTrackById(String trackId) native;
+
+ List<MediaStreamTrack> getTracks() native;
+
+ @Creates('JSExtendableArray|MediaStreamTrack')
+ @Returns('JSExtendableArray')
+ List<MediaStreamTrack> getVideoTracks() native;
+
+ void removeTrack(MediaStreamTrack track) native;
+
+ /// Stream of `addtrack` events handled by this [MediaStream].
+ Stream<Event> get onAddTrack => addTrackEvent.forTarget(this);
+
+ /// Stream of `removetrack` events handled by this [MediaStream].
+ Stream<Event> get onRemoveTrack => removeTrackEvent.forTarget(this);
+
+ /**
+ * Checks if the MediaStream APIs are supported on the current platform.
+ *
+ * See also:
+ *
+ * * [Navigator.getUserMedia]
+ */
+ static bool get supported => JS(
+ 'bool',
+ '''!!(#.getUserMedia || #.webkitGetUserMedia ||
+ #.mozGetUserMedia || #.msGetUserMedia)''',
+ window.navigator,
+ window.navigator,
+ window.navigator,
+ window.navigator);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("MediaStreamEvent")
+class MediaStreamEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory MediaStreamEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MediaStreamEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return MediaStreamEvent._create_1(type, eventInitDict_1);
+ }
+ return MediaStreamEvent._create_2(type);
+ }
+ static MediaStreamEvent _create_1(type, eventInitDict) =>
+ JS('MediaStreamEvent', 'new MediaStreamEvent(#,#)', type, eventInitDict);
+ static MediaStreamEvent _create_2(type) =>
+ JS('MediaStreamEvent', 'new MediaStreamEvent(#)', type);
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Device.isEventTypeSupported('MediaStreamEvent');
+
+ final MediaStream stream;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("MediaStreamTrack")
+class MediaStreamTrack extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory MediaStreamTrack._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `ended` events to event
+ * handlers that are not necessarily instances of [MediaStreamTrack].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> endedEvent =
+ const EventStreamProvider<Event>('ended');
+
+ /**
+ * Static factory designed to expose `mute` events to event
+ * handlers that are not necessarily instances of [MediaStreamTrack].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> muteEvent =
+ const EventStreamProvider<Event>('mute');
+
+ /**
+ * Static factory designed to expose `unmute` events to event
+ * handlers that are not necessarily instances of [MediaStreamTrack].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> unmuteEvent =
+ const EventStreamProvider<Event>('unmute');
+
+ String contentHint;
+
+ bool enabled;
+
+ final String id;
+
+ final String kind;
+
+ final String label;
+
+ final bool muted;
+
+ final String readyState;
+
+ Future applyConstraints([Map constraints]) {
+ var constraints_dict = null;
+ if (constraints != null) {
+ constraints_dict = convertDartToNative_Dictionary(constraints);
+ }
+ return promiseToFuture(
+ JS("", "#.applyConstraints(#)", this, constraints_dict));
+ }
+
+ MediaStreamTrack clone() native;
+
+ Map getCapabilities() {
+ return convertNativeToDart_Dictionary(_getCapabilities_1());
+ }
+
+ @JSName('getCapabilities')
+ _getCapabilities_1() native;
+
+ Map getConstraints() {
+ return convertNativeToDart_Dictionary(_getConstraints_1());
+ }
+
+ @JSName('getConstraints')
+ _getConstraints_1() native;
+
+ Map getSettings() {
+ return convertNativeToDart_Dictionary(_getSettings_1());
+ }
+
+ @JSName('getSettings')
+ _getSettings_1() native;
+
+ void stop() native;
+
+ /// Stream of `ended` events handled by this [MediaStreamTrack].
+ Stream<Event> get onEnded => endedEvent.forTarget(this);
+
+ /// Stream of `mute` events handled by this [MediaStreamTrack].
+ Stream<Event> get onMute => muteEvent.forTarget(this);
+
+ /// Stream of `unmute` events handled by this [MediaStreamTrack].
+ Stream<Event> get onUnmute => unmuteEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("MediaStreamTrackEvent")
+class MediaStreamTrackEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory MediaStreamTrackEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MediaStreamTrackEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return MediaStreamTrackEvent._create_1(type, eventInitDict_1);
+ }
+ static MediaStreamTrackEvent _create_1(type, eventInitDict) => JS(
+ 'MediaStreamTrackEvent',
+ 'new MediaStreamTrackEvent(#,#)',
+ type,
+ eventInitDict);
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ Device.isEventTypeSupported('MediaStreamTrackEvent');
+
+ final MediaStreamTrack track;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MemoryInfo")
+class MemoryInfo extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MemoryInfo._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int jsHeapSizeLimit;
+
+ final int totalJSHeapSize;
+
+ final int usedJSHeapSize;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An HTML <menu> element.
+ *
+ * A <menu> element represents an unordered list of menu commands.
+ *
+ * See also:
+ *
+ * * [Menu Element](https://developer.mozilla.org/en-US/docs/HTML/Element/menu) from MDN.
+ * * [Menu Element](http://www.w3.org/TR/html5/the-menu-element.html#the-menu-element) from the W3C.
+ */
+@Native("HTMLMenuElement")
+class MenuElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory MenuElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MenuElement() => JS(
+ 'returns:MenuElement;creates:MenuElement;new:true',
+ '#.createElement(#)',
+ document,
+ "menu");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ MenuElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void MessageCallback(Map message);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("MessageChannel")
+class MessageChannel extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MessageChannel._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MessageChannel() {
+ return MessageChannel._create_1();
+ }
+ static MessageChannel _create_1() =>
+ JS('MessageChannel', 'new MessageChannel()');
+
+ final MessagePort port1;
+
+ final MessagePort port2;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("MessageEvent")
+class MessageEvent extends Event {
+ factory MessageEvent(String type,
+ {bool canBubble: false,
+ bool cancelable: false,
+ Object data,
+ String origin,
+ String lastEventId,
+ Window source,
+ List<MessagePort> messagePorts: const []}) {
+ if (source == null) {
+ source = window;
+ }
+ if (!Device.isIE) {
+ // TODO: This if check should be removed once IE
+ // implements the constructor.
+ return JS(
+ 'MessageEvent',
+ 'new MessageEvent(#, {bubbles: #, cancelable: #, data: #, origin: #, lastEventId: #, source: #, ports: #})',
+ type,
+ canBubble,
+ cancelable,
+ data,
+ origin,
+ lastEventId,
+ source,
+ messagePorts);
+ }
+ MessageEvent event = document._createEvent("MessageEvent");
+ event._initMessageEvent(type, canBubble, cancelable, data, origin,
+ lastEventId, source, messagePorts);
+ return event;
+ }
+
+ // TODO(alanknight): This really should be generated by the
+ // _OutputConversion in the systemnative.py script, but that doesn't
+ // use those conversions right now, so do this as a one-off.
+ dynamic get data => convertNativeToDart_SerializedScriptValue(this._get_data);
+
+ @JSName('data')
+ @annotation_Creates_SerializedScriptValue
+ @annotation_Returns_SerializedScriptValue
+ final dynamic _get_data;
+
+ factory MessageEvent._(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return MessageEvent._create_1(type, eventInitDict_1);
+ }
+ return MessageEvent._create_2(type);
+ }
+ static MessageEvent _create_1(type, eventInitDict) =>
+ JS('MessageEvent', 'new MessageEvent(#,#)', type, eventInitDict);
+ static MessageEvent _create_2(type) =>
+ JS('MessageEvent', 'new MessageEvent(#)', type);
+
+ @Unstable()
+ final String lastEventId;
+
+ final String origin;
+
+ @Unstable()
+ @Creates('JSExtendableArray')
+ final List<MessagePort> ports;
+
+ EventTarget get source => _convertNativeToDart_EventTarget(this._get_source);
+ @JSName('source')
+ @Creates('Null')
+ @Returns('EventTarget|=Object')
+ final dynamic _get_source;
+
+ final String suborigin;
+
+ void _initMessageEvent(
+ String typeArg,
+ bool canBubbleArg,
+ bool cancelableArg,
+ Object dataArg,
+ String originArg,
+ String lastEventIdArg,
+ EventTarget sourceArg,
+ List<MessagePort> portsArg) {
+ var sourceArg_1 = _convertDartToNative_EventTarget(sourceArg);
+ _initMessageEvent_1(typeArg, canBubbleArg, cancelableArg, dataArg,
+ originArg, lastEventIdArg, sourceArg_1, portsArg);
+ return;
+ }
+
+ @JSName('initMessageEvent')
+ void _initMessageEvent_1(typeArg, canBubbleArg, cancelableArg, dataArg,
+ originArg, lastEventIdArg, sourceArg, List<MessagePort> portsArg) native;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Unstable()
+@Native("MessagePort")
+class MessagePort extends EventTarget {
+ void addEventListener(String type, EventListener listener,
+ [bool useCapture]) {
+ // Messages posted to ports are initially paused, allowing listeners to be
+ // setup, start() needs to be explicitly invoked to begin handling messages.
+ if (type == 'message') {
+ _start();
+ }
+
+ super.addEventListener(type, listener, useCapture);
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory MessagePort._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `message` events to event
+ * handlers that are not necessarily instances of [MessagePort].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ void close() native;
+
+ void postMessage(/*any*/ message, [List<Object> transfer]) {
+ if (transfer != null) {
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_1(message_1, transfer);
+ return;
+ }
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_2(message_1);
+ return;
+ }
+
+ @JSName('postMessage')
+ void _postMessage_1(message, List<Object> transfer) native;
+ @JSName('postMessage')
+ void _postMessage_2(message) native;
+
+ @JSName('start')
+ void _start() native;
+
+ /// Stream of `message` events handled by this [MessagePort].
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLMetaElement")
+class MetaElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory MetaElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MetaElement() => JS(
+ 'returns:MetaElement;creates:MetaElement;new:true',
+ '#.createElement(#)',
+ document,
+ "meta");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ MetaElement.created() : super.created();
+
+ String content;
+
+ String httpEquiv;
+
+ String name;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Metadata")
+class Metadata extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Metadata._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ DateTime get modificationTime =>
+ convertNativeToDart_DateTime(this._get_modificationTime);
+ @JSName('modificationTime')
+ @Creates('Null')
+ final dynamic _get_modificationTime;
+
+ final int size;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void MetadataCallback(Metadata metadata);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("HTMLMeterElement")
+class MeterElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory MeterElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MeterElement() => document.createElement("meter");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ MeterElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Element.isTagSupported('meter');
+
+ num high;
+
+ @Unstable()
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ final List<Node> labels;
+
+ num low;
+
+ num max;
+
+ num min;
+
+ num optimum;
+
+ num value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIAccess")
+class MidiAccess extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory MidiAccess._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final MidiInputMap inputs;
+
+ final MidiOutputMap outputs;
+
+ final bool sysexEnabled;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIConnectionEvent")
+class MidiConnectionEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory MidiConnectionEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MidiConnectionEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return MidiConnectionEvent._create_1(type, eventInitDict_1);
+ }
+ return MidiConnectionEvent._create_2(type);
+ }
+ static MidiConnectionEvent _create_1(type, eventInitDict) => JS(
+ 'MidiConnectionEvent',
+ 'new MIDIConnectionEvent(#,#)',
+ type,
+ eventInitDict);
+ static MidiConnectionEvent _create_2(type) =>
+ JS('MidiConnectionEvent', 'new MIDIConnectionEvent(#)', type);
+
+ final MidiPort port;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIInput")
+class MidiInput extends MidiPort {
+ // To suppress missing implicit constructor warnings.
+ factory MidiInput._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `midimessage` events to event
+ * handlers that are not necessarily instances of [MidiInput].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MidiMessageEvent> midiMessageEvent =
+ const EventStreamProvider<MidiMessageEvent>('midimessage');
+
+ /// Stream of `midimessage` events handled by this [MidiInput].
+ Stream<MidiMessageEvent> get onMidiMessage =>
+ midiMessageEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIInputMap")
+class MidiInputMap extends Interceptor with MapMixin<String, dynamic> {
+ // To suppress missing implicit constructor warnings.
+ factory MidiInputMap._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Map _getItem(String key) =>
+ convertNativeToDart_Dictionary(JS('', '#.get(#)', this, key));
+
+ void addAll(Map<String, dynamic> other) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ bool containsValue(dynamic value) => values.any((e) => e == value);
+
+ bool containsKey(dynamic key) => _getItem(key) != null;
+
+ Map operator [](dynamic key) => _getItem(key);
+
+ void forEach(void f(String key, dynamic value)) {
+ var entries = JS('', '#.entries()', this);
+ while (true) {
+ var entry = JS('', '#.next()', entries);
+ if (JS('bool', '#.done', entry)) return;
+ f(JS('String', '#.value[0]', entry),
+ convertNativeToDart_Dictionary(JS('', '#.value[1]', entry)));
+ }
+ }
+
+ Iterable<String> get keys {
+ final keys = <String>[];
+ forEach((k, v) => keys.add(k));
+ return keys;
+ }
+
+ Iterable<Map> get values {
+ final values = <Map>[];
+ forEach((k, v) => values.add(v));
+ return values;
+ }
+
+ int get length => JS('int', '#.size', this);
+
+ bool get isEmpty => length == 0;
+
+ bool get isNotEmpty => !isEmpty;
+
+ void operator []=(String key, dynamic value) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ dynamic putIfAbsent(String key, dynamic ifAbsent()) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String remove(dynamic key) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void clear() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIMessageEvent")
+class MidiMessageEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory MidiMessageEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MidiMessageEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return MidiMessageEvent._create_1(type, eventInitDict_1);
+ }
+ return MidiMessageEvent._create_2(type);
+ }
+ static MidiMessageEvent _create_1(type, eventInitDict) =>
+ JS('MidiMessageEvent', 'new MIDIMessageEvent(#,#)', type, eventInitDict);
+ static MidiMessageEvent _create_2(type) =>
+ JS('MidiMessageEvent', 'new MIDIMessageEvent(#)', type);
+
+ final Uint8List data;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIOutput")
+class MidiOutput extends MidiPort {
+ // To suppress missing implicit constructor warnings.
+ factory MidiOutput._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void send(Uint8List data, [num timestamp]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIOutputMap")
+class MidiOutputMap extends Interceptor with MapMixin<String, dynamic> {
+ // To suppress missing implicit constructor warnings.
+ factory MidiOutputMap._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Map _getItem(String key) =>
+ convertNativeToDart_Dictionary(JS('', '#.get(#)', this, key));
+
+ void addAll(Map<String, dynamic> other) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ bool containsValue(dynamic value) => values.any((e) => e == value);
+
+ bool containsKey(dynamic key) => _getItem(key) != null;
+
+ Map operator [](dynamic key) => _getItem(key);
+
+ void forEach(void f(String key, dynamic value)) {
+ var entries = JS('', '#.entries()', this);
+ while (true) {
+ var entry = JS('', '#.next()', entries);
+ if (JS('bool', '#.done', entry)) return;
+ f(JS('String', '#.value[0]', entry),
+ convertNativeToDart_Dictionary(JS('', '#.value[1]', entry)));
+ }
+ }
+
+ Iterable<String> get keys {
+ final keys = <String>[];
+ forEach((k, v) => keys.add(k));
+ return keys;
+ }
+
+ Iterable<Map> get values {
+ final values = <Map>[];
+ forEach((k, v) => values.add(v));
+ return values;
+ }
+
+ int get length => JS('int', '#.size', this);
+
+ bool get isEmpty => length == 0;
+
+ bool get isNotEmpty => !isEmpty;
+
+ void operator []=(String key, dynamic value) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ dynamic putIfAbsent(String key, dynamic ifAbsent()) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String remove(dynamic key) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void clear() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MIDIPort")
+class MidiPort extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory MidiPort._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String connection;
+
+ final String id;
+
+ final String manufacturer;
+
+ final String name;
+
+ final String state;
+
+ final String type;
+
+ final String version;
+
+ Future close() => promiseToFuture(JS("", "#.close()", this));
+
+ Future open() => promiseToFuture(JS("", "#.open()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MimeType")
+class MimeType extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MimeType._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String description;
+
+ final Plugin enabledPlugin;
+
+ final String suffixes;
+
+ final String type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MimeTypeArray")
+class MimeTypeArray extends Interceptor
+ with ListMixin<MimeType>, ImmutableListMixin<MimeType>
+ implements List<MimeType>, JavaScriptIndexingBehavior<MimeType> {
+ // To suppress missing implicit constructor warnings.
+ factory MimeTypeArray._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ MimeType operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("MimeType", "#[#]", this, index);
+ }
+
+ void operator []=(int index, MimeType value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<MimeType> mixins.
+ // MimeType is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ MimeType get first {
+ if (this.length > 0) {
+ return JS('MimeType', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ MimeType get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('MimeType', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ MimeType get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('MimeType', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ MimeType elementAt(int index) => this[index];
+ // -- end List<MimeType> mixins.
+
+ MimeType item(int index) native;
+
+ MimeType namedItem(String name) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("HTMLModElement")
+class ModElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory ModElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ModElement.created() : super.created();
+
+ String cite;
+
+ String dateTime;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void MojoWatchCallback(int result);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MouseEvent,DragEvent")
+class MouseEvent extends UIEvent {
+ factory MouseEvent(String type,
+ {Window view,
+ int detail: 0,
+ int screenX: 0,
+ int screenY: 0,
+ int clientX: 0,
+ int clientY: 0,
+ int button: 0,
+ bool canBubble: true,
+ bool cancelable: true,
+ bool ctrlKey: false,
+ bool altKey: false,
+ bool shiftKey: false,
+ bool metaKey: false,
+ EventTarget relatedTarget}) {
+ if (view == null) {
+ view = window;
+ }
+ MouseEvent event = document._createEvent('MouseEvent');
+ event._initMouseEvent(
+ type,
+ canBubble,
+ cancelable,
+ view,
+ detail,
+ screenX,
+ screenY,
+ clientX,
+ clientY,
+ ctrlKey,
+ altKey,
+ shiftKey,
+ metaKey,
+ button,
+ relatedTarget);
+ return event;
+ }
+
+ factory MouseEvent._(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return MouseEvent._create_1(type, eventInitDict_1);
+ }
+ return MouseEvent._create_2(type);
+ }
+ static MouseEvent _create_1(type, eventInitDict) =>
+ JS('MouseEvent', 'new MouseEvent(#,#)', type, eventInitDict);
+ static MouseEvent _create_2(type) =>
+ JS('MouseEvent', 'new MouseEvent(#)', type);
+
+ final bool altKey;
+
+ final int button;
+
+ final int buttons;
+
+ @JSName('clientX')
+ final num _clientX;
+
+ @JSName('clientY')
+ final num _clientY;
+
+ final bool ctrlKey;
+
+ /**
+ * The nonstandard way to access the element that the mouse comes
+ * from in the case of a `mouseover` event.
+ *
+ * This member is deprecated and not cross-browser compatible; use
+ * relatedTarget to get the same information in the standard way.
+ */
+ @deprecated
+ final Node fromElement;
+
+ @JSName('layerX')
+ final int _layerX;
+
+ @JSName('layerY')
+ final int _layerY;
+
+ final bool metaKey;
+
+ @JSName('movementX')
+ final int _movementX;
+
+ @JSName('movementY')
+ final int _movementY;
+
+ @JSName('pageX')
+ final num _pageX;
+
+ @JSName('pageY')
+ final num _pageY;
+
+ final String region;
+
+ EventTarget get relatedTarget =>
+ _convertNativeToDart_EventTarget(this._get_relatedTarget);
+ @JSName('relatedTarget')
+ @Creates('Node')
+ @Returns('EventTarget|=Object|Null')
+ final dynamic _get_relatedTarget;
+
+ @JSName('screenX')
+ final num _screenX;
+
+ @JSName('screenY')
+ final num _screenY;
+
+ final bool shiftKey;
+
+ /**
+ * The nonstandard way to access the element that the mouse goes
+ * to in the case of a `mouseout` event.
+ *
+ * This member is deprecated and not cross-browser compatible; use
+ * relatedTarget to get the same information in the standard way.
+ */
+ @deprecated
+ final Node toElement;
+
+ bool getModifierState(String keyArg) native;
+
+ void _initMouseEvent(
+ String type,
+ bool bubbles,
+ bool cancelable,
+ Window view,
+ int detail,
+ int screenX,
+ int screenY,
+ int clientX,
+ int clientY,
+ bool ctrlKey,
+ bool altKey,
+ bool shiftKey,
+ bool metaKey,
+ int button,
+ EventTarget relatedTarget) {
+ var relatedTarget_1 = _convertDartToNative_EventTarget(relatedTarget);
+ _initMouseEvent_1(
+ type,
+ bubbles,
+ cancelable,
+ view,
+ detail,
+ screenX,
+ screenY,
+ clientX,
+ clientY,
+ ctrlKey,
+ altKey,
+ shiftKey,
+ metaKey,
+ button,
+ relatedTarget_1);
+ return;
+ }
+
+ @JSName('initMouseEvent')
+ void _initMouseEvent_1(
+ type,
+ bubbles,
+ cancelable,
+ Window view,
+ detail,
+ screenX,
+ screenY,
+ clientX,
+ clientY,
+ ctrlKey,
+ altKey,
+ shiftKey,
+ metaKey,
+ button,
+ relatedTarget) native;
+
+ Point get client => new Point(_clientX, _clientY);
+
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ Point get movement => new Point(_movementX, _movementY);
+
+ /**
+ * The coordinates of the mouse pointer in target node coordinates.
+ *
+ * This value may vary between platforms if the target node moves
+ * after the event has fired or if the element has CSS transforms affecting
+ * it.
+ */
+ Point get offset {
+ if (JS('bool', '!!#.offsetX', this)) {
+ var x = JS('int', '#.offsetX', this);
+ var y = JS('int', '#.offsetY', this);
+ return new Point(x, y);
+ } else {
+ // Firefox does not support offsetX.
+ if (!(this.target is Element)) {
+ throw new UnsupportedError('offsetX is only supported on elements');
+ }
+ Element target = this.target;
+ var point = (this.client - target.getBoundingClientRect().topLeft);
+ return new Point(point.x.toInt(), point.y.toInt());
+ }
+ }
+
+ Point get screen => new Point(_screenX, _screenY);
+
+ Point get layer => new Point(_layerX, _layerY);
+
+ Point get page => new Point(_pageX, _pageY);
+
+ DataTransfer get dataTransfer =>
+ JS('DataTransfer', "#['dataTransfer']", this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void MutationCallback(List mutations, MutationObserver observer);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.w3.org/TR/DOM-Level-3-Events/#events-mutationevents
+@deprecated
+@Native("MutationEvent")
+class MutationEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory MutationEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int ADDITION = 2;
+
+ static const int MODIFICATION = 1;
+
+ static const int REMOVAL = 3;
+
+ final int attrChange;
+
+ final String attrName;
+
+ final String newValue;
+
+ final String prevValue;
+
+ final Node relatedNode;
+
+ void initMutationEvent(
+ String type,
+ bool bubbles,
+ bool cancelable,
+ Node relatedNode,
+ String prevValue,
+ String newValue,
+ String attrName,
+ int attrChange) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("MutationObserver,WebKitMutationObserver")
+class MutationObserver extends Interceptor {
+ void disconnect() native;
+
+ void _observe(Node target, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ _observe_1(target, options_1);
+ return;
+ }
+ _observe_2(target);
+ return;
+ }
+
+ @JSName('observe')
+ void _observe_1(Node target, options) native;
+ @JSName('observe')
+ void _observe_2(Node target) native;
+
+ List<MutationRecord> takeRecords() native;
+
+ /**
+ * Checks to see if the mutation observer API is supported on the current
+ * platform.
+ */
+ static bool get supported {
+ return JS(
+ 'bool', '!!(window.MutationObserver || window.WebKitMutationObserver)');
+ }
+
+ /**
+ * Observes the target for the specified changes.
+ *
+ * Some requirements for the optional parameters:
+ *
+ * * Either childList, attributes or characterData must be true.
+ * * If attributeOldValue is true then attributes must also be true.
+ * * If attributeFilter is specified then attributes must be true.
+ * * If characterDataOldValue is true then characterData must be true.
+ */
+ void observe(Node target,
+ {bool childList,
+ bool attributes,
+ bool characterData,
+ bool subtree,
+ bool attributeOldValue,
+ bool characterDataOldValue,
+ List<String> attributeFilter}) {
+ // Parse options into map of known type.
+ var parsedOptions = _createDict();
+
+ // Override options passed in the map with named optional arguments.
+ override(key, value) {
+ if (value != null) _add(parsedOptions, key, value);
+ }
+
+ override('childList', childList);
+ override('attributes', attributes);
+ override('characterData', characterData);
+ override('subtree', subtree);
+ override('attributeOldValue', attributeOldValue);
+ override('characterDataOldValue', characterDataOldValue);
+ if (attributeFilter != null) {
+ override('attributeFilter', _fixupList(attributeFilter));
+ }
+
+ _call(target, parsedOptions);
+ }
+
+ // TODO: Change to a set when const Sets are available.
+ static final _boolKeys = const {
+ 'childList': true,
+ 'attributes': true,
+ 'characterData': true,
+ 'subtree': true,
+ 'attributeOldValue': true,
+ 'characterDataOldValue': true
+ };
+
+ static _createDict() => JS('var', '{}');
+ static _add(m, String key, value) {
+ JS('void', '#[#] = #', m, key, value);
+ }
+
+ static _fixupList(list) => list; // TODO: Ensure is a JavaScript Array.
+
+ // Call native function with no conversions.
+ @JSName('observe')
+ void _call(target, options) native;
+
+ factory MutationObserver(MutationCallback callback) {
+ // Dummy statement to mark types as instantiated.
+ JS('MutationObserver|MutationRecord', '0');
+
+ return JS(
+ 'MutationObserver',
+ 'new(window.MutationObserver||window.WebKitMutationObserver||'
+ 'window.MozMutationObserver)(#)',
+ convertDartClosureToJS(_wrapBinaryZone(callback), 2));
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MutationRecord")
+class MutationRecord extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory MutationRecord._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ final List<Node> addedNodes;
+
+ final String attributeName;
+
+ final String attributeNamespace;
+
+ final Node nextSibling;
+
+ final String oldValue;
+
+ final Node previousSibling;
+
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ final List<Node> removedNodes;
+
+ final Node target;
+
+ final String type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NavigationPreloadManager")
+class NavigationPreloadManager extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory NavigationPreloadManager._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future disable() => promiseToFuture(JS("", "#.disable()", this));
+
+ Future enable() => promiseToFuture(JS("", "#.enable()", this));
+
+ Future<Map<String, dynamic>> getState() =>
+ promiseToFutureAsMap(JS("", "#.getState()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Navigator")
+class Navigator extends NavigatorConcurrentHardware
+ implements
+ NavigatorCookies,
+ NavigatorLanguage,
+ NavigatorOnLine,
+ NavigatorAutomationInformation,
+ NavigatorID {
+ List<Gamepad> getGamepads() {
+ var gamepadList = _getGamepads();
+
+ // If no prototype we need one for the world to hookup to the proper Dart class.
+ var jsProto = JS('', '#.prototype', gamepadList);
+ if (jsProto == null) {
+ JS('', '#.prototype = Object.create(null)', gamepadList);
+ }
+
+ applyExtension('GamepadList', gamepadList);
+ return gamepadList;
+ }
+
+ String get language =>
+ JS('String', '#.language || #.userLanguage', this, this);
+
+ /**
+ * Gets a stream (video and or audio) from the local computer.
+ *
+ * Use [MediaStream.supported] to check if this is supported by the current
+ * platform. The arguments `audio` and `video` default to `false` (stream does
+ * not use audio or video, respectively).
+ *
+ * Simple example usage:
+ *
+ * window.navigator.getUserMedia(audio: true, video: true).then((stream) {
+ * var video = new VideoElement()
+ * ..autoplay = true
+ * ..src = Url.createObjectUrlFromStream(stream);
+ * document.body.append(video);
+ * });
+ *
+ * The user can also pass in Maps to the audio or video parameters to specify
+ * mandatory and optional constraints for the media stream. Not passing in a
+ * map, but passing in `true` will provide a MediaStream with audio or
+ * video capabilities, but without any additional constraints. The particular
+ * constraint names for audio and video are still in flux, but as of this
+ * writing, here is an example providing more constraints.
+ *
+ * window.navigator.getUserMedia(
+ * audio: true,
+ * video: {'mandatory':
+ * { 'minAspectRatio': 1.333, 'maxAspectRatio': 1.334 },
+ * 'optional':
+ * [{ 'minFrameRate': 60 },
+ * { 'maxWidth': 640 }]
+ * });
+ *
+ * See also:
+ * * [MediaStream.supported]
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ Future<MediaStream> getUserMedia({audio: false, video: false}) {
+ var completer = new Completer<MediaStream>();
+ var options = {'audio': audio, 'video': video};
+ _ensureGetUserMedia();
+ this._getUserMedia(convertDartToNative_SerializedScriptValue(options),
+ (stream) {
+ completer.complete(stream);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ _ensureGetUserMedia() {
+ if (JS('bool', '!(#.getUserMedia)', this)) {
+ JS(
+ 'void',
+ '#.getUserMedia = '
+ '(#.getUserMedia || #.webkitGetUserMedia || #.mozGetUserMedia ||'
+ '#.msGetUserMedia)',
+ this,
+ this,
+ this,
+ this,
+ this);
+ }
+ }
+
+ @JSName('getUserMedia')
+ void _getUserMedia(options, _NavigatorUserMediaSuccessCallback success,
+ _NavigatorUserMediaErrorCallback error) native;
+
+ // To suppress missing implicit constructor warnings.
+ factory Navigator._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final _BudgetService budget;
+
+ final _Clipboard clipboard;
+
+ final NetworkInformation connection;
+
+ final CredentialsContainer credentials;
+
+ final num deviceMemory;
+
+ final String doNotTrack;
+
+ @Unstable()
+ final Geolocation geolocation;
+
+ final int maxTouchPoints;
+
+ final MediaCapabilities mediaCapabilities;
+
+ final MediaDevices mediaDevices;
+
+ final MediaSession mediaSession;
+
+ final MimeTypeArray mimeTypes;
+
+ final _NFC nfc;
+
+ final Permissions permissions;
+
+ final Presentation presentation;
+
+ @Unstable()
+ final String productSub;
+
+ final ServiceWorkerContainer serviceWorker;
+
+ final StorageManager storage;
+
+ @Unstable()
+ final String vendor;
+
+ @Unstable()
+ final String vendorSub;
+
+ final VR vr;
+
+ @JSName('webkitPersistentStorage')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ final DeprecatedStorageQuota persistentStorage;
+
+ @JSName('webkitTemporaryStorage')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ final DeprecatedStorageQuota temporaryStorage;
+
+ void cancelKeyboardLock() native;
+
+ Future getBattery() => promiseToFuture(JS("", "#.getBattery()", this));
+
+ @JSName('getGamepads')
+ @Returns('_GamepadList|Null')
+ @Creates('_GamepadList')
+ List<Gamepad> _getGamepads() native;
+
+ Future<RelatedApplication> getInstalledRelatedApps() =>
+ promiseToFuture<RelatedApplication>(
+ JS("", "#.getInstalledRelatedApps()", this));
+
+ Future getVRDisplays() => promiseToFuture(JS("", "#.getVRDisplays()", this));
+
+ @Unstable()
+ void registerProtocolHandler(String scheme, String url, String title) native;
+
+ Future requestKeyboardLock([List<String> keyCodes]) {
+ if (keyCodes != null) {
+ List keyCodes_1 = convertDartToNative_StringArray(keyCodes);
+ return _requestKeyboardLock_1(keyCodes_1);
+ }
+ return _requestKeyboardLock_2();
+ }
+
+ @JSName('requestKeyboardLock')
+ Future _requestKeyboardLock_1(List keyCodes) =>
+ promiseToFuture(JS("", "#.requestKeyboardLock(#)", this, keyCodes));
+ @JSName('requestKeyboardLock')
+ Future _requestKeyboardLock_2() =>
+ promiseToFuture(JS("", "#.requestKeyboardLock()", this));
+
+ @JSName('requestMIDIAccess')
+ Future requestMidiAccess([Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture(
+ JS("", "#.requestMidiAccess(#)", this, options_dict));
+ }
+
+ Future requestMediaKeySystemAccess(
+ String keySystem, List<Map> supportedConfigurations) =>
+ promiseToFuture(JS("", "#.requestMediaKeySystemAccess(#, #)", this,
+ keySystem, supportedConfigurations));
+
+ bool sendBeacon(String url, Object data) native;
+
+ Future share([Map data]) {
+ var data_dict = null;
+ if (data != null) {
+ data_dict = convertDartToNative_Dictionary(data);
+ }
+ return promiseToFuture(JS("", "#.share(#)", this, data_dict));
+ }
+
+ // From NavigatorAutomationInformation
+
+ final bool webdriver;
+
+ // From NavigatorCookies
+
+ @Unstable()
+ final bool cookieEnabled;
+
+ // From NavigatorID
+
+ final String appCodeName;
+
+ final String appName;
+
+ final String appVersion;
+
+ final bool dartEnabled;
+
+ final String platform;
+
+ @Unstable()
+ final String product;
+
+ final String userAgent;
+
+ // From NavigatorLanguage
+
+ final List<String> languages;
+
+ // From NavigatorOnLine
+
+ @Unstable()
+ final bool onLine;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NavigatorAutomationInformation")
+class NavigatorAutomationInformation extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory NavigatorAutomationInformation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool webdriver;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NavigatorConcurrentHardware")
+class NavigatorConcurrentHardware extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory NavigatorConcurrentHardware._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int hardwareConcurrency;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NavigatorCookies")
+class NavigatorCookies extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory NavigatorCookies._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool cookieEnabled;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class NavigatorID extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory NavigatorID._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String appCodeName;
+
+ final String appName;
+
+ final String appVersion;
+
+ final bool dartEnabled;
+
+ final String platform;
+
+ final String product;
+
+ final String userAgent;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class NavigatorLanguage extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory NavigatorLanguage._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String language;
+
+ final List<String> languages;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class NavigatorOnLine extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory NavigatorOnLine._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool onLine;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NavigatorUserMediaError")
+class NavigatorUserMediaError extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory NavigatorUserMediaError._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String constraintName;
+
+ final String message;
+
+ final String name;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _NavigatorUserMediaErrorCallback(NavigatorUserMediaError error);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _NavigatorUserMediaSuccessCallback(MediaStream stream);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NetworkInformation")
+class NetworkInformation extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory NetworkInformation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> changeEvent =
+ const EventStreamProvider<Event>('change');
+
+ final num downlink;
+
+ final num downlinkMax;
+
+ final String effectiveType;
+
+ final int rtt;
+
+ final String type;
+
+ Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Lazy implementation of the child nodes of an element that does not request
+ * the actual child nodes of an element until strictly necessary greatly
+ * improving performance for the typical cases where it is not required.
+ */
+class _ChildNodeListLazy extends ListBase<Node> implements NodeListWrapper {
+ final Node _this;
+
+ _ChildNodeListLazy(this._this);
+
+ Node get first {
+ Node result = JS('Node|Null', '#.firstChild', _this);
+ if (result == null) throw new StateError("No elements");
+ return result;
+ }
+
+ Node get last {
+ Node result = JS('Node|Null', '#.lastChild', _this);
+ if (result == null) throw new StateError("No elements");
+ return result;
+ }
+
+ Node get single {
+ int l = this.length;
+ if (l == 0) throw new StateError("No elements");
+ if (l > 1) throw new StateError("More than one element");
+ return JS('Node|Null', '#.firstChild', _this);
+ }
+
+ void add(Node value) {
+ _this.append(value);
+ }
+
+ void addAll(Iterable<Node> iterable) {
+ if (iterable is _ChildNodeListLazy) {
+ _ChildNodeListLazy otherList = iterable;
+ if (!identical(otherList._this, _this)) {
+ // Optimized route for copying between nodes.
+ for (var i = 0, len = otherList.length; i < len; ++i) {
+ _this.append(otherList._this.firstChild);
+ }
+ }
+ return;
+ }
+ for (Node node in iterable) {
+ _this.append(node);
+ }
+ }
+
+ void insert(int index, Node node) {
+ if (index < 0 || index > length) {
+ throw new RangeError.range(index, 0, length);
+ }
+ if (index == length) {
+ _this.append(node);
+ } else {
+ _this.insertBefore(node, this[index]);
+ }
+ }
+
+ void insertAll(int index, Iterable<Node> iterable) {
+ if (index == length) {
+ addAll(iterable);
+ } else {
+ var item = this[index];
+ _this.insertAllBefore(iterable, item);
+ }
+ }
+
+ void setAll(int index, Iterable<Node> iterable) {
+ throw new UnsupportedError("Cannot setAll on Node list");
+ }
+
+ Node removeLast() {
+ final result = last;
+ if (result != null) {
+ _this._removeChild(result);
+ }
+ return result;
+ }
+
+ Node removeAt(int index) {
+ var result = this[index];
+ if (result != null) {
+ _this._removeChild(result);
+ }
+ return result;
+ }
+
+ bool remove(Object object) {
+ if (object is! Node) return false;
+ Node node = object;
+ if (!identical(_this, node.parentNode)) return false;
+ _this._removeChild(node);
+ return true;
+ }
+
+ void _filter(bool test(Node node), bool removeMatching) {
+ // This implementation of removeWhere/retainWhere is more efficient
+ // than the default in ListBase. Child nodes can be removed in constant
+ // time.
+ Node child = _this.firstChild;
+ while (child != null) {
+ Node nextChild = child.nextNode;
+ if (test(child) == removeMatching) {
+ _this._removeChild(child);
+ }
+ child = nextChild;
+ }
+ }
+
+ void removeWhere(bool test(Node node)) {
+ _filter(test, true);
+ }
+
+ void retainWhere(bool test(Node node)) {
+ _filter(test, false);
+ }
+
+ void clear() {
+ _this._clearChildren();
+ }
+
+ void operator []=(int index, Node value) {
+ _this._replaceChild(value, this[index]);
+ }
+
+ Iterator<Node> get iterator => _this.childNodes.iterator;
+
+ // From List<Node>:
+
+ // TODO(jacobr): this could be implemented for child node lists.
+ // The exception we throw here is misleading.
+ void sort([Comparator<Node> compare]) {
+ throw new UnsupportedError("Cannot sort Node list");
+ }
+
+ void shuffle([Random random]) {
+ throw new UnsupportedError("Cannot shuffle Node list");
+ }
+
+ // FIXME: implement these.
+ void setRange(int start, int end, Iterable<Node> iterable,
+ [int skipCount = 0]) {
+ throw new UnsupportedError("Cannot setRange on Node list");
+ }
+
+ void fillRange(int start, int end, [Node fill]) {
+ throw new UnsupportedError("Cannot fillRange on Node list");
+ }
+
+ void removeRange(int start, int end) {
+ throw new UnsupportedError("Cannot removeRange on Node list");
+ }
+ // -- end List<Node> mixins.
+
+ // TODO(jacobr): benchmark whether this is more efficient or whether caching
+ // a local copy of childNodes is more efficient.
+ int get length => _this.childNodes.length;
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot set length on immutable List.");
+ }
+
+ Node operator [](int index) => _this.childNodes[index];
+
+ List<Node> get rawList => _this.childNodes;
+}
+
+@Native("Node")
+class Node extends EventTarget {
+ // Custom element created callback.
+ Node._created() : super._created();
+
+ /**
+ * A modifiable list of this node's children.
+ */
+ List<Node> get nodes {
+ return new _ChildNodeListLazy(this);
+ }
+
+ set nodes(Iterable<Node> value) {
+ // Copy list first since we don't want liveness during iteration.
+ // TODO(jacobr): there is a better way to do this.
+ var copy = value.toList();
+ text = '';
+ for (Node node in copy) {
+ append(node);
+ }
+ }
+
+ /**
+ * Removes this node from the DOM.
+ */
+ void remove() {
+ // TODO(jacobr): should we throw an exception if parent is already null?
+ // TODO(vsm): Use the native remove when available.
+ if (this.parentNode != null) {
+ final Node parent = this.parentNode;
+ parentNode._removeChild(this);
+ }
+ }
+
+ /**
+ * Replaces this node with another node.
+ */
+ Node replaceWith(Node otherNode) {
+ try {
+ final Node parent = this.parentNode;
+ parent._replaceChild(otherNode, this);
+ } catch (e) {}
+ ;
+ return this;
+ }
+
+ /**
+ * Inserts all of the nodes into this node directly before refChild.
+ *
+ * See also:
+ *
+ * * [insertBefore]
+ */
+ Node insertAllBefore(Iterable<Node> newNodes, Node refChild) {
+ if (newNodes is _ChildNodeListLazy) {
+ _ChildNodeListLazy otherList = newNodes;
+ if (identical(otherList._this, this)) {
+ throw new ArgumentError(newNodes);
+ }
+
+ // Optimized route for copying between nodes.
+ for (var i = 0, len = otherList.length; i < len; ++i) {
+ this.insertBefore(otherList._this.firstChild, refChild);
+ }
+ } else {
+ for (var node in newNodes) {
+ this.insertBefore(node, refChild);
+ }
+ }
+ }
+
+ void _clearChildren() {
+ while (firstChild != null) {
+ _removeChild(firstChild);
+ }
+ }
+
+ /**
+ * Print out a String representation of this Node.
+ */
+ String toString() {
+ String value = nodeValue; // Fetch DOM Node property once.
+ return value == null ? super.toString() : value;
+ }
+
+ /**
+ * A list of this node's children.
+ *
+ * ## Other resources
+ *
+ * * [Node.childNodes](https://developer.mozilla.org/en-US/docs/Web/API/Node.childNodes)
+ * from MDN.
+ */
+ @Returns('NodeList')
+ @Creates('NodeList')
+ final List<Node> childNodes;
+
+ // To suppress missing implicit constructor warnings.
+ factory Node._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int ATTRIBUTE_NODE = 2;
+
+ static const int CDATA_SECTION_NODE = 4;
+
+ static const int COMMENT_NODE = 8;
+
+ static const int DOCUMENT_FRAGMENT_NODE = 11;
+
+ static const int DOCUMENT_NODE = 9;
+
+ static const int DOCUMENT_TYPE_NODE = 10;
+
+ static const int ELEMENT_NODE = 1;
+
+ static const int ENTITY_NODE = 6;
+
+ static const int ENTITY_REFERENCE_NODE = 5;
+
+ static const int NOTATION_NODE = 12;
+
+ static const int PROCESSING_INSTRUCTION_NODE = 7;
+
+ static const int TEXT_NODE = 3;
+
+ @JSName('baseURI')
+ final String baseUri;
+
+ /**
+ * The first child of this node.
+ *
+ * ## Other resources
+ *
+ * * [Node.firstChild](https://developer.mozilla.org/en-US/docs/Web/API/Node.firstChild)
+ * from MDN.
+ */
+ final Node firstChild;
+
+ final bool isConnected;
+
+ /**
+ * The last child of this node.
+ *
+ * ## Other resources
+ *
+ * * [Node.lastChild](https://developer.mozilla.org/en-US/docs/Web/API/Node.lastChild)
+ * from MDN.
+ */
+ final Node lastChild;
+
+ @JSName('nextSibling')
+ /**
+ * The next sibling node.
+ *
+ * ## Other resources
+ *
+ * * [Node.nextSibling](https://developer.mozilla.org/en-US/docs/Web/API/Node.nextSibling)
+ * from MDN.
+ */
+ final Node nextNode;
+
+ /**
+ * The name of this node.
+ *
+ * This varies by this node's [nodeType].
+ *
+ * ## Other resources
+ *
+ * * [Node.nodeName](https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeName)
+ * from MDN. This page contains a table of [nodeName] values for each
+ * [nodeType].
+ */
+ final String nodeName;
+
+ /**
+ * The type of node.
+ *
+ * This value is one of:
+ *
+ * * [ATTRIBUTE_NODE] if this node is an attribute.
+ * * [CDATA_SECTION_NODE] if this node is a [CDataSection].
+ * * [COMMENT_NODE] if this node is a [Comment].
+ * * [DOCUMENT_FRAGMENT_NODE] if this node is a [DocumentFragment].
+ * * [DOCUMENT_NODE] if this node is a [Document].
+ * * [DOCUMENT_TYPE_NODE] if this node is a [DocumentType] node.
+ * * [ELEMENT_NODE] if this node is an [Element].
+ * * [ENTITY_NODE] if this node is an entity.
+ * * [ENTITY_REFERENCE_NODE] if this node is an entity reference.
+ * * [NOTATION_NODE] if this node is a notation.
+ * * [PROCESSING_INSTRUCTION_NODE] if this node is a [ProcessingInstruction].
+ * * [TEXT_NODE] if this node is a [Text] node.
+ *
+ * ## Other resources
+ *
+ * * [Node.nodeType](https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType)
+ * from MDN.
+ */
+ final int nodeType;
+
+ /**
+ * The value of this node.
+ *
+ * This varies by this type's [nodeType].
+ *
+ * ## Other resources
+ *
+ * * [Node.nodeValue](https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeValue)
+ * from MDN. This page contains a table of [nodeValue] values for each
+ * [nodeType].
+ */
+ final String nodeValue;
+
+ /**
+ * The document this node belongs to.
+ *
+ * Returns null if this node does not belong to any document.
+ *
+ * ## Other resources
+ *
+ * * [Node.ownerDocument](https://developer.mozilla.org/en-US/docs/Web/API/Node.ownerDocument)
+ * from MDN.
+ */
+ final Document ownerDocument;
+
+ @JSName('parentElement')
+ /**
+ * The parent element of this node.
+ *
+ * Returns null if this node either does not have a parent or its parent is
+ * not an element.
+ *
+ * ## Other resources
+ *
+ * * [Node.parentElement](https://developer.mozilla.org/en-US/docs/Web/API/Node.parentElement)
+ * from W3C.
+ */
+ final Element parent;
+
+ /**
+ * The parent node of this node.
+ *
+ * ## Other resources
+ *
+ * * [Node.parentNode](https://developer.mozilla.org/en-US/docs/Web/API/Node.parentNode)
+ * from MDN.
+ */
+ final Node parentNode;
+
+ @JSName('previousSibling')
+ /**
+ * The previous sibling node.
+ *
+ * ## Other resources
+ *
+ * * [Node.previousSibling](https://developer.mozilla.org/en-US/docs/Web/API/Node.previousSibling)
+ * from MDN.
+ */
+ final Node previousNode;
+
+ @JSName('textContent')
+ /**
+ * All text within this node and its descendents.
+ *
+ * ## Other resources
+ *
+ * * [Node.textContent](https://developer.mozilla.org/en-US/docs/Web/API/Node.textContent)
+ * from MDN.
+ */
+ String text;
+
+ @JSName('appendChild')
+ /**
+ * Adds a node to the end of the child [nodes] list of this node.
+ *
+ * If the node already exists in this document, it will be removed from its
+ * current parent node, then added to this node.
+ *
+ * This method is more efficient than `nodes.add`, and is the preferred
+ * way of appending a child node.
+ */
+ Node append(Node node) native;
+
+ @JSName('cloneNode')
+ /**
+ * Returns a copy of this node.
+ *
+ * If [deep] is `true`, then all of this node's children and descendents are
+ * copied as well. If [deep] is `false`, then only this node is copied.
+ *
+ * ## Other resources
+ *
+ * * [Node.cloneNode](https://developer.mozilla.org/en-US/docs/Web/API/Node.cloneNode)
+ * from MDN.
+ */
+ Node clone(bool deep) native;
+
+ /**
+ * Returns true if this node contains the specified node.
+ *
+ * ## Other resources
+ *
+ * * [Node.contains](https://developer.mozilla.org/en-US/docs/Web/API/Node.contains)
+ * from MDN.
+ */
+ bool contains(Node other) native;
+
+ Node getRootNode([Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return _getRootNode_1(options_1);
+ }
+ return _getRootNode_2();
+ }
+
+ @JSName('getRootNode')
+ Node _getRootNode_1(options) native;
+ @JSName('getRootNode')
+ Node _getRootNode_2() native;
+
+ /**
+ * Returns true if this node has any children.
+ *
+ * ## Other resources
+ *
+ * * [Node.hasChildNodes](https://developer.mozilla.org/en-US/docs/Web/API/Node.hasChildNodes)
+ * from MDN.
+ */
+ bool hasChildNodes() native;
+
+ /**
+ * Inserts all of the nodes into this node directly before refChild.
+ *
+ * ## Other resources
+ *
+ * * [Node.insertBefore](https://developer.mozilla.org/en-US/docs/Web/API/Node.insertBefore)
+ * from MDN.
+ */
+ Node insertBefore(Node node, Node child) native;
+
+ @JSName('removeChild')
+ Node _removeChild(Node child) native;
+
+ @JSName('replaceChild')
+ Node _replaceChild(Node node, Node child) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("NodeFilter")
+class NodeFilter extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory NodeFilter._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int FILTER_ACCEPT = 1;
+
+ static const int FILTER_REJECT = 2;
+
+ static const int FILTER_SKIP = 3;
+
+ static const int SHOW_ALL = 0xFFFFFFFF;
+
+ static const int SHOW_COMMENT = 0x80;
+
+ static const int SHOW_DOCUMENT = 0x100;
+
+ static const int SHOW_DOCUMENT_FRAGMENT = 0x400;
+
+ static const int SHOW_DOCUMENT_TYPE = 0x200;
+
+ static const int SHOW_ELEMENT = 0x1;
+
+ static const int SHOW_PROCESSING_INSTRUCTION = 0x40;
+
+ static const int SHOW_TEXT = 0x4;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("NodeIterator")
+class NodeIterator extends Interceptor {
+ factory NodeIterator(Node root, int whatToShow) {
+ return document._createNodeIterator(root, whatToShow, null);
+ }
+ // To suppress missing implicit constructor warnings.
+ factory NodeIterator._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool pointerBeforeReferenceNode;
+
+ final Node referenceNode;
+
+ final Node root;
+
+ final int whatToShow;
+
+ void detach() native;
+
+ Node nextNode() native;
+
+ Node previousNode() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NodeList,RadioNodeList")
+class NodeList extends Interceptor
+ with ListMixin<Node>, ImmutableListMixin<Node>
+ implements JavaScriptIndexingBehavior<Node>, List<Node> {
+ // To suppress missing implicit constructor warnings.
+ factory NodeList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ Node operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("Node", "#[#]", this, index);
+ }
+
+ void operator []=(int index, Node value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<Node> mixins.
+ // Node is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ Node get first {
+ if (this.length > 0) {
+ return JS('Node', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ Node get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('Node', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ Node get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('Node', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ Node elementAt(int index) => this[index];
+ // -- end List<Node> mixins.
+
+ @JSName('item')
+ Node _item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NonDocumentTypeChildNode")
+class NonDocumentTypeChildNode extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory NonDocumentTypeChildNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Element nextElementSibling;
+
+ final Element previousElementSibling;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NonElementParentNode")
+class NonElementParentNode extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory NonElementParentNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Element getElementById(String elementId) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NoncedElement")
+class NoncedElement extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory NoncedElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String nonce;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Notification")
+class Notification extends EventTarget {
+ factory Notification(String title,
+ {String dir: null,
+ String body: null,
+ String lang: null,
+ String tag: null,
+ String icon: null}) {
+ var parsedOptions = {};
+ if (dir != null) parsedOptions['dir'] = dir;
+ if (body != null) parsedOptions['body'] = body;
+ if (lang != null) parsedOptions['lang'] = lang;
+ if (tag != null) parsedOptions['tag'] = tag;
+ if (icon != null) parsedOptions['icon'] = icon;
+ return Notification._factoryNotification(title, parsedOptions);
+ }
+ // To suppress missing implicit constructor warnings.
+ factory Notification._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `click` events to event
+ * handlers that are not necessarily instances of [Notification].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> clickEvent =
+ const EventStreamProvider<Event>('click');
+
+ /**
+ * Static factory designed to expose `close` events to event
+ * handlers that are not necessarily instances of [Notification].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> closeEvent =
+ const EventStreamProvider<Event>('close');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [Notification].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /**
+ * Static factory designed to expose `show` events to event
+ * handlers that are not necessarily instances of [Notification].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> showEvent =
+ const EventStreamProvider<Event>('show');
+
+ static Notification _factoryNotification(String title, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return Notification._create_1(title, options_1);
+ }
+ return Notification._create_2(title);
+ }
+
+ static Notification _create_1(title, options) =>
+ JS('Notification', 'new Notification(#,#)', title, options);
+ static Notification _create_2(title) =>
+ JS('Notification', 'new Notification(#)', title);
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => JS('bool', '!!(window.Notification)');
+
+ final List actions;
+
+ final String badge;
+
+ final String body;
+
+ @annotation_Creates_SerializedScriptValue
+ @annotation_Returns_SerializedScriptValue
+ final Object data;
+
+ final String dir;
+
+ final String icon;
+
+ final String image;
+
+ final String lang;
+
+ static final int maxActions;
+
+ static final String permission;
+
+ final bool renotify;
+
+ final bool requireInteraction;
+
+ final bool silent;
+
+ final String tag;
+
+ final int timestamp;
+
+ final String title;
+
+ final List<int> vibrate;
+
+ void close() native;
+
+ @JSName('requestPermission')
+ static Future _requestPermission(
+ [_NotificationPermissionCallback deprecatedCallback]) native;
+
+ @JSName('requestPermission')
+ static Future<String> requestPermission() {
+ var completer = new Completer<String>();
+ _requestPermission((value) {
+ completer.complete(value);
+ });
+ return completer.future;
+ }
+
+ /// Stream of `click` events handled by this [Notification].
+ Stream<Event> get onClick => clickEvent.forTarget(this);
+
+ /// Stream of `close` events handled by this [Notification].
+ Stream<Event> get onClose => closeEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [Notification].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `show` events handled by this [Notification].
+ Stream<Event> get onShow => showEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NotificationEvent")
+class NotificationEvent extends ExtendableEvent {
+ // To suppress missing implicit constructor warnings.
+ factory NotificationEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory NotificationEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return NotificationEvent._create_1(type, eventInitDict_1);
+ }
+ static NotificationEvent _create_1(type, eventInitDict) => JS(
+ 'NotificationEvent', 'new NotificationEvent(#,#)', type, eventInitDict);
+
+ final String action;
+
+ final Notification notification;
+
+ final String reply;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _NotificationPermissionCallback(String permission);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLOListElement")
+class OListElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory OListElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory OListElement() => JS(
+ 'returns:OListElement;creates:OListElement;new:true',
+ '#.createElement(#)',
+ document,
+ "ol");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ OListElement.created() : super.created();
+
+ bool reversed;
+
+ int start;
+
+ String type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.IE)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("HTMLObjectElement")
+class ObjectElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory ObjectElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ObjectElement() => document.createElement("object");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ObjectElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Element.isTagSupported('object');
+
+ WindowBase get contentWindow =>
+ _convertNativeToDart_Window(this._get_contentWindow);
+ @JSName('contentWindow')
+ @Creates('Window|=Object')
+ @Returns('Window|=Object')
+ final dynamic _get_contentWindow;
+
+ String data;
+
+ final FormElement form;
+
+ String height;
+
+ String name;
+
+ String type;
+
+ String useMap;
+
+ final String validationMessage;
+
+ final ValidityState validity;
+
+ String width;
+
+ final bool willValidate;
+
+ Node __getter__(String name) native;
+
+ void __setter__(String name, Node value) native;
+
+ bool checkValidity() native;
+
+ bool reportValidity() native;
+
+ void setCustomValidity(String error) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OffscreenCanvas")
+class OffscreenCanvas extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory OffscreenCanvas._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory OffscreenCanvas(int width, int height) {
+ return OffscreenCanvas._create_1(width, height);
+ }
+ static OffscreenCanvas _create_1(width, height) =>
+ JS('OffscreenCanvas', 'new OffscreenCanvas(#,#)', width, height);
+
+ int height;
+
+ int width;
+
+ Future<Blob> convertToBlob([Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture<Blob>(
+ JS("", "#.convertToBlob(#)", this, options_dict));
+ }
+
+ Object getContext(String contextType, [Map attributes]) {
+ if (attributes != null) {
+ var attributes_1 = convertDartToNative_Dictionary(attributes);
+ return _getContext_1(contextType, attributes_1);
+ }
+ return _getContext_2(contextType);
+ }
+
+ @JSName('getContext')
+ Object _getContext_1(contextType, attributes) native;
+ @JSName('getContext')
+ Object _getContext_2(contextType) native;
+
+ ImageBitmap transferToImageBitmap() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OffscreenCanvasRenderingContext2D")
+class OffscreenCanvasRenderingContext2D extends Interceptor
+ implements _CanvasPath {
+ // To suppress missing implicit constructor warnings.
+ factory OffscreenCanvasRenderingContext2D._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final OffscreenCanvas canvas;
+
+ String direction;
+
+ Object fillStyle;
+
+ String filter;
+
+ String font;
+
+ num globalAlpha;
+
+ String globalCompositeOperation;
+
+ bool imageSmoothingEnabled;
+
+ String imageSmoothingQuality;
+
+ String lineCap;
+
+ num lineDashOffset;
+
+ String lineJoin;
+
+ num lineWidth;
+
+ num miterLimit;
+
+ num shadowBlur;
+
+ String shadowColor;
+
+ num shadowOffsetX;
+
+ num shadowOffsetY;
+
+ Object strokeStyle;
+
+ String textAlign;
+
+ String textBaseline;
+
+ void beginPath() native;
+
+ void clearRect(num x, num y, num width, num height) native;
+
+ void clip([Path2D path]) native;
+
+ Future commit() => promiseToFuture(JS("", "#.commit()", this));
+
+ ImageData createImageData(data_OR_imagedata_OR_sw,
+ [int sh_OR_sw,
+ imageDataColorSettings_OR_sh,
+ Map imageDataColorSettings]) {
+ if ((data_OR_imagedata_OR_sw is ImageData) &&
+ sh_OR_sw == null &&
+ imageDataColorSettings_OR_sh == null &&
+ imageDataColorSettings == null) {
+ var imagedata_1 = convertDartToNative_ImageData(data_OR_imagedata_OR_sw);
+ return convertNativeToDart_ImageData(_createImageData_1(imagedata_1));
+ }
+ if (sh_OR_sw != null &&
+ (data_OR_imagedata_OR_sw is int) &&
+ imageDataColorSettings_OR_sh == null &&
+ imageDataColorSettings == null) {
+ return convertNativeToDart_ImageData(
+ _createImageData_2(data_OR_imagedata_OR_sw, sh_OR_sw));
+ }
+ if ((imageDataColorSettings_OR_sh is Map) &&
+ sh_OR_sw != null &&
+ (data_OR_imagedata_OR_sw is int) &&
+ imageDataColorSettings == null) {
+ var imageDataColorSettings_1 =
+ convertDartToNative_Dictionary(imageDataColorSettings_OR_sh);
+ return convertNativeToDart_ImageData(_createImageData_3(
+ data_OR_imagedata_OR_sw, sh_OR_sw, imageDataColorSettings_1));
+ }
+ if (imageDataColorSettings != null &&
+ (imageDataColorSettings_OR_sh is int) &&
+ sh_OR_sw != null &&
+ data_OR_imagedata_OR_sw != null) {
+ var imageDataColorSettings_1 =
+ convertDartToNative_Dictionary(imageDataColorSettings);
+ return convertNativeToDart_ImageData(_createImageData_4(
+ data_OR_imagedata_OR_sw,
+ sh_OR_sw,
+ imageDataColorSettings_OR_sh,
+ imageDataColorSettings_1));
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('createImageData')
+ _createImageData_1(imagedata) native;
+ @JSName('createImageData')
+ _createImageData_2(int sw, sh) native;
+ @JSName('createImageData')
+ _createImageData_3(int sw, sh, imageDataColorSettings) native;
+ @JSName('createImageData')
+ _createImageData_4(data, sw, int sh, imageDataColorSettings) native;
+
+ CanvasGradient createLinearGradient(num x0, num y0, num x1, num y1) native;
+
+ CanvasPattern createPattern(
+ /*CanvasImageSource*/ image, String repetitionType) native;
+
+ CanvasGradient createRadialGradient(
+ num x0, num y0, num r0, num x1, num y1, num r1) native;
+
+ void drawImage(/*CanvasImageSource*/ image, num sx_OR_x, num sy_OR_y,
+ [num sw_OR_width,
+ num height_OR_sh,
+ num dx,
+ num dy,
+ num dw,
+ num dh]) native;
+
+ void fill([path_OR_winding, String winding]) native;
+
+ void fillRect(num x, num y, num width, num height) native;
+
+ void fillText(String text, num x, num y, [num maxWidth]) native;
+
+ ImageData getImageData(int sx, int sy, int sw, int sh) {
+ return convertNativeToDart_ImageData(_getImageData_1(sx, sy, sw, sh));
+ }
+
+ @JSName('getImageData')
+ _getImageData_1(sx, sy, sw, sh) native;
+
+ List<num> getLineDash() native;
+
+ bool isPointInPath(path_OR_x, num x_OR_y, [winding_OR_y, String winding])
+ native;
+
+ bool isPointInStroke(path_OR_x, num x_OR_y, [num y]) native;
+
+ TextMetrics measureText(String text) native;
+
+ void putImageData(ImageData imagedata, int dx, int dy,
+ [int dirtyX, int dirtyY, int dirtyWidth, int dirtyHeight]) {
+ if (dirtyX == null &&
+ dirtyY == null &&
+ dirtyWidth == null &&
+ dirtyHeight == null) {
+ var imagedata_1 = convertDartToNative_ImageData(imagedata);
+ _putImageData_1(imagedata_1, dx, dy);
+ return;
+ }
+ if (dirtyHeight != null &&
+ dirtyWidth != null &&
+ dirtyY != null &&
+ dirtyX != null) {
+ var imagedata_1 = convertDartToNative_ImageData(imagedata);
+ _putImageData_2(
+ imagedata_1, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('putImageData')
+ void _putImageData_1(imagedata, dx, dy) native;
+ @JSName('putImageData')
+ void _putImageData_2(
+ imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) native;
+
+ void resetTransform() native;
+
+ void restore() native;
+
+ void rotate(num angle) native;
+
+ void save() native;
+
+ void scale(num x, num y) native;
+
+ void setLineDash(List<num> dash) native;
+
+ void setTransform(num a, num b, num c, num d, num e, num f) native;
+
+ void stroke([Path2D path]) native;
+
+ void strokeRect(num x, num y, num width, num height) native;
+
+ void strokeText(String text, num x, num y, [num maxWidth]) native;
+
+ void transform(num a, num b, num c, num d, num e, num f) native;
+
+ void translate(num x, num y) native;
+
+ // From CanvasPath
+
+ void arc(num x, num y, num radius, num startAngle, num endAngle,
+ bool anticlockwise) native;
+
+ void arcTo(num x1, num y1, num x2, num y2, num radius) native;
+
+ void bezierCurveTo(num cp1x, num cp1y, num cp2x, num cp2y, num x, num y)
+ native;
+
+ void closePath() native;
+
+ void ellipse(num x, num y, num radiusX, num radiusY, num rotation,
+ num startAngle, num endAngle, bool anticlockwise) native;
+
+ void lineTo(num x, num y) native;
+
+ void moveTo(num x, num y) native;
+
+ void quadraticCurveTo(num cpx, num cpy, num x, num y) native;
+
+ void rect(num x, num y, num width, num height) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLOptGroupElement")
+class OptGroupElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory OptGroupElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory OptGroupElement() => JS(
+ 'returns:OptGroupElement;creates:OptGroupElement;new:true',
+ '#.createElement(#)',
+ document,
+ "optgroup");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ OptGroupElement.created() : super.created();
+
+ bool disabled;
+
+ String label;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLOptionElement")
+class OptionElement extends HtmlElement {
+ factory OptionElement(
+ {String data: '', String value: '', bool selected: false}) {
+ return new OptionElement._(data, value, null, selected);
+ }
+
+ factory OptionElement._(
+ [String data, String value, bool defaultSelected, bool selected]) {
+ if (selected != null) {
+ return OptionElement._create_1(data, value, defaultSelected, selected);
+ }
+ if (defaultSelected != null) {
+ return OptionElement._create_2(data, value, defaultSelected);
+ }
+ if (value != null) {
+ return OptionElement._create_3(data, value);
+ }
+ if (data != null) {
+ return OptionElement._create_4(data);
+ }
+ return OptionElement._create_5();
+ }
+ static OptionElement _create_1(data, value, defaultSelected, selected) => JS(
+ 'OptionElement',
+ 'new Option(#,#,#,#)',
+ data,
+ value,
+ defaultSelected,
+ selected);
+ static OptionElement _create_2(data, value, defaultSelected) =>
+ JS('OptionElement', 'new Option(#,#,#)', data, value, defaultSelected);
+ static OptionElement _create_3(data, value) =>
+ JS('OptionElement', 'new Option(#,#)', data, value);
+ static OptionElement _create_4(data) =>
+ JS('OptionElement', 'new Option(#)', data);
+ static OptionElement _create_5() => JS('OptionElement', 'new Option()');
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ OptionElement.created() : super.created();
+
+ bool defaultSelected;
+
+ bool disabled;
+
+ final FormElement form;
+
+ final int index;
+
+ String label;
+
+ bool selected;
+
+ String value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OrientationSensor")
+class OrientationSensor extends Sensor {
+ // To suppress missing implicit constructor warnings.
+ factory OrientationSensor._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final List<num> quaternion;
+
+ void populateMatrix(Object targetBuffer) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("HTMLOutputElement")
+class OutputElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory OutputElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory OutputElement() => document.createElement("output");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ OutputElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Element.isTagSupported('output');
+
+ String defaultValue;
+
+ final FormElement form;
+
+ final DomTokenList htmlFor;
+
+ @Unstable()
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ final List<Node> labels;
+
+ String name;
+
+ final String type;
+
+ final String validationMessage;
+
+ final ValidityState validity;
+
+ String value;
+
+ final bool willValidate;
+
+ bool checkValidity() native;
+
+ bool reportValidity() native;
+
+ void setCustomValidity(String error) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OverconstrainedError")
+class OverconstrainedError extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory OverconstrainedError._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory OverconstrainedError(String constraint, String message) {
+ return OverconstrainedError._create_1(constraint, message);
+ }
+ static OverconstrainedError _create_1(constraint, message) => JS(
+ 'OverconstrainedError',
+ 'new OverconstrainedError(#,#)',
+ constraint,
+ message);
+
+ final String constraint;
+
+ final String message;
+
+ final String name;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PageTransitionEvent")
+class PageTransitionEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory PageTransitionEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PageTransitionEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return PageTransitionEvent._create_1(type, eventInitDict_1);
+ }
+ return PageTransitionEvent._create_2(type);
+ }
+ static PageTransitionEvent _create_1(type, eventInitDict) => JS(
+ 'PageTransitionEvent',
+ 'new PageTransitionEvent(#,#)',
+ type,
+ eventInitDict);
+ static PageTransitionEvent _create_2(type) =>
+ JS('PageTransitionEvent', 'new PageTransitionEvent(#)', type);
+
+ final bool persisted;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaintRenderingContext2D")
+class PaintRenderingContext2D extends Interceptor implements _CanvasPath {
+ // To suppress missing implicit constructor warnings.
+ factory PaintRenderingContext2D._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Matrix currentTransform;
+
+ Object fillStyle;
+
+ String filter;
+
+ num globalAlpha;
+
+ String globalCompositeOperation;
+
+ bool imageSmoothingEnabled;
+
+ String imageSmoothingQuality;
+
+ String lineCap;
+
+ num lineDashOffset;
+
+ String lineJoin;
+
+ num lineWidth;
+
+ num miterLimit;
+
+ num shadowBlur;
+
+ String shadowColor;
+
+ num shadowOffsetX;
+
+ num shadowOffsetY;
+
+ Object strokeStyle;
+
+ void beginPath() native;
+
+ void clearRect(num x, num y, num width, num height) native;
+
+ void clip([path_OR_winding, String winding]) native;
+
+ CanvasGradient createLinearGradient(num x0, num y0, num x1, num y1) native;
+
+ CanvasPattern createPattern(
+ /*CanvasImageSource*/ image, String repetitionType) native;
+
+ CanvasGradient createRadialGradient(
+ num x0, num y0, num r0, num x1, num y1, num r1) native;
+
+ void drawImage(/*CanvasImageSource*/ image, num sx_OR_x, num sy_OR_y,
+ [num sw_OR_width,
+ num height_OR_sh,
+ num dx,
+ num dy,
+ num dw,
+ num dh]) native;
+
+ void fill([path_OR_winding, String winding]) native;
+
+ void fillRect(num x, num y, num width, num height) native;
+
+ List<num> getLineDash() native;
+
+ bool isPointInPath(path_OR_x, num x_OR_y, [winding_OR_y, String winding])
+ native;
+
+ bool isPointInStroke(path_OR_x, num x_OR_y, [num y]) native;
+
+ void resetTransform() native;
+
+ void restore() native;
+
+ void rotate(num angle) native;
+
+ void save() native;
+
+ void scale(num x, num y) native;
+
+ void setLineDash(List<num> dash) native;
+
+ void setTransform(num a, num b, num c, num d, num e, num f) native;
+
+ void stroke([Path2D path]) native;
+
+ void strokeRect(num x, num y, num width, num height) native;
+
+ void transform(num a, num b, num c, num d, num e, num f) native;
+
+ void translate(num x, num y) native;
+
+ // From CanvasPath
+
+ void arc(num x, num y, num radius, num startAngle, num endAngle,
+ bool anticlockwise) native;
+
+ void arcTo(num x1, num y1, num x2, num y2, num radius) native;
+
+ void bezierCurveTo(num cp1x, num cp1y, num cp2x, num cp2y, num x, num y)
+ native;
+
+ void closePath() native;
+
+ void ellipse(num x, num y, num radiusX, num radiusY, num rotation,
+ num startAngle, num endAngle, bool anticlockwise) native;
+
+ void lineTo(num x, num y) native;
+
+ void moveTo(num x, num y) native;
+
+ void quadraticCurveTo(num cpx, num cpy, num x, num y) native;
+
+ void rect(num x, num y, num width, num height) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaintSize")
+class PaintSize extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PaintSize._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num height;
+
+ final num width;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaintWorkletGlobalScope")
+class PaintWorkletGlobalScope extends WorkletGlobalScope {
+ // To suppress missing implicit constructor warnings.
+ factory PaintWorkletGlobalScope._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num devicePixelRatio;
+
+ void registerPaint(String name, Object paintCtor) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLParagraphElement")
+class ParagraphElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory ParagraphElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ParagraphElement() => JS(
+ 'returns:ParagraphElement;creates:ParagraphElement;new:true',
+ '#.createElement(#)',
+ document,
+ "p");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ParagraphElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("HTMLParamElement")
+class ParamElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory ParamElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ParamElement() => JS(
+ 'returns:ParamElement;creates:ParamElement;new:true',
+ '#.createElement(#)',
+ document,
+ "param");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ParamElement.created() : super.created();
+
+ String name;
+
+ String value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class ParentNode extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ParentNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int _childElementCount;
+
+ final List<Node> _children;
+
+ final Element _firstElementChild;
+
+ final Element _lastElementChild;
+
+ Element querySelector(String selectors);
+
+ List<Node> _querySelectorAll(String selectors);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PasswordCredential")
+class PasswordCredential extends Credential implements CredentialUserData {
+ // To suppress missing implicit constructor warnings.
+ factory PasswordCredential._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PasswordCredential(data_OR_form) {
+ if ((data_OR_form is Map)) {
+ var data_1 = convertDartToNative_Dictionary(data_OR_form);
+ return PasswordCredential._create_1(data_1);
+ }
+ if ((data_OR_form is FormElement)) {
+ return PasswordCredential._create_2(data_OR_form);
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+ static PasswordCredential _create_1(data_OR_form) =>
+ JS('PasswordCredential', 'new PasswordCredential(#)', data_OR_form);
+ static PasswordCredential _create_2(data_OR_form) =>
+ JS('PasswordCredential', 'new PasswordCredential(#)', data_OR_form);
+
+ Object additionalData;
+
+ String idName;
+
+ final String password;
+
+ String passwordName;
+
+ // From CredentialUserData
+
+ @JSName('iconURL')
+ final String iconUrl;
+
+ final String name;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Path2D")
+class Path2D extends Interceptor implements _CanvasPath {
+ // To suppress missing implicit constructor warnings.
+ factory Path2D._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory Path2D([path_OR_text]) {
+ if (path_OR_text == null) {
+ return Path2D._create_1();
+ }
+ if ((path_OR_text is Path2D)) {
+ return Path2D._create_2(path_OR_text);
+ }
+ if ((path_OR_text is String)) {
+ return Path2D._create_3(path_OR_text);
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+ static Path2D _create_1() => JS('Path2D', 'new Path2D()');
+ static Path2D _create_2(path_OR_text) =>
+ JS('Path2D', 'new Path2D(#)', path_OR_text);
+ static Path2D _create_3(path_OR_text) =>
+ JS('Path2D', 'new Path2D(#)', path_OR_text);
+
+ void addPath(Path2D path, [Matrix transform]) native;
+
+ // From CanvasPath
+
+ void arc(num x, num y, num radius, num startAngle, num endAngle,
+ bool anticlockwise) native;
+
+ void arcTo(num x1, num y1, num x2, num y2, num radius) native;
+
+ void bezierCurveTo(num cp1x, num cp1y, num cp2x, num cp2y, num x, num y)
+ native;
+
+ void closePath() native;
+
+ void ellipse(num x, num y, num radiusX, num radiusY, num rotation,
+ num startAngle, num endAngle, bool anticlockwise) native;
+
+ void lineTo(num x, num y) native;
+
+ void moveTo(num x, num y) native;
+
+ void quadraticCurveTo(num cpx, num cpy, num x, num y) native;
+
+ void rect(num x, num y, num width, num height) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentAddress")
+class PaymentAddress extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PaymentAddress._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final List<String> addressLine;
+
+ final String city;
+
+ final String country;
+
+ final String dependentLocality;
+
+ final String languageCode;
+
+ final String organization;
+
+ final String phone;
+
+ final String postalCode;
+
+ final String recipient;
+
+ final String region;
+
+ final String sortingCode;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentInstruments")
+class PaymentInstruments extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PaymentInstruments._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future clear() => promiseToFuture(JS("", "#.clear()", this));
+
+ Future<bool> delete(String instrumentKey) =>
+ promiseToFuture<bool>(JS("", "#.delete(#)", this, instrumentKey));
+
+ Future<Map<String, dynamic>> get(String instrumentKey) =>
+ promiseToFutureAsMap(JS("", "#.get(#)", this, instrumentKey));
+
+ Future has(String instrumentKey) =>
+ promiseToFuture(JS("", "#.has(#)", this, instrumentKey));
+
+ Future<List<String>> keys() =>
+ promiseToFuture<List<String>>(JS("", "#.keys()", this));
+
+ Future set(String instrumentKey, Map details) {
+ var details_dict = convertDartToNative_Dictionary(details);
+ return promiseToFuture(
+ JS("", "#.set(#, #)", this, instrumentKey, details_dict));
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentManager")
+class PaymentManager extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PaymentManager._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final PaymentInstruments instruments;
+
+ String userHint;
+}
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentRequest")
+class PaymentRequest extends EventTarget {
+ factory PaymentRequest(List<Map> methodData, Map details, [Map options]) {
+ var methodData_1 = [];
+ for (var i in methodData) {
+ methodData_1.add(convertDartToNative_Dictionary(i));
+ }
+ if (options != null) {
+ var details_1 = convertDartToNative_Dictionary(details);
+ var options_2 = convertDartToNative_Dictionary(options);
+ return PaymentRequest._create_1(methodData_1, details_1, options_2);
+ }
+ var details_1 = convertDartToNative_Dictionary(details);
+ return PaymentRequest._create_2(methodData_1, details_1);
+ }
+
+ static PaymentRequest _create_1(methodData, details, options) => JS(
+ 'PaymentRequest',
+ 'new PaymentRequest(#,#,#)',
+ methodData,
+ details,
+ options);
+ static PaymentRequest _create_2(methodData, details) =>
+ JS('PaymentRequest', 'new PaymentRequest(#,#)', methodData, details);
+
+ // To suppress missing implicit constructor warnings.
+ factory PaymentRequest._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String id;
+
+ final PaymentAddress shippingAddress;
+
+ final String shippingOption;
+
+ final String shippingType;
+
+ Future abort() => promiseToFuture(JS("", "#.abort()", this));
+
+ Future<bool> canMakePayment() =>
+ promiseToFuture<bool>(JS("", "#.canMakePayment()", this));
+
+ Future<PaymentResponse> show() =>
+ promiseToFuture<PaymentResponse>(JS("", "#.show()", this));
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentRequestEvent")
+class PaymentRequestEvent extends ExtendableEvent {
+ // To suppress missing implicit constructor warnings.
+ factory PaymentRequestEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PaymentRequestEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return PaymentRequestEvent._create_1(type, eventInitDict_1);
+ }
+ static PaymentRequestEvent _create_1(type, eventInitDict) => JS(
+ 'PaymentRequestEvent',
+ 'new PaymentRequestEvent(#,#)',
+ type,
+ eventInitDict);
+
+ final String instrumentKey;
+
+ final List methodData;
+
+ final List modifiers;
+
+ final String paymentRequestId;
+
+ final String paymentRequestOrigin;
+
+ final String topLevelOrigin;
+
+ final Object total;
+
+ Future<WindowClient> openWindow(String url) =>
+ promiseToFuture<WindowClient>(JS("", "#.openWindow(#)", this, url));
+
+ void respondWith(Future response) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentRequestUpdateEvent")
+class PaymentRequestUpdateEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory PaymentRequestUpdateEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PaymentRequestUpdateEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return PaymentRequestUpdateEvent._create_1(type, eventInitDict_1);
+ }
+ return PaymentRequestUpdateEvent._create_2(type);
+ }
+ static PaymentRequestUpdateEvent _create_1(type, eventInitDict) => JS(
+ 'PaymentRequestUpdateEvent',
+ 'new PaymentRequestUpdateEvent(#,#)',
+ type,
+ eventInitDict);
+ static PaymentRequestUpdateEvent _create_2(type) =>
+ JS('PaymentRequestUpdateEvent', 'new PaymentRequestUpdateEvent(#)', type);
+
+ void updateWith(Future detailsPromise) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PaymentResponse")
+class PaymentResponse extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PaymentResponse._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Object details;
+
+ final String methodName;
+
+ final String payerEmail;
+
+ final String payerName;
+
+ final String payerPhone;
+
+ final String requestId;
+
+ final PaymentAddress shippingAddress;
+
+ final String shippingOption;
+
+ Future complete([String paymentResult]) =>
+ promiseToFuture(JS("", "#.complete(#)", this, paymentResult));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE)
+@Native("Performance")
+class Performance extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory Performance._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => JS('bool', '!!(window.performance)');
+
+ final MemoryInfo memory;
+
+ final PerformanceNavigation navigation;
+
+ final num timeOrigin;
+
+ final PerformanceTiming timing;
+
+ void clearMarks(String markName) native;
+
+ void clearMeasures(String measureName) native;
+
+ void clearResourceTimings() native;
+
+ List<PerformanceEntry> getEntries() native;
+
+ List<PerformanceEntry> getEntriesByName(String name, String entryType) native;
+
+ List<PerformanceEntry> getEntriesByType(String entryType) native;
+
+ void mark(String markName) native;
+
+ void measure(String measureName, String startMark, String endMark) native;
+
+ double now() native;
+
+ void setResourceTimingBufferSize(int maxSize) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceEntry")
+class PerformanceEntry extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PerformanceEntry._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num duration;
+
+ final String entryType;
+
+ final String name;
+
+ final num startTime;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceLongTaskTiming")
+class PerformanceLongTaskTiming extends PerformanceEntry {
+ // To suppress missing implicit constructor warnings.
+ factory PerformanceLongTaskTiming._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final List<TaskAttributionTiming> attribution;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceMark")
+class PerformanceMark extends PerformanceEntry {
+ // To suppress missing implicit constructor warnings.
+ factory PerformanceMark._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceMeasure")
+class PerformanceMeasure extends PerformanceEntry {
+ // To suppress missing implicit constructor warnings.
+ factory PerformanceMeasure._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("PerformanceNavigation")
+class PerformanceNavigation extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PerformanceNavigation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int TYPE_BACK_FORWARD = 2;
+
+ static const int TYPE_NAVIGATE = 0;
+
+ static const int TYPE_RELOAD = 1;
+
+ static const int TYPE_RESERVED = 255;
+
+ final int redirectCount;
+
+ final int type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceNavigationTiming")
+class PerformanceNavigationTiming extends PerformanceResourceTiming {
+ // To suppress missing implicit constructor warnings.
+ factory PerformanceNavigationTiming._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num domComplete;
+
+ final num domContentLoadedEventEnd;
+
+ final num domContentLoadedEventStart;
+
+ final num domInteractive;
+
+ final num loadEventEnd;
+
+ final num loadEventStart;
+
+ final int redirectCount;
+
+ final String type;
+
+ final num unloadEventEnd;
+
+ final num unloadEventStart;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceObserver")
+class PerformanceObserver extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PerformanceObserver._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PerformanceObserver(PerformanceObserverCallback callback) {
+ var callback_1 = convertDartClosureToJS(callback, 2);
+ return PerformanceObserver._create_1(callback_1);
+ }
+ static PerformanceObserver _create_1(callback) =>
+ JS('PerformanceObserver', 'new PerformanceObserver(#)', callback);
+
+ void disconnect() native;
+
+ void observe(Map options) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ _observe_1(options_1);
+ return;
+ }
+
+ @JSName('observe')
+ void _observe_1(options) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void PerformanceObserverCallback(
+ PerformanceObserverEntryList entries, PerformanceObserver observer);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceObserverEntryList")
+class PerformanceObserverEntryList extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PerformanceObserverEntryList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ List<PerformanceEntry> getEntries() native;
+
+ List<PerformanceEntry> getEntriesByName(String name, String entryType) native;
+
+ List<PerformanceEntry> getEntriesByType(String entryType) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformancePaintTiming")
+class PerformancePaintTiming extends PerformanceEntry {
+ // To suppress missing implicit constructor warnings.
+ factory PerformancePaintTiming._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceResourceTiming")
+class PerformanceResourceTiming extends PerformanceEntry {
+ // To suppress missing implicit constructor warnings.
+ factory PerformanceResourceTiming._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num connectEnd;
+
+ final num connectStart;
+
+ final int decodedBodySize;
+
+ final num domainLookupEnd;
+
+ final num domainLookupStart;
+
+ final int encodedBodySize;
+
+ final num fetchStart;
+
+ final String initiatorType;
+
+ final String nextHopProtocol;
+
+ final num redirectEnd;
+
+ final num redirectStart;
+
+ final num requestStart;
+
+ final num responseEnd;
+
+ final num responseStart;
+
+ final num secureConnectionStart;
+
+ final List<PerformanceServerTiming> serverTiming;
+
+ final int transferSize;
+
+ final num workerStart;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PerformanceServerTiming")
+class PerformanceServerTiming extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PerformanceServerTiming._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String description;
+
+ final num duration;
+
+ final String name;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("PerformanceTiming")
+class PerformanceTiming extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PerformanceTiming._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int connectEnd;
+
+ final int connectStart;
+
+ final int domComplete;
+
+ final int domContentLoadedEventEnd;
+
+ final int domContentLoadedEventStart;
+
+ final int domInteractive;
+
+ final int domLoading;
+
+ final int domainLookupEnd;
+
+ final int domainLookupStart;
+
+ final int fetchStart;
+
+ final int loadEventEnd;
+
+ final int loadEventStart;
+
+ final int navigationStart;
+
+ final int redirectEnd;
+
+ final int redirectStart;
+
+ final int requestStart;
+
+ final int responseEnd;
+
+ final int responseStart;
+
+ final int secureConnectionStart;
+
+ final int unloadEventEnd;
+
+ final int unloadEventStart;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PermissionStatus")
+class PermissionStatus extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory PermissionStatus._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> changeEvent =
+ const EventStreamProvider<Event>('change');
+
+ final String state;
+
+ Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Permissions")
+class Permissions extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Permissions._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future<PermissionStatus> query(Map permission) {
+ var permission_dict = convertDartToNative_Dictionary(permission);
+ return promiseToFuture<PermissionStatus>(
+ JS("", "#.query(#)", this, permission_dict));
+ }
+
+ Future<PermissionStatus> request(Map permissions) {
+ var permissions_dict = convertDartToNative_Dictionary(permissions);
+ return promiseToFuture<PermissionStatus>(
+ JS("", "#.request(#)", this, permissions_dict));
+ }
+
+ Future<PermissionStatus> requestAll(List<Map> permissions) =>
+ promiseToFuture<PermissionStatus>(
+ JS("", "#.requestAll(#)", this, permissions));
+
+ Future<PermissionStatus> revoke(Map permission) {
+ var permission_dict = convertDartToNative_Dictionary(permission);
+ return promiseToFuture<PermissionStatus>(
+ JS("", "#.revoke(#)", this, permission_dict));
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PhotoCapabilities")
+class PhotoCapabilities extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PhotoCapabilities._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final List fillLightMode;
+
+ final MediaSettingsRange imageHeight;
+
+ final MediaSettingsRange imageWidth;
+
+ final String redEyeReduction;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLPictureElement")
+class PictureElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory PictureElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ PictureElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Plugin")
+class Plugin extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Plugin._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String description;
+
+ final String filename;
+
+ final int length;
+
+ final String name;
+
+ MimeType item(int index) native;
+
+ MimeType namedItem(String name) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PluginArray")
+class PluginArray extends Interceptor
+ with ListMixin<Plugin>, ImmutableListMixin<Plugin>
+ implements JavaScriptIndexingBehavior<Plugin>, List<Plugin> {
+ // To suppress missing implicit constructor warnings.
+ factory PluginArray._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ Plugin operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("Plugin", "#[#]", this, index);
+ }
+
+ void operator []=(int index, Plugin value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<Plugin> mixins.
+ // Plugin is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ Plugin get first {
+ if (this.length > 0) {
+ return JS('Plugin', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ Plugin get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('Plugin', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ Plugin get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('Plugin', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ Plugin elementAt(int index) => this[index];
+ // -- end List<Plugin> mixins.
+
+ Plugin item(int index) native;
+
+ Plugin namedItem(String name) native;
+
+ void refresh(bool reload) native;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("PointerEvent")
+class PointerEvent extends MouseEvent {
+ // To suppress missing implicit constructor warnings.
+ factory PointerEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PointerEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return PointerEvent._create_1(type, eventInitDict_1);
+ }
+ return PointerEvent._create_2(type);
+ }
+ static PointerEvent _create_1(type, eventInitDict) =>
+ JS('PointerEvent', 'new PointerEvent(#,#)', type, eventInitDict);
+ static PointerEvent _create_2(type) =>
+ JS('PointerEvent', 'new PointerEvent(#)', type);
+
+ final num height;
+
+ final bool isPrimary;
+
+ final int pointerId;
+
+ final String pointerType;
+
+ final num pressure;
+
+ final num tangentialPressure;
+
+ final int tiltX;
+
+ final int tiltY;
+
+ final int twist;
+
+ final num width;
+
+ List<PointerEvent> getCoalescedEvents() native;
+
+ /**
+ * PointerEvent used for both touch and mouse. To check if touch is supported
+ * call the property TouchEvent.supported
+ */
+ static bool get supported {
+ try {
+ return PointerEvent('pointerover') is PointerEvent;
+ } catch (_) {}
+ return false;
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("PopStateEvent")
+class PopStateEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory PopStateEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PopStateEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return PopStateEvent._create_1(type, eventInitDict_1);
+ }
+ return PopStateEvent._create_2(type);
+ }
+ static PopStateEvent _create_1(type, eventInitDict) =>
+ JS('PopStateEvent', 'new PopStateEvent(#,#)', type, eventInitDict);
+ static PopStateEvent _create_2(type) =>
+ JS('PopStateEvent', 'new PopStateEvent(#)', type);
+
+ dynamic get state =>
+ convertNativeToDart_SerializedScriptValue(this._get_state);
+ @JSName('state')
+ @annotation_Creates_SerializedScriptValue
+ @annotation_Returns_SerializedScriptValue
+ final dynamic _get_state;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Unstable()
+typedef void _PositionCallback(Geoposition position);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("PositionError")
+class PositionError extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PositionError._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int PERMISSION_DENIED = 1;
+
+ static const int POSITION_UNAVAILABLE = 2;
+
+ static const int TIMEOUT = 3;
+
+ final int code;
+
+ final String message;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Unstable()
+typedef void _PositionErrorCallback(PositionError error);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLPreElement")
+class PreElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory PreElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PreElement() => JS('returns:PreElement;creates:PreElement;new:true',
+ '#.createElement(#)', document, "pre");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ PreElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Presentation")
+class Presentation extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Presentation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ PresentationRequest defaultRequest;
+
+ final PresentationReceiver receiver;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationAvailability")
+class PresentationAvailability extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory PresentationAvailability._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> changeEvent =
+ const EventStreamProvider<Event>('change');
+
+ final bool value;
+
+ Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationConnection")
+class PresentationConnection extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory PresentationConnection._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ String binaryType;
+
+ final String id;
+
+ final String state;
+
+ final String url;
+
+ void close() native;
+
+ void send(data_OR_message) native;
+
+ void terminate() native;
+
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationConnectionAvailableEvent")
+class PresentationConnectionAvailableEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory PresentationConnectionAvailableEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PresentationConnectionAvailableEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return PresentationConnectionAvailableEvent._create_1(
+ type, eventInitDict_1);
+ }
+ static PresentationConnectionAvailableEvent _create_1(type, eventInitDict) =>
+ JS('PresentationConnectionAvailableEvent',
+ 'new PresentationConnectionAvailableEvent(#,#)', type, eventInitDict);
+
+ final PresentationConnection connection;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationConnectionCloseEvent")
+class PresentationConnectionCloseEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory PresentationConnectionCloseEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PresentationConnectionCloseEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return PresentationConnectionCloseEvent._create_1(type, eventInitDict_1);
+ }
+ static PresentationConnectionCloseEvent _create_1(type, eventInitDict) => JS(
+ 'PresentationConnectionCloseEvent',
+ 'new PresentationConnectionCloseEvent(#,#)',
+ type,
+ eventInitDict);
+
+ final String message;
+
+ final String reason;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationConnectionList")
+class PresentationConnectionList extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory PresentationConnectionList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final List<PresentationConnection> connections;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationReceiver")
+class PresentationReceiver extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PresentationReceiver._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future<PresentationConnectionList> get connectionList =>
+ promiseToFuture<PresentationConnectionList>(
+ JS("", "#.connectionList", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PresentationRequest")
+class PresentationRequest extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory PresentationRequest._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PresentationRequest(url_OR_urls) {
+ if ((url_OR_urls is String)) {
+ return PresentationRequest._create_1(url_OR_urls);
+ }
+ if ((url_OR_urls is List<String>)) {
+ List urls_1 = convertDartToNative_StringArray(url_OR_urls);
+ return PresentationRequest._create_2(urls_1);
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+ static PresentationRequest _create_1(url_OR_urls) =>
+ JS('PresentationRequest', 'new PresentationRequest(#)', url_OR_urls);
+ static PresentationRequest _create_2(url_OR_urls) =>
+ JS('PresentationRequest', 'new PresentationRequest(#)', url_OR_urls);
+
+ Future<PresentationAvailability> getAvailability() =>
+ promiseToFuture<PresentationAvailability>(
+ JS("", "#.getAvailability()", this));
+
+ Future<PresentationConnection> reconnect(String id) =>
+ promiseToFuture<PresentationConnection>(
+ JS("", "#.reconnect(#)", this, id));
+
+ Future<PresentationConnection> start() =>
+ promiseToFuture<PresentationConnection>(JS("", "#.start()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("ProcessingInstruction")
+class ProcessingInstruction extends CharacterData {
+ // To suppress missing implicit constructor warnings.
+ factory ProcessingInstruction._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final StyleSheet sheet;
+
+ final String target;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("HTMLProgressElement")
+class ProgressElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory ProgressElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ProgressElement() => document.createElement("progress");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ProgressElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Element.isTagSupported('progress');
+
+ @Unstable()
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ final List<Node> labels;
+
+ num max;
+
+ final num position;
+
+ num value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ProgressEvent")
+class ProgressEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory ProgressEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ProgressEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return ProgressEvent._create_1(type, eventInitDict_1);
+ }
+ return ProgressEvent._create_2(type);
+ }
+ static ProgressEvent _create_1(type, eventInitDict) =>
+ JS('ProgressEvent', 'new ProgressEvent(#,#)', type, eventInitDict);
+ static ProgressEvent _create_2(type) =>
+ JS('ProgressEvent', 'new ProgressEvent(#)', type);
+
+ final bool lengthComputable;
+
+ final int loaded;
+
+ final int total;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PromiseRejectionEvent")
+class PromiseRejectionEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory PromiseRejectionEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PromiseRejectionEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return PromiseRejectionEvent._create_1(type, eventInitDict_1);
+ }
+ static PromiseRejectionEvent _create_1(type, eventInitDict) => JS(
+ 'PromiseRejectionEvent',
+ 'new PromiseRejectionEvent(#,#)',
+ type,
+ eventInitDict);
+
+ Future get promise => promiseToFuture(JS("", "#.promise", this));
+
+ final Object reason;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PublicKeyCredential")
+class PublicKeyCredential extends Credential {
+ // To suppress missing implicit constructor warnings.
+ factory PublicKeyCredential._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final ByteBuffer rawId;
+
+ final AuthenticatorResponse response;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PushEvent")
+class PushEvent extends ExtendableEvent {
+ // To suppress missing implicit constructor warnings.
+ factory PushEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PushEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return PushEvent._create_1(type, eventInitDict_1);
+ }
+ return PushEvent._create_2(type);
+ }
+ static PushEvent _create_1(type, eventInitDict) =>
+ JS('PushEvent', 'new PushEvent(#,#)', type, eventInitDict);
+ static PushEvent _create_2(type) => JS('PushEvent', 'new PushEvent(#)', type);
+
+ final PushMessageData data;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PushManager")
+class PushManager extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PushManager._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static final List<String> supportedContentEncodings;
+
+ Future<PushSubscription> getSubscription() =>
+ promiseToFuture<PushSubscription>(JS("", "#.getSubscription()", this));
+
+ Future permissionState([Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture(JS("", "#.permissionState(#)", this, options_dict));
+ }
+
+ Future<PushSubscription> subscribe([Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture<PushSubscription>(
+ JS("", "#.subscribe(#)", this, options_dict));
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PushMessageData")
+class PushMessageData extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PushMessageData._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ ByteBuffer arrayBuffer() native;
+
+ Blob blob() native;
+
+ Object json() native;
+
+ String text() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PushSubscription")
+class PushSubscription extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PushSubscription._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String endpoint;
+
+ final int expirationTime;
+
+ final PushSubscriptionOptions options;
+
+ ByteBuffer getKey(String name) native;
+
+ Future<bool> unsubscribe() =>
+ promiseToFuture<bool>(JS("", "#.unsubscribe()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PushSubscriptionOptions")
+class PushSubscriptionOptions extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PushSubscriptionOptions._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final ByteBuffer applicationServerKey;
+
+ final bool userVisibleOnly;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLQuoteElement")
+class QuoteElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory QuoteElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory QuoteElement() => JS(
+ 'returns:QuoteElement;creates:QuoteElement;new:true',
+ '#.createElement(#)',
+ document,
+ "q");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ QuoteElement.created() : super.created();
+
+ String cite;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void RtcPeerConnectionErrorCallback(DomException exception);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void _RtcSessionDescriptionCallback(RtcSessionDescription sdp);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void RtcStatsCallback(RtcStatsResponse response);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Unstable()
+@Native("Range")
+class Range extends Interceptor {
+ factory Range() => document.createRange();
+
+ factory Range.fromPoint(Point point) =>
+ document._caretRangeFromPoint(point.x, point.y);
+ // To suppress missing implicit constructor warnings.
+ factory Range._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int END_TO_END = 2;
+
+ static const int END_TO_START = 3;
+
+ static const int START_TO_END = 1;
+
+ static const int START_TO_START = 0;
+
+ final bool collapsed;
+
+ final Node commonAncestorContainer;
+
+ final Node endContainer;
+
+ final int endOffset;
+
+ final Node startContainer;
+
+ final int startOffset;
+
+ DocumentFragment cloneContents() native;
+
+ Range cloneRange() native;
+
+ void collapse([bool toStart]) native;
+
+ int compareBoundaryPoints(int how, Range sourceRange) native;
+
+ int comparePoint(Node node, int offset) native;
+
+ DocumentFragment createContextualFragment(String fragment) native;
+
+ void deleteContents() native;
+
+ void detach() native;
+
+ void expand(String unit) native;
+
+ DocumentFragment extractContents() native;
+
+ Rectangle getBoundingClientRect() native;
+
+ @JSName('getClientRects')
+ @Returns('DomRectList|Null')
+ @Creates('DomRectList')
+ List<Rectangle> _getClientRects() native;
+
+ void insertNode(Node node) native;
+
+ bool isPointInRange(Node node, int offset) native;
+
+ void selectNode(Node node) native;
+
+ void selectNodeContents(Node node) native;
+
+ void setEnd(Node node, int offset) native;
+
+ void setEndAfter(Node node) native;
+
+ void setEndBefore(Node node) native;
+
+ void setStart(Node node, int offset) native;
+
+ void setStartAfter(Node node) native;
+
+ void setStartBefore(Node node) native;
+
+ void surroundContents(Node newParent) native;
+
+ List<Rectangle> getClientRects() {
+ var value = _getClientRects();
+
+ // If no prototype we need one for the world to hookup to the proper Dart class.
+ var jsProto = JS('', '#.prototype', value);
+ if (jsProto == null) {
+ JS('', '#.prototype = Object.create(null)', value);
+ }
+
+ applyExtension('DOMRectList', value);
+
+ return value;
+ }
+
+ /**
+ * Checks if createContextualFragment is supported.
+ *
+ * See also:
+ *
+ * * [createContextualFragment]
+ */
+ static bool get supportsCreateContextualFragment =>
+ JS('bool', '("createContextualFragment" in window.Range.prototype)');
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RelatedApplication")
+class RelatedApplication extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory RelatedApplication._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String id;
+
+ final String platform;
+
+ final String url;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RelativeOrientationSensor")
+class RelativeOrientationSensor extends OrientationSensor {
+ // To suppress missing implicit constructor warnings.
+ factory RelativeOrientationSensor._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory RelativeOrientationSensor([Map sensorOptions]) {
+ if (sensorOptions != null) {
+ var sensorOptions_1 = convertDartToNative_Dictionary(sensorOptions);
+ return RelativeOrientationSensor._create_1(sensorOptions_1);
+ }
+ return RelativeOrientationSensor._create_2();
+ }
+ static RelativeOrientationSensor _create_1(sensorOptions) => JS(
+ 'RelativeOrientationSensor',
+ 'new RelativeOrientationSensor(#)',
+ sensorOptions);
+ static RelativeOrientationSensor _create_2() =>
+ JS('RelativeOrientationSensor', 'new RelativeOrientationSensor()');
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RemotePlayback")
+class RemotePlayback extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory RemotePlayback._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String state;
+
+ Future cancelWatchAvailability([int id]) =>
+ promiseToFuture(JS("", "#.cancelWatchAvailability(#)", this, id));
+
+ Future prompt() => promiseToFuture(JS("", "#.prompt()", this));
+
+ Future<int> watchAvailability(RemotePlaybackAvailabilityCallback callback) =>
+ promiseToFuture<int>(JS("", "#.watchAvailability(#)", this, callback));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void RemotePlaybackAvailabilityCallback(bool available);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ReportBody")
+class ReportBody extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ReportBody._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ReportingObserver")
+class ReportingObserver extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ReportingObserver._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ReportingObserver(ReportingObserverCallback callback) {
+ var callback_1 = convertDartClosureToJS(callback, 2);
+ return ReportingObserver._create_1(callback_1);
+ }
+ static ReportingObserver _create_1(callback) =>
+ JS('ReportingObserver', 'new ReportingObserver(#)', callback);
+
+ void disconnect() native;
+
+ void observe() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void ReportingObserverCallback(
+ List reports, ReportingObserver observer);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void RequestAnimationFrameCallback(num highResTime);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ResizeObserver")
+class ResizeObserver extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ResizeObserver._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ResizeObserver(ResizeObserverCallback callback) {
+ var callback_1 = convertDartClosureToJS(callback, 2);
+ return ResizeObserver._create_1(callback_1);
+ }
+ static ResizeObserver _create_1(callback) =>
+ JS('ResizeObserver', 'new ResizeObserver(#)', callback);
+
+ void disconnect() native;
+
+ void observe(Element target) native;
+
+ void unobserve(Element target) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void ResizeObserverCallback(
+ List<ResizeObserverEntry> entries, ResizeObserver observer);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ResizeObserverEntry")
+class ResizeObserverEntry extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ResizeObserverEntry._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final DomRectReadOnly contentRect;
+
+ final Element target;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCCertificate")
+class RtcCertificate extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory RtcCertificate._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int expires;
+
+ List<Map> getFingerprints() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCDataChannel,DataChannel")
+class RtcDataChannel extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory RtcDataChannel._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `close` events to event
+ * handlers that are not necessarily instances of [RtcDataChannel].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> closeEvent =
+ const EventStreamProvider<Event>('close');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [RtcDataChannel].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /**
+ * Static factory designed to expose `message` events to event
+ * handlers that are not necessarily instances of [RtcDataChannel].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ /**
+ * Static factory designed to expose `open` events to event
+ * handlers that are not necessarily instances of [RtcDataChannel].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> openEvent =
+ const EventStreamProvider<Event>('open');
+
+ String binaryType;
+
+ final int bufferedAmount;
+
+ int bufferedAmountLowThreshold;
+
+ final int id;
+
+ final String label;
+
+ final int maxRetransmitTime;
+
+ final int maxRetransmits;
+
+ final bool negotiated;
+
+ final bool ordered;
+
+ final String protocol;
+
+ final String readyState;
+
+ final bool reliable;
+
+ void close() native;
+
+ void send(data) native;
+
+ @JSName('send')
+ void sendBlob(Blob data) native;
+
+ @JSName('send')
+ void sendByteBuffer(ByteBuffer data) native;
+
+ @JSName('send')
+ void sendString(String data) native;
+
+ @JSName('send')
+ void sendTypedData(TypedData data) native;
+
+ /// Stream of `close` events handled by this [RtcDataChannel].
+ Stream<Event> get onClose => closeEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [RtcDataChannel].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `message` events handled by this [RtcDataChannel].
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+ /// Stream of `open` events handled by this [RtcDataChannel].
+ Stream<Event> get onOpen => openEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCDataChannelEvent")
+class RtcDataChannelEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory RtcDataChannelEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory RtcDataChannelEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return RtcDataChannelEvent._create_1(type, eventInitDict_1);
+ }
+ static RtcDataChannelEvent _create_1(type, eventInitDict) => JS(
+ 'RtcDataChannelEvent',
+ 'new RTCDataChannelEvent(#,#)',
+ type,
+ eventInitDict);
+
+ final RtcDataChannel channel;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCDTMFSender")
+class RtcDtmfSender extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory RtcDtmfSender._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `tonechange` events to event
+ * handlers that are not necessarily instances of [RtcDtmfSender].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<RtcDtmfToneChangeEvent> toneChangeEvent =
+ const EventStreamProvider<RtcDtmfToneChangeEvent>('tonechange');
+
+ @JSName('canInsertDTMF')
+ final bool canInsertDtmf;
+
+ final int duration;
+
+ final int interToneGap;
+
+ final String toneBuffer;
+
+ final MediaStreamTrack track;
+
+ @JSName('insertDTMF')
+ void insertDtmf(String tones, [int duration, int interToneGap]) native;
+
+ /// Stream of `tonechange` events handled by this [RtcDtmfSender].
+ Stream<RtcDtmfToneChangeEvent> get onToneChange =>
+ toneChangeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCDTMFToneChangeEvent")
+class RtcDtmfToneChangeEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory RtcDtmfToneChangeEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory RtcDtmfToneChangeEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return RtcDtmfToneChangeEvent._create_1(type, eventInitDict_1);
+ }
+ static RtcDtmfToneChangeEvent _create_1(type, eventInitDict) => JS(
+ 'RtcDtmfToneChangeEvent',
+ 'new RTCDTMFToneChangeEvent(#,#)',
+ type,
+ eventInitDict);
+
+ final String tone;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("RTCIceCandidate,mozRTCIceCandidate")
+class RtcIceCandidate extends Interceptor {
+ factory RtcIceCandidate(Map dictionary) {
+ // TODO(efortuna): Remove this check if when you can actually construct with
+ // the unprefixed RTCIceCandidate in Firefox (currently both are defined,
+ // but one can't be used as a constructor).
+ var constructorName = JS(
+ '',
+ 'window[#]',
+ Device.isFirefox
+ ? '${Device.propertyPrefix}RTCIceCandidate'
+ : 'RTCIceCandidate');
+ return JS('RtcIceCandidate', 'new #(#)', constructorName,
+ convertDartToNative_SerializedScriptValue(dictionary));
+ }
+ // To suppress missing implicit constructor warnings.
+ factory RtcIceCandidate._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String candidate;
+
+ int sdpMLineIndex;
+
+ String sdpMid;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCLegacyStatsReport")
+class RtcLegacyStatsReport extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory RtcLegacyStatsReport._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String id;
+
+ DateTime get timestamp => convertNativeToDart_DateTime(this._get_timestamp);
+ @JSName('timestamp')
+ final dynamic _get_timestamp;
+
+ final String type;
+
+ List<String> names() native;
+
+ String stat(String name) native;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("RTCPeerConnection,webkitRTCPeerConnection,mozRTCPeerConnection")
+class RtcPeerConnection extends EventTarget {
+ factory RtcPeerConnection(Map rtcIceServers, [Map mediaConstraints]) {
+ var constructorName = JS('RtcPeerConnection', 'window[#]',
+ '${Device.propertyPrefix}RTCPeerConnection');
+ if (mediaConstraints != null) {
+ return JS(
+ 'RtcPeerConnection',
+ 'new #(#,#)',
+ constructorName,
+ convertDartToNative_SerializedScriptValue(rtcIceServers),
+ convertDartToNative_SerializedScriptValue(mediaConstraints));
+ } else {
+ return JS('RtcPeerConnection', 'new #(#)', constructorName,
+ convertDartToNative_SerializedScriptValue(rtcIceServers));
+ }
+ }
+
+ /**
+ * Checks if Real Time Communication (RTC) APIs are supported and enabled on
+ * the current platform.
+ */
+ static bool get supported {
+ // Currently in Firefox some of the RTC elements are defined but throw an
+ // error unless the user has specifically enabled them in their
+ // about:config. So we have to construct an element to actually test if RTC
+ // is supported at the given time.
+ try {
+ new RtcPeerConnection({
+ "iceServers": [
+ {"url": "stun:localhost"}
+ ]
+ });
+ return true;
+ } catch (_) {
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * Temporarily exposes _getStats and old getStats as getLegacyStats until Chrome fully supports
+ * new getStats API.
+ */
+ Future<RtcStatsResponse> getLegacyStats([MediaStreamTrack selector]) {
+ var completer = new Completer<RtcStatsResponse>();
+ _getStats((value) {
+ completer.complete(value);
+ }, selector);
+ return completer.future;
+ }
+
+ @JSName('getStats')
+ Future _getStats(
+ [RtcStatsCallback successCallback, MediaStreamTrack selector]) native;
+
+ static Future generateCertificate(/*AlgorithmIdentifier*/ keygenAlgorithm) =>
+ JS('dynamic', 'generateCertificate(#)', keygenAlgorithm);
+
+ // To suppress missing implicit constructor warnings.
+ factory RtcPeerConnection._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `addstream` events to event
+ * handlers that are not necessarily instances of [RtcPeerConnection].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MediaStreamEvent> addStreamEvent =
+ const EventStreamProvider<MediaStreamEvent>('addstream');
+
+ /**
+ * Static factory designed to expose `datachannel` events to event
+ * handlers that are not necessarily instances of [RtcPeerConnection].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<RtcDataChannelEvent> dataChannelEvent =
+ const EventStreamProvider<RtcDataChannelEvent>('datachannel');
+
+ /**
+ * Static factory designed to expose `icecandidate` events to event
+ * handlers that are not necessarily instances of [RtcPeerConnection].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<RtcPeerConnectionIceEvent>
+ iceCandidateEvent =
+ const EventStreamProvider<RtcPeerConnectionIceEvent>('icecandidate');
+
+ /**
+ * Static factory designed to expose `iceconnectionstatechange` events to event
+ * handlers that are not necessarily instances of [RtcPeerConnection].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> iceConnectionStateChangeEvent =
+ const EventStreamProvider<Event>('iceconnectionstatechange');
+
+ /**
+ * Static factory designed to expose `negotiationneeded` events to event
+ * handlers that are not necessarily instances of [RtcPeerConnection].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> negotiationNeededEvent =
+ const EventStreamProvider<Event>('negotiationneeded');
+
+ /**
+ * Static factory designed to expose `removestream` events to event
+ * handlers that are not necessarily instances of [RtcPeerConnection].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MediaStreamEvent> removeStreamEvent =
+ const EventStreamProvider<MediaStreamEvent>('removestream');
+
+ /**
+ * Static factory designed to expose `signalingstatechange` events to event
+ * handlers that are not necessarily instances of [RtcPeerConnection].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> signalingStateChangeEvent =
+ const EventStreamProvider<Event>('signalingstatechange');
+
+ final String iceConnectionState;
+
+ final String iceGatheringState;
+
+ final RtcSessionDescription localDescription;
+
+ final RtcSessionDescription remoteDescription;
+
+ final String signalingState;
+
+ Future addIceCandidate(Object candidate,
+ [VoidCallback successCallback,
+ RtcPeerConnectionErrorCallback failureCallback]) =>
+ promiseToFuture(JS("", "#.addIceCandidate(#, #, #)", this, candidate,
+ successCallback, failureCallback));
+
+ void addStream(MediaStream stream, [Map mediaConstraints]) {
+ if (mediaConstraints != null) {
+ var mediaConstraints_1 = convertDartToNative_Dictionary(mediaConstraints);
+ _addStream_1(stream, mediaConstraints_1);
+ return;
+ }
+ _addStream_2(stream);
+ return;
+ }
+
+ @JSName('addStream')
+ void _addStream_1(MediaStream stream, mediaConstraints) native;
+ @JSName('addStream')
+ void _addStream_2(MediaStream stream) native;
+
+ RtcRtpSender addTrack(MediaStreamTrack track, MediaStream streams) native;
+
+ void close() native;
+
+ Future<RtcSessionDescription> createAnswer([Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture<RtcSessionDescription>(
+ JS("", "#.createAnswer(#)", this, options_dict));
+ }
+
+ @JSName('createDTMFSender')
+ RtcDtmfSender createDtmfSender(MediaStreamTrack track) native;
+
+ RtcDataChannel createDataChannel(String label, [Map dataChannelDict]) {
+ if (dataChannelDict != null) {
+ var dataChannelDict_1 = convertDartToNative_Dictionary(dataChannelDict);
+ return _createDataChannel_1(label, dataChannelDict_1);
+ }
+ return _createDataChannel_2(label);
+ }
+
+ @JSName('createDataChannel')
+ RtcDataChannel _createDataChannel_1(label, dataChannelDict) native;
+ @JSName('createDataChannel')
+ RtcDataChannel _createDataChannel_2(label) native;
+
+ Future<RtcSessionDescription> createOffer([Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture<RtcSessionDescription>(
+ JS("", "#.createOffer(#)", this, options_dict));
+ }
+
+ List<MediaStream> getLocalStreams() native;
+
+ List<RtcRtpReceiver> getReceivers() native;
+
+ List<MediaStream> getRemoteStreams() native;
+
+ List<RtcRtpSender> getSenders() native;
+
+ Future<RtcStatsReport> getStats() =>
+ promiseToFuture<RtcStatsReport>(JS("", "#.getStats()", this));
+
+ void removeStream(MediaStream stream) native;
+
+ void removeTrack(RtcRtpSender sender) native;
+
+ void setConfiguration(Map configuration) {
+ var configuration_1 = convertDartToNative_Dictionary(configuration);
+ _setConfiguration_1(configuration_1);
+ return;
+ }
+
+ @JSName('setConfiguration')
+ void _setConfiguration_1(configuration) native;
+
+ Future setLocalDescription(Map description) {
+ var description_dict = convertDartToNative_Dictionary(description);
+ return promiseToFuture(
+ JS("", "#.setLocalDescription(#)", this, description_dict));
+ }
+
+ Future setRemoteDescription(Map description) {
+ var description_dict = convertDartToNative_Dictionary(description);
+ return promiseToFuture(
+ JS("", "#.setRemoteDescription(#)", this, description_dict));
+ }
+
+ /// Stream of `addstream` events handled by this [RtcPeerConnection].
+ Stream<MediaStreamEvent> get onAddStream => addStreamEvent.forTarget(this);
+
+ /// Stream of `datachannel` events handled by this [RtcPeerConnection].
+ Stream<RtcDataChannelEvent> get onDataChannel =>
+ dataChannelEvent.forTarget(this);
+
+ /// Stream of `icecandidate` events handled by this [RtcPeerConnection].
+ Stream<RtcPeerConnectionIceEvent> get onIceCandidate =>
+ iceCandidateEvent.forTarget(this);
+
+ /// Stream of `iceconnectionstatechange` events handled by this [RtcPeerConnection].
+ Stream<Event> get onIceConnectionStateChange =>
+ iceConnectionStateChangeEvent.forTarget(this);
+
+ /// Stream of `negotiationneeded` events handled by this [RtcPeerConnection].
+ Stream<Event> get onNegotiationNeeded =>
+ negotiationNeededEvent.forTarget(this);
+
+ /// Stream of `removestream` events handled by this [RtcPeerConnection].
+ Stream<MediaStreamEvent> get onRemoveStream =>
+ removeStreamEvent.forTarget(this);
+
+ /// Stream of `signalingstatechange` events handled by this [RtcPeerConnection].
+ Stream<Event> get onSignalingStateChange =>
+ signalingStateChangeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCPeerConnectionIceEvent")
+class RtcPeerConnectionIceEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory RtcPeerConnectionIceEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory RtcPeerConnectionIceEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return RtcPeerConnectionIceEvent._create_1(type, eventInitDict_1);
+ }
+ return RtcPeerConnectionIceEvent._create_2(type);
+ }
+ static RtcPeerConnectionIceEvent _create_1(type, eventInitDict) => JS(
+ 'RtcPeerConnectionIceEvent',
+ 'new RTCPeerConnectionIceEvent(#,#)',
+ type,
+ eventInitDict);
+ static RtcPeerConnectionIceEvent _create_2(type) =>
+ JS('RtcPeerConnectionIceEvent', 'new RTCPeerConnectionIceEvent(#)', type);
+
+ final RtcIceCandidate candidate;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCRtpContributingSource")
+class RtcRtpContributingSource extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory RtcRtpContributingSource._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int source;
+
+ final num timestamp;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCRtpReceiver")
+class RtcRtpReceiver extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory RtcRtpReceiver._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final MediaStreamTrack track;
+
+ List<RtcRtpContributingSource> getContributingSources() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCRtpSender")
+class RtcRtpSender extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory RtcRtpSender._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final MediaStreamTrack track;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("RTCSessionDescription,mozRTCSessionDescription")
+class RtcSessionDescription extends Interceptor {
+ factory RtcSessionDescription(Map dictionary) {
+ // TODO(efortuna): Remove this check if when you can actually construct with
+ // the unprefixed RTCIceCandidate in Firefox (currently both are defined,
+ // but one can't be used as a constructor).
+ var constructorName = JS(
+ '',
+ 'window[#]',
+ Device.isFirefox
+ ? '${Device.propertyPrefix}RTCSessionDescription'
+ : 'RTCSessionDescription');
+ return JS('RtcSessionDescription', 'new #(#)', constructorName,
+ convertDartToNative_SerializedScriptValue(dictionary));
+ }
+ // To suppress missing implicit constructor warnings.
+ factory RtcSessionDescription._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String sdp;
+
+ String type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCStatsReport")
+class RtcStatsReport extends Interceptor with MapMixin<String, dynamic> {
+ // To suppress missing implicit constructor warnings.
+ factory RtcStatsReport._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Map _getItem(String key) =>
+ convertNativeToDart_Dictionary(JS('', '#.get(#)', this, key));
+
+ void addAll(Map<String, dynamic> other) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ bool containsValue(dynamic value) => values.any((e) => e == value);
+
+ bool containsKey(dynamic key) => _getItem(key) != null;
+
+ Map operator [](dynamic key) => _getItem(key);
+
+ void forEach(void f(String key, dynamic value)) {
+ var entries = JS('', '#.entries()', this);
+ while (true) {
+ var entry = JS('', '#.next()', entries);
+ if (JS('bool', '#.done', entry)) return;
+ f(JS('String', '#.value[0]', entry),
+ convertNativeToDart_Dictionary(JS('', '#.value[1]', entry)));
+ }
+ }
+
+ Iterable<String> get keys {
+ final keys = <String>[];
+ forEach((k, v) => keys.add(k));
+ return keys;
+ }
+
+ Iterable<Map> get values {
+ final values = <Map>[];
+ forEach((k, v) => values.add(v));
+ return values;
+ }
+
+ int get length => JS('int', '#.size', this);
+
+ bool get isEmpty => length == 0;
+
+ bool get isNotEmpty => !isEmpty;
+
+ void operator []=(String key, dynamic value) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ dynamic putIfAbsent(String key, dynamic ifAbsent()) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String remove(dynamic key) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void clear() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCStatsResponse")
+class RtcStatsResponse extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory RtcStatsResponse._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ RtcLegacyStatsReport namedItem(String name) native;
+
+ List<RtcLegacyStatsReport> result() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("RTCTrackEvent")
+class RtcTrackEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory RtcTrackEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory RtcTrackEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return RtcTrackEvent._create_1(type, eventInitDict_1);
+ }
+ static RtcTrackEvent _create_1(type, eventInitDict) =>
+ JS('RtcTrackEvent', 'new RTCTrackEvent(#,#)', type, eventInitDict);
+
+ final RtcRtpReceiver receiver;
+
+ final List<MediaStream> streams;
+
+ final MediaStreamTrack track;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Screen")
+class Screen extends Interceptor {
+ Rectangle get available =>
+ new Rectangle(_availLeft, _availTop, _availWidth, _availHeight);
+ // To suppress missing implicit constructor warnings.
+ factory Screen._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('availHeight')
+ final int _availHeight;
+
+ @JSName('availLeft')
+ final int _availLeft;
+
+ @JSName('availTop')
+ final int _availTop;
+
+ @JSName('availWidth')
+ final int _availWidth;
+
+ final int colorDepth;
+
+ final int height;
+
+ bool keepAwake;
+
+ final ScreenOrientation orientation;
+
+ final int pixelDepth;
+
+ final int width;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ScreenOrientation")
+class ScreenOrientation extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory ScreenOrientation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> changeEvent =
+ const EventStreamProvider<Event>('change');
+
+ final int angle;
+
+ final String type;
+
+ Future lock(String orientation) =>
+ promiseToFuture(JS("", "#.lock(#)", this, orientation));
+
+ void unlock() native;
+
+ Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLScriptElement")
+class ScriptElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory ScriptElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ScriptElement() => JS(
+ 'returns:ScriptElement;creates:ScriptElement;new:true',
+ '#.createElement(#)',
+ document,
+ "script");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ScriptElement.created() : super.created();
+
+ bool async;
+
+ String charset;
+
+ String crossOrigin;
+
+ bool defer;
+
+ String integrity;
+
+ bool noModule;
+
+ String src;
+
+ String type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ScrollState")
+class ScrollState extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ScrollState._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ScrollState([Map scrollStateInit]) {
+ if (scrollStateInit != null) {
+ var scrollStateInit_1 = convertDartToNative_Dictionary(scrollStateInit);
+ return ScrollState._create_1(scrollStateInit_1);
+ }
+ return ScrollState._create_2();
+ }
+ static ScrollState _create_1(scrollStateInit) =>
+ JS('ScrollState', 'new ScrollState(#)', scrollStateInit);
+ static ScrollState _create_2() => JS('ScrollState', 'new ScrollState()');
+
+ final num deltaGranularity;
+
+ final num deltaX;
+
+ final num deltaY;
+
+ final bool fromUserInput;
+
+ final bool inInertialPhase;
+
+ final bool isBeginning;
+
+ final bool isDirectManipulation;
+
+ final bool isEnding;
+
+ final int positionX;
+
+ final int positionY;
+
+ final num velocityX;
+
+ final num velocityY;
+
+ void consumeDelta(num x, num y) native;
+
+ void distributeToScrollChainDescendant() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void ScrollStateCallback(ScrollState scrollState);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ScrollTimeline")
+class ScrollTimeline extends AnimationTimeline {
+ // To suppress missing implicit constructor warnings.
+ factory ScrollTimeline._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ScrollTimeline([Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return ScrollTimeline._create_1(options_1);
+ }
+ return ScrollTimeline._create_2();
+ }
+ static ScrollTimeline _create_1(options) =>
+ JS('ScrollTimeline', 'new ScrollTimeline(#)', options);
+ static ScrollTimeline _create_2() =>
+ JS('ScrollTimeline', 'new ScrollTimeline()');
+
+ final String orientation;
+
+ final Element scrollSource;
+
+ final Object timeRange;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SecurityPolicyViolationEvent")
+class SecurityPolicyViolationEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory SecurityPolicyViolationEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SecurityPolicyViolationEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return SecurityPolicyViolationEvent._create_1(type, eventInitDict_1);
+ }
+ return SecurityPolicyViolationEvent._create_2(type);
+ }
+ static SecurityPolicyViolationEvent _create_1(type, eventInitDict) => JS(
+ 'SecurityPolicyViolationEvent',
+ 'new SecurityPolicyViolationEvent(#,#)',
+ type,
+ eventInitDict);
+ static SecurityPolicyViolationEvent _create_2(type) => JS(
+ 'SecurityPolicyViolationEvent',
+ 'new SecurityPolicyViolationEvent(#)',
+ type);
+
+ @JSName('blockedURI')
+ final String blockedUri;
+
+ final int columnNumber;
+
+ final String disposition;
+
+ @JSName('documentURI')
+ final String documentUri;
+
+ final String effectiveDirective;
+
+ final int lineNumber;
+
+ final String originalPolicy;
+
+ final String referrer;
+
+ final String sample;
+
+ final String sourceFile;
+
+ final int statusCode;
+
+ final String violatedDirective;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLSelectElement")
+class SelectElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory SelectElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SelectElement() => JS(
+ 'returns:SelectElement;creates:SelectElement;new:true',
+ '#.createElement(#)',
+ document,
+ "select");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ SelectElement.created() : super.created();
+
+ bool autofocus;
+
+ bool disabled;
+
+ final FormElement form;
+
+ @Unstable()
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ final List<Node> labels;
+
+ int length;
+
+ bool multiple;
+
+ String name;
+
+ bool required;
+
+ int selectedIndex;
+
+ int size;
+
+ final String type;
+
+ final String validationMessage;
+
+ final ValidityState validity;
+
+ String value;
+
+ final bool willValidate;
+
+ void __setter__(int index, OptionElement option) native;
+
+ void add(Object element, Object before) native;
+
+ bool checkValidity() native;
+
+ Element item(int index) native;
+
+ OptionElement namedItem(String name) native;
+
+ bool reportValidity() native;
+
+ void setCustomValidity(String error) native;
+
+ // Override default options, since IE returns SelectElement itself and it
+ // does not operate as a List.
+ List<OptionElement> get options {
+ dynamic options = this.querySelectorAll<OptionElement>('option');
+ return new UnmodifiableListView(options.toList());
+ }
+
+ List<OptionElement> get selectedOptions {
+ // IE does not change the selected flag for single-selection items.
+ if (this.multiple) {
+ var options = this.options.where((o) => o.selected).toList();
+ return new UnmodifiableListView(options);
+ } else {
+ return [this.options[this.selectedIndex]];
+ }
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Selection")
+class Selection extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Selection._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Node anchorNode;
+
+ final int anchorOffset;
+
+ final Node baseNode;
+
+ final int baseOffset;
+
+ final Node extentNode;
+
+ final int extentOffset;
+
+ final Node focusNode;
+
+ final int focusOffset;
+
+ final bool isCollapsed;
+
+ final int rangeCount;
+
+ final String type;
+
+ void addRange(Range range) native;
+
+ void collapse(Node node, [int offset]) native;
+
+ void collapseToEnd() native;
+
+ void collapseToStart() native;
+
+ bool containsNode(Node node, [bool allowPartialContainment]) native;
+
+ void deleteFromDocument() native;
+
+ void empty() native;
+
+ void extend(Node node, [int offset]) native;
+
+ Range getRangeAt(int index) native;
+
+ void modify(String alter, String direction, String granularity) native;
+
+ void removeAllRanges() native;
+
+ void removeRange(Range range) native;
+
+ void selectAllChildren(Node node) native;
+
+ void setBaseAndExtent(
+ Node baseNode, int baseOffset, Node extentNode, int extentOffset) native;
+
+ void setPosition(Node node, [int offset]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Sensor")
+class Sensor extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory Sensor._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ final bool activated;
+
+ final bool hasReading;
+
+ final num timestamp;
+
+ void start() native;
+
+ void stop() native;
+
+ Stream<Event> get onError => errorEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SensorErrorEvent")
+class SensorErrorEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory SensorErrorEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SensorErrorEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return SensorErrorEvent._create_1(type, eventInitDict_1);
+ }
+ static SensorErrorEvent _create_1(type, eventInitDict) =>
+ JS('SensorErrorEvent', 'new SensorErrorEvent(#,#)', type, eventInitDict);
+
+ final DomException error;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ServiceWorker")
+class ServiceWorker extends EventTarget implements AbstractWorker {
+ // To suppress missing implicit constructor warnings.
+ factory ServiceWorker._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ @JSName('scriptURL')
+ final String scriptUrl;
+
+ final String state;
+
+ void postMessage(/*any*/ message, [List<Object> transfer]) {
+ if (transfer != null) {
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_1(message_1, transfer);
+ return;
+ }
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_2(message_1);
+ return;
+ }
+
+ @JSName('postMessage')
+ void _postMessage_1(message, List<Object> transfer) native;
+ @JSName('postMessage')
+ void _postMessage_2(message) native;
+
+ Stream<Event> get onError => errorEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ServiceWorkerContainer")
+class ServiceWorkerContainer extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory ServiceWorkerContainer._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ final ServiceWorker controller;
+
+ Future<ServiceWorkerRegistration> get ready =>
+ promiseToFuture<ServiceWorkerRegistration>(JS("", "#.ready", this));
+
+ Future<ServiceWorkerRegistration> getRegistration([String documentURL]) =>
+ promiseToFuture<ServiceWorkerRegistration>(
+ JS("", "#.getRegistration(#)", this, documentURL));
+
+ Future<List<ServiceWorkerRegistration>> getRegistrations() =>
+ promiseToFuture<List<ServiceWorkerRegistration>>(
+ JS("", "#.getRegistrations()", this));
+
+ Future<ServiceWorkerRegistration> register(String url, [Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture<ServiceWorkerRegistration>(
+ JS("", "#.register(#, #)", this, url, options_dict));
+ }
+
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ServiceWorkerGlobalScope")
+class ServiceWorkerGlobalScope extends WorkerGlobalScope {
+ // To suppress missing implicit constructor warnings.
+ factory ServiceWorkerGlobalScope._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> activateEvent =
+ const EventStreamProvider<Event>('activate');
+
+ static const EventStreamProvider<Event> fetchEvent =
+ const EventStreamProvider<Event>('fetch');
+
+ static const EventStreamProvider<ForeignFetchEvent> foreignfetchEvent =
+ const EventStreamProvider<ForeignFetchEvent>('foreignfetch');
+
+ static const EventStreamProvider<Event> installEvent =
+ const EventStreamProvider<Event>('install');
+
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ final Clients clients;
+
+ final ServiceWorkerRegistration registration;
+
+ Future skipWaiting() => promiseToFuture(JS("", "#.skipWaiting()", this));
+
+ Stream<Event> get onActivate => activateEvent.forTarget(this);
+
+ Stream<Event> get onFetch => fetchEvent.forTarget(this);
+
+ Stream<ForeignFetchEvent> get onForeignfetch =>
+ foreignfetchEvent.forTarget(this);
+
+ Stream<Event> get onInstall => installEvent.forTarget(this);
+
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+ static ServiceWorkerGlobalScope get instance {
+ return _workerSelf as ServiceWorkerGlobalScope;
+ }
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ServiceWorkerRegistration")
+class ServiceWorkerRegistration extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory ServiceWorkerRegistration._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final ServiceWorker active;
+
+ final BackgroundFetchManager backgroundFetch;
+
+ final ServiceWorker installing;
+
+ final NavigationPreloadManager navigationPreload;
+
+ final PaymentManager paymentManager;
+
+ final PushManager pushManager;
+
+ final String scope;
+
+ final SyncManager sync;
+
+ final ServiceWorker waiting;
+
+ Future<List<Notification>> getNotifications([Map filter]) {
+ var filter_dict = null;
+ if (filter != null) {
+ filter_dict = convertDartToNative_Dictionary(filter);
+ }
+ return promiseToFuture<List<Notification>>(
+ JS("", "#.getNotifications(#)", this, filter_dict));
+ }
+
+ Future showNotification(String title, [Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture(
+ JS("", "#.showNotification(#, #)", this, title, options_dict));
+ }
+
+ Future<bool> unregister() =>
+ promiseToFuture<bool>(JS("", "#.unregister()", this));
+
+ Future update() => promiseToFuture(JS("", "#.update()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '26')
+@Native("HTMLShadowElement")
+class ShadowElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory ShadowElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ShadowElement() => document.createElement("shadow");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ShadowElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Element.isTagSupported('shadow');
+
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ List<Node> getDistributedNodes() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '26')
+@Native("ShadowRoot")
+class ShadowRoot extends DocumentFragment implements DocumentOrShadowRoot {
+ // To suppress missing implicit constructor warnings.
+ factory ShadowRoot._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool delegatesFocus;
+
+ final Element host;
+
+ @JSName('innerHTML')
+ String innerHtml;
+
+ final String mode;
+
+ final ShadowRoot olderShadowRoot;
+
+ // From DocumentOrShadowRoot
+
+ final Element activeElement;
+
+ final Element fullscreenElement;
+
+ final Element pointerLockElement;
+
+ @Returns('_StyleSheetList|Null')
+ @Creates('_StyleSheetList')
+ final List<StyleSheet> styleSheets;
+
+ Element elementFromPoint(int x, int y) native;
+
+ List<Element> elementsFromPoint(int x, int y) native;
+
+ Selection getSelection() native;
+
+ static bool get supported => JS(
+ 'bool',
+ '!!(Element.prototype.createShadowRoot||'
+ 'Element.prototype.webkitCreateShadowRoot)');
+
+ static bool _shadowRootDeprecationReported = false;
+ static void _shadowRootDeprecationReport() {
+ if (!_shadowRootDeprecationReported) {
+ window.console.warn('''
+ShadowRoot.resetStyleInheritance and ShadowRoot.applyAuthorStyles now deprecated in dart:html.
+Please remove them from your code.
+''');
+ _shadowRootDeprecationReported = true;
+ }
+ }
+
+ @deprecated
+ bool get resetStyleInheritance {
+ _shadowRootDeprecationReport();
+ // Default value from when it was specified.
+ return false;
+ }
+
+ @deprecated
+ set resetStyleInheritance(bool value) {
+ _shadowRootDeprecationReport();
+ }
+
+ @deprecated
+ bool get applyAuthorStyles {
+ _shadowRootDeprecationReport();
+ // Default value from when it was specified.
+ return false;
+ }
+
+ @deprecated
+ set applyAuthorStyles(bool value) {
+ _shadowRootDeprecationReport();
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SharedArrayBuffer")
+class SharedArrayBuffer extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory SharedArrayBuffer._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int byteLength;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SharedWorker")
+class SharedWorker extends EventTarget implements AbstractWorker {
+ // To suppress missing implicit constructor warnings.
+ factory SharedWorker._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ factory SharedWorker(String scriptURL, [String name]) {
+ if (name != null) {
+ return SharedWorker._create_1(scriptURL, name);
+ }
+ return SharedWorker._create_2(scriptURL);
+ }
+ static SharedWorker _create_1(scriptURL, name) =>
+ JS('SharedWorker', 'new SharedWorker(#,#)', scriptURL, name);
+ static SharedWorker _create_2(scriptURL) =>
+ JS('SharedWorker', 'new SharedWorker(#)', scriptURL);
+
+ final MessagePort port;
+
+ Stream<Event> get onError => errorEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SharedWorkerGlobalScope")
+class SharedWorkerGlobalScope extends WorkerGlobalScope {
+ // To suppress missing implicit constructor warnings.
+ factory SharedWorkerGlobalScope._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `connect` events to event
+ * handlers that are not necessarily instances of [SharedWorkerGlobalScope].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> connectEvent =
+ const EventStreamProvider<Event>('connect');
+
+ static const int PERSISTENT = 1;
+
+ static const int TEMPORARY = 0;
+
+ final String name;
+
+ void close() native;
+
+ @JSName('webkitRequestFileSystem')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void _webkitRequestFileSystem(int type, int size,
+ [_FileSystemCallback successCallback,
+ _ErrorCallback errorCallback]) native;
+
+ @JSName('webkitRequestFileSystemSync')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ _DOMFileSystemSync requestFileSystemSync(int type, int size) native;
+
+ @JSName('webkitResolveLocalFileSystemSyncURL')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ _EntrySync resolveLocalFileSystemSyncUrl(String url) native;
+
+ @JSName('webkitResolveLocalFileSystemURL')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void _webkitResolveLocalFileSystemUrl(
+ String url, _EntryCallback successCallback,
+ [_ErrorCallback errorCallback]) native;
+
+ /// Stream of `connect` events handled by this [SharedWorkerGlobalScope].
+ Stream<Event> get onConnect => connectEvent.forTarget(this);
+
+ static SharedWorkerGlobalScope get instance {
+ return _workerSelf as SharedWorkerGlobalScope;
+ }
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLSlotElement")
+class SlotElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory SlotElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ SlotElement.created() : super.created();
+
+ String name;
+
+ List<Node> assignedNodes([Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return _assignedNodes_1(options_1);
+ }
+ return _assignedNodes_2();
+ }
+
+ @JSName('assignedNodes')
+ List<Node> _assignedNodes_1(options) native;
+ @JSName('assignedNodes')
+ List<Node> _assignedNodes_2() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SourceBuffer")
+class SourceBuffer extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory SourceBuffer._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> abortEvent =
+ const EventStreamProvider<Event>('abort');
+
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ num appendWindowEnd;
+
+ num appendWindowStart;
+
+ final AudioTrackList audioTracks;
+
+ final TimeRanges buffered;
+
+ String mode;
+
+ num timestampOffset;
+
+ TrackDefaultList trackDefaults;
+
+ final bool updating;
+
+ final VideoTrackList videoTracks;
+
+ void abort() native;
+
+ void appendBuffer(ByteBuffer data) native;
+
+ @JSName('appendBuffer')
+ void appendTypedData(TypedData data) native;
+
+ void remove(num start, num end) native;
+
+ Stream<Event> get onAbort => abortEvent.forTarget(this);
+
+ Stream<Event> get onError => errorEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SourceBufferList")
+class SourceBufferList extends EventTarget
+ with ListMixin<SourceBuffer>, ImmutableListMixin<SourceBuffer>
+ implements JavaScriptIndexingBehavior<SourceBuffer>, List<SourceBuffer> {
+ // To suppress missing implicit constructor warnings.
+ factory SourceBufferList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ SourceBuffer operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("SourceBuffer", "#[#]", this, index);
+ }
+
+ void operator []=(int index, SourceBuffer value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<SourceBuffer> mixins.
+ // SourceBuffer is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ SourceBuffer get first {
+ if (this.length > 0) {
+ return JS('SourceBuffer', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ SourceBuffer get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('SourceBuffer', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ SourceBuffer get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('SourceBuffer', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ SourceBuffer elementAt(int index) => this[index];
+ // -- end List<SourceBuffer> mixins.
+
+ SourceBuffer item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLSourceElement")
+class SourceElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory SourceElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SourceElement() => JS(
+ 'returns:SourceElement;creates:SourceElement;new:true',
+ '#.createElement(#)',
+ document,
+ "source");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ SourceElement.created() : super.created();
+
+ String media;
+
+ String sizes;
+
+ String src;
+
+ String srcset;
+
+ String type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLSpanElement")
+class SpanElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory SpanElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SpanElement() => JS(
+ 'returns:SpanElement;creates:SpanElement;new:true',
+ '#.createElement(#)',
+ document,
+ "span");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ SpanElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechGrammar")
+class SpeechGrammar extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory SpeechGrammar._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SpeechGrammar() {
+ return SpeechGrammar._create_1();
+ }
+ static SpeechGrammar _create_1() =>
+ JS('SpeechGrammar', 'new SpeechGrammar()');
+
+ String src;
+
+ num weight;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechGrammarList")
+class SpeechGrammarList extends Interceptor
+ with ListMixin<SpeechGrammar>, ImmutableListMixin<SpeechGrammar>
+ implements JavaScriptIndexingBehavior<SpeechGrammar>, List<SpeechGrammar> {
+ // To suppress missing implicit constructor warnings.
+ factory SpeechGrammarList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SpeechGrammarList() {
+ return SpeechGrammarList._create_1();
+ }
+ static SpeechGrammarList _create_1() =>
+ JS('SpeechGrammarList', 'new SpeechGrammarList()');
+
+ int get length => JS("int", "#.length", this);
+
+ SpeechGrammar operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("SpeechGrammar", "#[#]", this, index);
+ }
+
+ void operator []=(int index, SpeechGrammar value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<SpeechGrammar> mixins.
+ // SpeechGrammar is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ SpeechGrammar get first {
+ if (this.length > 0) {
+ return JS('SpeechGrammar', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ SpeechGrammar get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('SpeechGrammar', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ SpeechGrammar get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('SpeechGrammar', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ SpeechGrammar elementAt(int index) => this[index];
+ // -- end List<SpeechGrammar> mixins.
+
+ void addFromString(String string, [num weight]) native;
+
+ void addFromUri(String src, [num weight]) native;
+
+ SpeechGrammar item(int index) native;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+@Native("SpeechRecognition")
+class SpeechRecognition extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory SpeechRecognition._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `audioend` events to event
+ * handlers that are not necessarily instances of [SpeechRecognition].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> audioEndEvent =
+ const EventStreamProvider<Event>('audioend');
+
+ /**
+ * Static factory designed to expose `audiostart` events to event
+ * handlers that are not necessarily instances of [SpeechRecognition].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> audioStartEvent =
+ const EventStreamProvider<Event>('audiostart');
+
+ /**
+ * Static factory designed to expose `end` events to event
+ * handlers that are not necessarily instances of [SpeechRecognition].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> endEvent =
+ const EventStreamProvider<Event>('end');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [SpeechRecognition].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<SpeechRecognitionError> errorEvent =
+ const EventStreamProvider<SpeechRecognitionError>('error');
+
+ /**
+ * Static factory designed to expose `nomatch` events to event
+ * handlers that are not necessarily instances of [SpeechRecognition].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<SpeechRecognitionEvent> noMatchEvent =
+ const EventStreamProvider<SpeechRecognitionEvent>('nomatch');
+
+ /**
+ * Static factory designed to expose `result` events to event
+ * handlers that are not necessarily instances of [SpeechRecognition].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<SpeechRecognitionEvent> resultEvent =
+ const EventStreamProvider<SpeechRecognitionEvent>('result');
+
+ /**
+ * Static factory designed to expose `soundend` events to event
+ * handlers that are not necessarily instances of [SpeechRecognition].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> soundEndEvent =
+ const EventStreamProvider<Event>('soundend');
+
+ /**
+ * Static factory designed to expose `soundstart` events to event
+ * handlers that are not necessarily instances of [SpeechRecognition].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> soundStartEvent =
+ const EventStreamProvider<Event>('soundstart');
+
+ /**
+ * Static factory designed to expose `speechend` events to event
+ * handlers that are not necessarily instances of [SpeechRecognition].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> speechEndEvent =
+ const EventStreamProvider<Event>('speechend');
+
+ /**
+ * Static factory designed to expose `speechstart` events to event
+ * handlers that are not necessarily instances of [SpeechRecognition].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> speechStartEvent =
+ const EventStreamProvider<Event>('speechstart');
+
+ /**
+ * Static factory designed to expose `start` events to event
+ * handlers that are not necessarily instances of [SpeechRecognition].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> startEvent =
+ const EventStreamProvider<Event>('start');
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => JS(
+ 'bool', '!!(window.SpeechRecognition || window.webkitSpeechRecognition)');
+
+ MediaStreamTrack audioTrack;
+
+ bool continuous;
+
+ SpeechGrammarList grammars;
+
+ bool interimResults;
+
+ String lang;
+
+ int maxAlternatives;
+
+ void abort() native;
+
+ void start() native;
+
+ void stop() native;
+
+ /// Stream of `audioend` events handled by this [SpeechRecognition].
+ Stream<Event> get onAudioEnd => audioEndEvent.forTarget(this);
+
+ /// Stream of `audiostart` events handled by this [SpeechRecognition].
+ Stream<Event> get onAudioStart => audioStartEvent.forTarget(this);
+
+ /// Stream of `end` events handled by this [SpeechRecognition].
+ Stream<Event> get onEnd => endEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [SpeechRecognition].
+ Stream<SpeechRecognitionError> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `nomatch` events handled by this [SpeechRecognition].
+ Stream<SpeechRecognitionEvent> get onNoMatch => noMatchEvent.forTarget(this);
+
+ /// Stream of `result` events handled by this [SpeechRecognition].
+ Stream<SpeechRecognitionEvent> get onResult => resultEvent.forTarget(this);
+
+ /// Stream of `soundend` events handled by this [SpeechRecognition].
+ Stream<Event> get onSoundEnd => soundEndEvent.forTarget(this);
+
+ /// Stream of `soundstart` events handled by this [SpeechRecognition].
+ Stream<Event> get onSoundStart => soundStartEvent.forTarget(this);
+
+ /// Stream of `speechend` events handled by this [SpeechRecognition].
+ Stream<Event> get onSpeechEnd => speechEndEvent.forTarget(this);
+
+ /// Stream of `speechstart` events handled by this [SpeechRecognition].
+ Stream<Event> get onSpeechStart => speechStartEvent.forTarget(this);
+
+ /// Stream of `start` events handled by this [SpeechRecognition].
+ Stream<Event> get onStart => startEvent.forTarget(this);
+
+ factory SpeechRecognition() {
+ return JS('SpeechRecognition',
+ 'new (window.SpeechRecognition || window.webkitSpeechRecognition)()');
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+@Native("SpeechRecognitionAlternative")
+class SpeechRecognitionAlternative extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory SpeechRecognitionAlternative._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num confidence;
+
+ final String transcript;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+@Native("SpeechRecognitionError")
+class SpeechRecognitionError extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory SpeechRecognitionError._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SpeechRecognitionError(String type, [Map initDict]) {
+ if (initDict != null) {
+ var initDict_1 = convertDartToNative_Dictionary(initDict);
+ return SpeechRecognitionError._create_1(type, initDict_1);
+ }
+ return SpeechRecognitionError._create_2(type);
+ }
+ static SpeechRecognitionError _create_1(type, initDict) => JS(
+ 'SpeechRecognitionError',
+ 'new SpeechRecognitionError(#,#)',
+ type,
+ initDict);
+ static SpeechRecognitionError _create_2(type) =>
+ JS('SpeechRecognitionError', 'new SpeechRecognitionError(#)', type);
+
+ final String error;
+
+ final String message;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+@Native("SpeechRecognitionEvent")
+class SpeechRecognitionEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory SpeechRecognitionEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SpeechRecognitionEvent(String type, [Map initDict]) {
+ if (initDict != null) {
+ var initDict_1 = convertDartToNative_Dictionary(initDict);
+ return SpeechRecognitionEvent._create_1(type, initDict_1);
+ }
+ return SpeechRecognitionEvent._create_2(type);
+ }
+ static SpeechRecognitionEvent _create_1(type, initDict) => JS(
+ 'SpeechRecognitionEvent',
+ 'new SpeechRecognitionEvent(#,#)',
+ type,
+ initDict);
+ static SpeechRecognitionEvent _create_2(type) =>
+ JS('SpeechRecognitionEvent', 'new SpeechRecognitionEvent(#)', type);
+
+ final Document emma;
+
+ final Document interpretation;
+
+ final int resultIndex;
+
+ @Returns('_SpeechRecognitionResultList|Null')
+ @Creates('_SpeechRecognitionResultList')
+ final List<SpeechRecognitionResult> results;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME, '25')
+@Native("SpeechRecognitionResult")
+class SpeechRecognitionResult extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory SpeechRecognitionResult._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool isFinal;
+
+ final int length;
+
+ SpeechRecognitionAlternative item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechSynthesis")
+class SpeechSynthesis extends EventTarget {
+ List<SpeechSynthesisVoice> getVoices() {
+ List<SpeechSynthesisVoice> voices = _getVoices();
+ if (voices.length > 0) applyExtension('SpeechSynthesisVoice', voices[0]);
+ return voices;
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory SpeechSynthesis._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool paused;
+
+ final bool pending;
+
+ final bool speaking;
+
+ void cancel() native;
+
+ @JSName('getVoices')
+ List<SpeechSynthesisVoice> _getVoices() native;
+
+ void pause() native;
+
+ void resume() native;
+
+ void speak(SpeechSynthesisUtterance utterance) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechSynthesisEvent")
+class SpeechSynthesisEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory SpeechSynthesisEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int charIndex;
+
+ final num elapsedTime;
+
+ final String name;
+
+ final SpeechSynthesisUtterance utterance;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechSynthesisUtterance")
+class SpeechSynthesisUtterance extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory SpeechSynthesisUtterance._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `boundary` events to event
+ * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<SpeechSynthesisEvent> boundaryEvent =
+ const EventStreamProvider<SpeechSynthesisEvent>('boundary');
+
+ /**
+ * Static factory designed to expose `end` events to event
+ * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<SpeechSynthesisEvent> endEvent =
+ const EventStreamProvider<SpeechSynthesisEvent>('end');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /**
+ * Static factory designed to expose `mark` events to event
+ * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<SpeechSynthesisEvent> markEvent =
+ const EventStreamProvider<SpeechSynthesisEvent>('mark');
+
+ /**
+ * Static factory designed to expose `pause` events to event
+ * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> pauseEvent =
+ const EventStreamProvider<Event>('pause');
+
+ /**
+ * Static factory designed to expose `resume` events to event
+ * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<SpeechSynthesisEvent> resumeEvent =
+ const EventStreamProvider<SpeechSynthesisEvent>('resume');
+
+ /**
+ * Static factory designed to expose `start` events to event
+ * handlers that are not necessarily instances of [SpeechSynthesisUtterance].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<SpeechSynthesisEvent> startEvent =
+ const EventStreamProvider<SpeechSynthesisEvent>('start');
+
+ factory SpeechSynthesisUtterance([String text]) {
+ if (text != null) {
+ return SpeechSynthesisUtterance._create_1(text);
+ }
+ return SpeechSynthesisUtterance._create_2();
+ }
+ static SpeechSynthesisUtterance _create_1(text) =>
+ JS('SpeechSynthesisUtterance', 'new SpeechSynthesisUtterance(#)', text);
+ static SpeechSynthesisUtterance _create_2() =>
+ JS('SpeechSynthesisUtterance', 'new SpeechSynthesisUtterance()');
+
+ String lang;
+
+ num pitch;
+
+ num rate;
+
+ String text;
+
+ SpeechSynthesisVoice voice;
+
+ num volume;
+
+ /// Stream of `boundary` events handled by this [SpeechSynthesisUtterance].
+ Stream<SpeechSynthesisEvent> get onBoundary => boundaryEvent.forTarget(this);
+
+ /// Stream of `end` events handled by this [SpeechSynthesisUtterance].
+ Stream<SpeechSynthesisEvent> get onEnd => endEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [SpeechSynthesisUtterance].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `mark` events handled by this [SpeechSynthesisUtterance].
+ Stream<SpeechSynthesisEvent> get onMark => markEvent.forTarget(this);
+
+ /// Stream of `pause` events handled by this [SpeechSynthesisUtterance].
+ Stream<Event> get onPause => pauseEvent.forTarget(this);
+
+ /// Stream of `resume` events handled by this [SpeechSynthesisUtterance].
+ Stream<SpeechSynthesisEvent> get onResume => resumeEvent.forTarget(this);
+
+ /// Stream of `start` events handled by this [SpeechSynthesisUtterance].
+ Stream<SpeechSynthesisEvent> get onStart => startEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechSynthesisVoice")
+class SpeechSynthesisVoice extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory SpeechSynthesisVoice._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('default')
+ final bool defaultValue;
+
+ final String lang;
+
+ final bool localService;
+
+ final String name;
+
+ @JSName('voiceURI')
+ final String voiceUri;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StaticRange")
+class StaticRange extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory StaticRange._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool collapsed;
+
+ final Node endContainer;
+
+ final int endOffset;
+
+ final Node startContainer;
+
+ final int startOffset;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * The type used by the
+ * [Window.localStorage] and [Window.sessionStorage] properties.
+ * Storage is implemented as a Map<String, String>.
+ *
+ * To store and get values, use Dart's built-in map syntax:
+ *
+ * window.localStorage['key1'] = 'val1';
+ * window.localStorage['key2'] = 'val2';
+ * window.localStorage['key3'] = 'val3';
+ * assert(window.localStorage['key3'] == 'val3');
+ *
+ * You can use [Map](http://api.dartlang.org/dart_core/Map.html) APIs
+ * such as containsValue(), clear(), and length:
+ *
+ * assert(window.localStorage.containsValue('does not exist') == false);
+ * window.localStorage.clear();
+ * assert(window.localStorage.length == 0);
+ *
+ * For more examples of using this API, see
+ * [localstorage_test.dart](http://code.google.com/p/dart/source/browse/branches/bleeding_edge/dart/tests/html/localstorage_test.dart).
+ * For details on using the Map API, see the
+ * [Maps](https://www.dartlang.org/guides/libraries/library-tour#maps)
+ * section of the library tour.
+ */
+@Unstable()
+@Native("Storage")
+class Storage extends Interceptor with MapMixin<String, String> {
+ void addAll(Map<String, String> other) {
+ other.forEach((k, v) {
+ this[k] = v;
+ });
+ }
+
+ // TODO(nweiz): update this when maps support lazy iteration
+ bool containsValue(Object value) => values.any((e) => e == value);
+
+ bool containsKey(Object key) => _getItem(key) != null;
+
+ String operator [](Object key) => _getItem(key);
+
+ void operator []=(String key, String value) {
+ _setItem(key, value);
+ }
+
+ String putIfAbsent(String key, String ifAbsent()) {
+ if (!containsKey(key)) this[key] = ifAbsent();
+ return this[key];
+ }
+
+ String remove(Object key) {
+ final value = this[key];
+ _removeItem(key);
+ return value;
+ }
+
+ void clear() => _clear();
+
+ void forEach(void f(String key, String value)) {
+ for (var i = 0; true; i++) {
+ final key = _key(i);
+ if (key == null) return;
+
+ f(key, this[key]);
+ }
+ }
+
+ Iterable<String> get keys {
+ final keys = <String>[];
+ forEach((k, v) => keys.add(k));
+ return keys;
+ }
+
+ Iterable<String> get values {
+ final values = <String>[];
+ forEach((k, v) => values.add(v));
+ return values;
+ }
+
+ int get length => _length;
+
+ bool get isEmpty => _key(0) == null;
+
+ bool get isNotEmpty => !isEmpty;
+ // To suppress missing implicit constructor warnings.
+ factory Storage._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('length')
+ final int _length;
+
+ @JSName('clear')
+ void _clear() native;
+
+ @JSName('getItem')
+ String _getItem(String key) native;
+
+ @JSName('key')
+ String _key(int index) native;
+
+ @JSName('removeItem')
+ void _removeItem(String key) native;
+
+ @JSName('setItem')
+ void _setItem(String key, String value) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void StorageErrorCallback(DomError error);
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Unstable()
+@Native("StorageEvent")
+class StorageEvent extends Event {
+ factory StorageEvent(String type,
+ {bool canBubble: false,
+ bool cancelable: false,
+ String key,
+ String oldValue,
+ String newValue,
+ String url,
+ Storage storageArea}) {
+ StorageEvent e = document._createEvent("StorageEvent");
+ e._initStorageEvent(
+ type, canBubble, cancelable, key, oldValue, newValue, url, storageArea);
+ return e;
+ }
+
+ factory StorageEvent._(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return StorageEvent._create_1(type, eventInitDict_1);
+ }
+ return StorageEvent._create_2(type);
+ }
+ static StorageEvent _create_1(type, eventInitDict) =>
+ JS('StorageEvent', 'new StorageEvent(#,#)', type, eventInitDict);
+ static StorageEvent _create_2(type) =>
+ JS('StorageEvent', 'new StorageEvent(#)', type);
+
+ final String key;
+
+ final String newValue;
+
+ final String oldValue;
+
+ final Storage storageArea;
+
+ final String url;
+
+ @JSName('initStorageEvent')
+ void _initStorageEvent(
+ String typeArg,
+ bool canBubbleArg,
+ bool cancelableArg,
+ String keyArg,
+ String oldValueArg,
+ String newValueArg,
+ String urlArg,
+ Storage storageAreaArg) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StorageManager")
+class StorageManager extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory StorageManager._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future<Map<String, dynamic>> estimate() =>
+ promiseToFutureAsMap(JS("", "#.estimate()", this));
+
+ Future<bool> persist() => promiseToFuture<bool>(JS("", "#.persist()", this));
+
+ Future<bool> persisted() =>
+ promiseToFuture<bool>(JS("", "#.persisted()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void StorageQuotaCallback(int grantedQuotaInBytes);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void StorageUsageCallback(
+ int currentUsageInBytes, int currentQuotaInBytes);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLStyleElement")
+class StyleElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory StyleElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory StyleElement() => JS(
+ 'returns:StyleElement;creates:StyleElement;new:true',
+ '#.createElement(#)',
+ document,
+ "style");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ StyleElement.created() : super.created();
+
+ bool disabled;
+
+ String media;
+
+ final StyleSheet sheet;
+
+ String type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StyleMedia")
+class StyleMedia extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory StyleMedia._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String type;
+
+ bool matchMedium(String mediaquery) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StylePropertyMap")
+class StylePropertyMap extends StylePropertyMapReadonly {
+ // To suppress missing implicit constructor warnings.
+ factory StylePropertyMap._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void append(String property, Object value) native;
+
+ void delete(String property) native;
+
+ void set(String property, Object value) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StylePropertyMapReadonly")
+class StylePropertyMapReadonly extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory StylePropertyMapReadonly._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ CssStyleValue get(String property) native;
+
+ List<CssStyleValue> getAll(String property) native;
+
+ List<String> getProperties() native;
+
+ bool has(String property) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StyleSheet")
+class StyleSheet extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory StyleSheet._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ bool disabled;
+
+ final String href;
+
+ final MediaList media;
+
+ final Node ownerNode;
+
+ final StyleSheet parentStyleSheet;
+
+ final String title;
+
+ final String type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SyncEvent")
+class SyncEvent extends ExtendableEvent {
+ // To suppress missing implicit constructor warnings.
+ factory SyncEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SyncEvent(String type, Map init) {
+ var init_1 = convertDartToNative_Dictionary(init);
+ return SyncEvent._create_1(type, init_1);
+ }
+ static SyncEvent _create_1(type, init) =>
+ JS('SyncEvent', 'new SyncEvent(#,#)', type, init);
+
+ final bool lastChance;
+
+ final String tag;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SyncManager")
+class SyncManager extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory SyncManager._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future<List<String>> getTags() =>
+ promiseToFuture<List<String>>(JS("", "#.getTags()", this));
+
+ Future register(String tag) =>
+ promiseToFuture(JS("", "#.register(#)", this, tag));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTableCaptionElement")
+class TableCaptionElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory TableCaptionElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TableCaptionElement() => JS(
+ 'returns:TableCaptionElement;creates:TableCaptionElement;new:true',
+ '#.createElement(#)',
+ document,
+ "caption");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TableCaptionElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native(
+ "HTMLTableCellElement,HTMLTableDataCellElement,HTMLTableHeaderCellElement")
+class TableCellElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory TableCellElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TableCellElement() => JS(
+ 'returns:TableCellElement;creates:TableCellElement;new:true',
+ '#.createElement(#)',
+ document,
+ "td");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TableCellElement.created() : super.created();
+
+ final int cellIndex;
+
+ int colSpan;
+
+ String headers;
+
+ int rowSpan;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTableColElement")
+class TableColElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory TableColElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TableColElement() => JS(
+ 'returns:TableColElement;creates:TableColElement;new:true',
+ '#.createElement(#)',
+ document,
+ "col");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TableColElement.created() : super.created();
+
+ int span;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTableElement")
+class TableElement extends HtmlElement {
+ List<TableSectionElement> get tBodies =>
+ new _WrappedList<TableSectionElement>(_tBodies);
+
+ List<TableRowElement> get rows => new _WrappedList<TableRowElement>(_rows);
+
+ TableRowElement addRow() {
+ return insertRow(-1);
+ }
+
+ TableCaptionElement createCaption() => _createCaption();
+ TableSectionElement createTBody() => _createTBody();
+ TableSectionElement createTFoot() => _createTFoot();
+ TableSectionElement createTHead() => _createTHead();
+ TableRowElement insertRow(int index) => _insertRow(index);
+
+ TableSectionElement _createTBody() {
+ if (JS('bool', '!!#.createTBody', this)) {
+ return this._nativeCreateTBody();
+ }
+ var tbody = new Element.tag('tbody');
+ this.children.add(tbody);
+ return tbody;
+ }
+
+ @JSName('createTBody')
+ TableSectionElement _nativeCreateTBody() native;
+
+ DocumentFragment createFragment(String html,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ if (Range.supportsCreateContextualFragment) {
+ return super.createFragment(html,
+ validator: validator, treeSanitizer: treeSanitizer);
+ }
+ // IE9 workaround which does not support innerHTML on Table elements.
+ var contextualHtml = '<table>$html</table>';
+ var table = new Element.html(contextualHtml,
+ validator: validator, treeSanitizer: treeSanitizer);
+ var fragment = new DocumentFragment();
+ fragment.nodes.addAll(table.nodes);
+
+ return fragment;
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory TableElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TableElement() => JS(
+ 'returns:TableElement;creates:TableElement;new:true',
+ '#.createElement(#)',
+ document,
+ "table");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TableElement.created() : super.created();
+
+ TableCaptionElement caption;
+
+ @JSName('rows')
+ @Returns('HtmlCollection|Null')
+ @Creates('HtmlCollection')
+ final List<Node> _rows;
+
+ @JSName('tBodies')
+ @Returns('HtmlCollection|Null')
+ @Creates('HtmlCollection')
+ final List<Node> _tBodies;
+
+ TableSectionElement tFoot;
+
+ TableSectionElement tHead;
+
+ @JSName('createCaption')
+ TableCaptionElement _createCaption() native;
+
+ @JSName('createTFoot')
+ TableSectionElement _createTFoot() native;
+
+ @JSName('createTHead')
+ TableSectionElement _createTHead() native;
+
+ void deleteCaption() native;
+
+ void deleteRow(int index) native;
+
+ void deleteTFoot() native;
+
+ void deleteTHead() native;
+
+ @JSName('insertRow')
+ TableRowElement _insertRow([int index]) native;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTableRowElement")
+class TableRowElement extends HtmlElement {
+ List<TableCellElement> get cells =>
+ new _WrappedList<TableCellElement>(_cells);
+
+ TableCellElement addCell() {
+ return insertCell(-1);
+ }
+
+ TableCellElement insertCell(int index) => _insertCell(index);
+
+ DocumentFragment createFragment(String html,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ if (Range.supportsCreateContextualFragment) {
+ return super.createFragment(html,
+ validator: validator, treeSanitizer: treeSanitizer);
+ }
+ // IE9 workaround which does not support innerHTML on Table elements.
+ var fragment = new DocumentFragment();
+ var section = new TableElement()
+ .createFragment(html,
+ validator: validator, treeSanitizer: treeSanitizer)
+ .nodes
+ .single;
+ var row = section.nodes.single;
+ fragment.nodes.addAll(row.nodes);
+ return fragment;
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory TableRowElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TableRowElement() => JS(
+ 'returns:TableRowElement;creates:TableRowElement;new:true',
+ '#.createElement(#)',
+ document,
+ "tr");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TableRowElement.created() : super.created();
+
+ @JSName('cells')
+ @Returns('HtmlCollection|Null')
+ @Creates('HtmlCollection')
+ final List<Node> _cells;
+
+ final int rowIndex;
+
+ final int sectionRowIndex;
+
+ void deleteCell(int index) native;
+
+ @JSName('insertCell')
+ HtmlElement _insertCell([int index]) native;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTableSectionElement")
+class TableSectionElement extends HtmlElement {
+ List<TableRowElement> get rows => new _WrappedList<TableRowElement>(_rows);
+
+ TableRowElement addRow() {
+ return insertRow(-1);
+ }
+
+ TableRowElement insertRow(int index) => _insertRow(index);
+
+ DocumentFragment createFragment(String html,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ if (Range.supportsCreateContextualFragment) {
+ return super.createFragment(html,
+ validator: validator, treeSanitizer: treeSanitizer);
+ }
+ // IE9 workaround which does not support innerHTML on Table elements.
+ var fragment = new DocumentFragment();
+ var section = new TableElement()
+ .createFragment(html,
+ validator: validator, treeSanitizer: treeSanitizer)
+ .nodes
+ .single;
+ fragment.nodes.addAll(section.nodes);
+ return fragment;
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory TableSectionElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TableSectionElement.created() : super.created();
+
+ @JSName('rows')
+ @Returns('HtmlCollection|Null')
+ @Creates('HtmlCollection')
+ final List<Node> _rows;
+
+ void deleteRow(int index) native;
+
+ @JSName('insertRow')
+ HtmlElement _insertRow([int index]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TaskAttributionTiming")
+class TaskAttributionTiming extends PerformanceEntry {
+ // To suppress missing implicit constructor warnings.
+ factory TaskAttributionTiming._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String containerId;
+
+ final String containerName;
+
+ final String containerSrc;
+
+ final String containerType;
+
+ @JSName('scriptURL')
+ final String scriptUrl;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("HTMLTemplateElement")
+class TemplateElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory TemplateElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TemplateElement() => document.createElement("template");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TemplateElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Element.isTagSupported('template');
+
+ final DocumentFragment content;
+
+ /**
+ * An override to place the contents into content rather than as child nodes.
+ *
+ * See also:
+ *
+ * * <https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin>
+ */
+ void setInnerHtml(String html,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ text = null;
+ content.nodes.clear();
+ var fragment = createFragment(html,
+ validator: validator, treeSanitizer: treeSanitizer);
+
+ content.append(fragment);
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("Text")
+class Text extends CharacterData {
+ factory Text(String data) => JS(
+ 'returns:Text;depends:none;effects:none;new:true',
+ '#.createTextNode(#)',
+ document,
+ data);
+ // To suppress missing implicit constructor warnings.
+ factory Text._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final SlotElement assignedSlot;
+
+ final String wholeText;
+
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ List<Node> getDestinationInsertionPoints() native;
+
+ Text splitText(int offset) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTextAreaElement")
+class TextAreaElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory TextAreaElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TextAreaElement() => JS(
+ 'returns:TextAreaElement;creates:TextAreaElement;new:true',
+ '#.createElement(#)',
+ document,
+ "textarea");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TextAreaElement.created() : super.created();
+
+ String autocapitalize;
+
+ bool autofocus;
+
+ int cols;
+
+ String defaultValue;
+
+ String dirName;
+
+ bool disabled;
+
+ final FormElement form;
+
+ @Unstable()
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ final List<Node> labels;
+
+ int maxLength;
+
+ int minLength;
+
+ String name;
+
+ String placeholder;
+
+ bool readOnly;
+
+ bool required;
+
+ int rows;
+
+ String selectionDirection;
+
+ int selectionEnd;
+
+ int selectionStart;
+
+ final int textLength;
+
+ final String type;
+
+ final String validationMessage;
+
+ final ValidityState validity;
+
+ String value;
+
+ final bool willValidate;
+
+ String wrap;
+
+ bool checkValidity() native;
+
+ bool reportValidity() native;
+
+ void select() native;
+
+ void setCustomValidity(String error) native;
+
+ void setRangeText(String replacement,
+ {int start, int end, String selectionMode}) native;
+
+ void setSelectionRange(int start, int end, [String direction]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TextDetector")
+class TextDetector extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory TextDetector._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TextDetector() {
+ return TextDetector._create_1();
+ }
+ static TextDetector _create_1() => JS('TextDetector', 'new TextDetector()');
+
+ Future<List<DetectedText>> detect(/*ImageBitmapSource*/ image) =>
+ promiseToFuture<List<DetectedText>>(JS("", "#.detect(#)", this, image));
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Unstable()
+@Native("TextEvent")
+class TextEvent extends UIEvent {
+ factory TextEvent(String type,
+ {bool canBubble: false,
+ bool cancelable: false,
+ Window view,
+ String data}) {
+ if (view == null) {
+ view = window;
+ }
+ TextEvent e = document._createEvent("TextEvent");
+ e._initTextEvent(type, canBubble, cancelable, view, data);
+ return e;
+ }
+ // To suppress missing implicit constructor warnings.
+ factory TextEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String data;
+
+ @JSName('initTextEvent')
+ void _initTextEvent(String type, bool bubbles, bool cancelable, Window view,
+ String data) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TextMetrics")
+class TextMetrics extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory TextMetrics._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num actualBoundingBoxAscent;
+
+ final num actualBoundingBoxDescent;
+
+ final num actualBoundingBoxLeft;
+
+ final num actualBoundingBoxRight;
+
+ final num alphabeticBaseline;
+
+ final num emHeightAscent;
+
+ final num emHeightDescent;
+
+ final num fontBoundingBoxAscent;
+
+ final num fontBoundingBoxDescent;
+
+ final num hangingBaseline;
+
+ final num ideographicBaseline;
+
+ final num width;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TextTrack")
+class TextTrack extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory TextTrack._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `cuechange` events to event
+ * handlers that are not necessarily instances of [TextTrack].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> cueChangeEvent =
+ const EventStreamProvider<Event>('cuechange');
+
+ final TextTrackCueList activeCues;
+
+ final TextTrackCueList cues;
+
+ final String id;
+
+ final String kind;
+
+ final String label;
+
+ final String language;
+
+ String mode;
+
+ void addCue(TextTrackCue cue) native;
+
+ void removeCue(TextTrackCue cue) native;
+
+ /// Stream of `cuechange` events handled by this [TextTrack].
+ Stream<Event> get onCueChange => cueChangeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TextTrackCue")
+class TextTrackCue extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory TextTrackCue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `enter` events to event
+ * handlers that are not necessarily instances of [TextTrackCue].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> enterEvent =
+ const EventStreamProvider<Event>('enter');
+
+ /**
+ * Static factory designed to expose `exit` events to event
+ * handlers that are not necessarily instances of [TextTrackCue].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> exitEvent =
+ const EventStreamProvider<Event>('exit');
+
+ num endTime;
+
+ String id;
+
+ bool pauseOnExit;
+
+ num startTime;
+
+ final TextTrack track;
+
+ /// Stream of `enter` events handled by this [TextTrackCue].
+ Stream<Event> get onEnter => enterEvent.forTarget(this);
+
+ /// Stream of `exit` events handled by this [TextTrackCue].
+ Stream<Event> get onExit => exitEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TextTrackCueList")
+class TextTrackCueList extends Interceptor
+ with ListMixin<TextTrackCue>, ImmutableListMixin<TextTrackCue>
+ implements List<TextTrackCue>, JavaScriptIndexingBehavior<TextTrackCue> {
+ // To suppress missing implicit constructor warnings.
+ factory TextTrackCueList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ TextTrackCue operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("TextTrackCue", "#[#]", this, index);
+ }
+
+ void operator []=(int index, TextTrackCue value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<TextTrackCue> mixins.
+ // TextTrackCue is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ TextTrackCue get first {
+ if (this.length > 0) {
+ return JS('TextTrackCue', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ TextTrackCue get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('TextTrackCue', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ TextTrackCue get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('TextTrackCue', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ TextTrackCue elementAt(int index) => this[index];
+ // -- end List<TextTrackCue> mixins.
+
+ TextTrackCue __getter__(int index) native;
+
+ TextTrackCue getCueById(String id) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TextTrackList")
+class TextTrackList extends EventTarget
+ with ListMixin<TextTrack>, ImmutableListMixin<TextTrack>
+ implements List<TextTrack>, JavaScriptIndexingBehavior<TextTrack> {
+ // To suppress missing implicit constructor warnings.
+ factory TextTrackList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `addtrack` events to event
+ * handlers that are not necessarily instances of [TextTrackList].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<TrackEvent> addTrackEvent =
+ const EventStreamProvider<TrackEvent>('addtrack');
+
+ static const EventStreamProvider<Event> changeEvent =
+ const EventStreamProvider<Event>('change');
+
+ int get length => JS("int", "#.length", this);
+
+ TextTrack operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("TextTrack", "#[#]", this, index);
+ }
+
+ void operator []=(int index, TextTrack value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<TextTrack> mixins.
+ // TextTrack is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ TextTrack get first {
+ if (this.length > 0) {
+ return JS('TextTrack', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ TextTrack get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('TextTrack', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ TextTrack get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('TextTrack', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ TextTrack elementAt(int index) => this[index];
+ // -- end List<TextTrack> mixins.
+
+ TextTrack __getter__(int index) native;
+
+ TextTrack getTrackById(String id) native;
+
+ /// Stream of `addtrack` events handled by this [TextTrackList].
+ Stream<TrackEvent> get onAddTrack => addTrackEvent.forTarget(this);
+
+ Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTimeElement")
+class TimeElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory TimeElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TimeElement.created() : super.created();
+
+ String dateTime;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("TimeRanges")
+class TimeRanges extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory TimeRanges._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int length;
+
+ double end(int index) native;
+
+ double start(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void TimeoutHandler();
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLTitleElement")
+class TitleElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory TitleElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TitleElement() => JS(
+ 'returns:TitleElement;creates:TitleElement;new:true',
+ '#.createElement(#)',
+ document,
+ "title");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TitleElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Touch")
+class Touch extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Touch._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory Touch(Map initDict) {
+ var initDict_1 = convertDartToNative_Dictionary(initDict);
+ return Touch._create_1(initDict_1);
+ }
+ static Touch _create_1(initDict) => JS('Touch', 'new Touch(#)', initDict);
+
+ @JSName('clientX')
+ final num _clientX;
+
+ @JSName('clientY')
+ final num _clientY;
+
+ final num force;
+
+ final int identifier;
+
+ @JSName('pageX')
+ final num _pageX;
+
+ @JSName('pageY')
+ final num _pageY;
+
+ @JSName('radiusX')
+ final num _radiusX;
+
+ @JSName('radiusY')
+ final num _radiusY;
+
+ final String region;
+
+ final num rotationAngle;
+
+ @JSName('screenX')
+ final num _screenX;
+
+ @JSName('screenY')
+ final num _screenY;
+
+ EventTarget get target => _convertNativeToDart_EventTarget(this._get_target);
+ @JSName('target')
+ @Creates('Element|Document')
+ @Returns('Element|Document')
+ final dynamic _get_target;
+
+// As of Chrome 37, these all changed from long to double. This code
+// preserves backwards compatibility for the time being.
+ int get __clientX => JS<num>('num', '#.clientX', this).round();
+ int get __clientY => JS<num>('num', '#.clientY', this).round();
+ int get __screenX => JS<num>('num', '#.screenX', this).round();
+ int get __screenY => JS<num>('num', '#.screenY', this).round();
+ int get __pageX => JS<num>('num', '#.pageX', this).round();
+ int get __pageY => JS<num>('num', '#.pageY', this).round();
+ int get __radiusX => JS<num>('num', '#.radiusX', this).round();
+ int get __radiusY => JS<num>('num', '#.radiusY', this).round();
+
+ Point get client => new Point(__clientX, __clientY);
+
+ Point get page => new Point(__pageX, __pageY);
+
+ Point get screen => new Point(__screenX, __screenY);
+
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ int get radiusX => __radiusX;
+
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ int get radiusY => __radiusY;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("TouchEvent")
+class TouchEvent extends UIEvent {
+ // To suppress missing implicit constructor warnings.
+ factory TouchEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TouchEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return TouchEvent._create_1(type, eventInitDict_1);
+ }
+ return TouchEvent._create_2(type);
+ }
+ static TouchEvent _create_1(type, eventInitDict) =>
+ JS('TouchEvent', 'new TouchEvent(#,#)', type, eventInitDict);
+ static TouchEvent _create_2(type) =>
+ JS('TouchEvent', 'new TouchEvent(#)', type);
+
+ final bool altKey;
+
+ final TouchList changedTouches;
+
+ final bool ctrlKey;
+
+ final bool metaKey;
+
+ final bool shiftKey;
+
+ final TouchList targetTouches;
+
+ final TouchList touches;
+
+ /**
+ * Checks if touch events supported on the current platform.
+ */
+ static bool get supported {
+ try {
+ return TouchEvent('touches') is TouchEvent;
+ } catch (_) {}
+
+ return false;
+ }
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("TouchList")
+class TouchList extends Interceptor
+ with ListMixin<Touch>, ImmutableListMixin<Touch>
+ implements JavaScriptIndexingBehavior<Touch>, List<Touch> {
+ /// NB: This constructor likely does not work as you might expect it to! This
+ /// constructor will simply fail (returning null) if you are not on a device
+ /// with touch enabled. See dartbug.com/8314.
+ // TODO(5760): createTouchList now uses varargs.
+ factory TouchList() => null; //document._createTouchList();
+ // To suppress missing implicit constructor warnings.
+ factory TouchList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => JS('bool', '!!document.createTouchList');
+
+ int get length => JS("int", "#.length", this);
+
+ Touch operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("Touch", "#[#]", this, index);
+ }
+
+ void operator []=(int index, Touch value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<Touch> mixins.
+ // Touch is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ Touch get first {
+ if (this.length > 0) {
+ return JS('Touch', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ Touch get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('Touch', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ Touch get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('Touch', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ Touch elementAt(int index) => this[index];
+ // -- end List<Touch> mixins.
+
+ Touch item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TrackDefault")
+class TrackDefault extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory TrackDefault._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TrackDefault(
+ String type, String language, String label, List<String> kinds,
+ [String byteStreamTrackID]) {
+ if (byteStreamTrackID != null) {
+ List kinds_1 = convertDartToNative_StringArray(kinds);
+ return TrackDefault._create_1(
+ type, language, label, kinds_1, byteStreamTrackID);
+ }
+ List kinds_1 = convertDartToNative_StringArray(kinds);
+ return TrackDefault._create_2(type, language, label, kinds_1);
+ }
+ static TrackDefault _create_1(
+ type, language, label, kinds, byteStreamTrackID) =>
+ JS('TrackDefault', 'new TrackDefault(#,#,#,#,#)', type, language, label,
+ kinds, byteStreamTrackID);
+ static TrackDefault _create_2(type, language, label, kinds) => JS(
+ 'TrackDefault',
+ 'new TrackDefault(#,#,#,#)',
+ type,
+ language,
+ label,
+ kinds);
+
+ final String byteStreamTrackID;
+
+ final Object kinds;
+
+ final String label;
+
+ final String language;
+
+ final String type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TrackDefaultList")
+class TrackDefaultList extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory TrackDefaultList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TrackDefaultList([List<TrackDefault> trackDefaults]) {
+ if (trackDefaults != null) {
+ return TrackDefaultList._create_1(trackDefaults);
+ }
+ return TrackDefaultList._create_2();
+ }
+ static TrackDefaultList _create_1(trackDefaults) =>
+ JS('TrackDefaultList', 'new TrackDefaultList(#)', trackDefaults);
+ static TrackDefaultList _create_2() =>
+ JS('TrackDefaultList', 'new TrackDefaultList()');
+
+ final int length;
+
+ TrackDefault item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("HTMLTrackElement")
+class TrackElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory TrackElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TrackElement() => document.createElement("track");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TrackElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => Element.isTagSupported('track');
+
+ static const int ERROR = 3;
+
+ static const int LOADED = 2;
+
+ static const int LOADING = 1;
+
+ static const int NONE = 0;
+
+ @JSName('default')
+ bool defaultValue;
+
+ String kind;
+
+ String label;
+
+ final int readyState;
+
+ String src;
+
+ String srclang;
+
+ final TextTrack track;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("TrackEvent")
+class TrackEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory TrackEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TrackEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return TrackEvent._create_1(type, eventInitDict_1);
+ }
+ return TrackEvent._create_2(type);
+ }
+ static TrackEvent _create_1(type, eventInitDict) =>
+ JS('TrackEvent', 'new TrackEvent(#,#)', type, eventInitDict);
+ static TrackEvent _create_2(type) =>
+ JS('TrackEvent', 'new TrackEvent(#)', type);
+
+ @Creates('Null')
+ final Object track;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TransitionEvent,WebKitTransitionEvent")
+class TransitionEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory TransitionEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TransitionEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return TransitionEvent._create_1(type, eventInitDict_1);
+ }
+ return TransitionEvent._create_2(type);
+ }
+ static TransitionEvent _create_1(type, eventInitDict) =>
+ JS('TransitionEvent', 'new TransitionEvent(#,#)', type, eventInitDict);
+ static TransitionEvent _create_2(type) =>
+ JS('TransitionEvent', 'new TransitionEvent(#)', type);
+
+ final num elapsedTime;
+
+ final String propertyName;
+
+ final String pseudoElement;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("TreeWalker")
+class TreeWalker extends Interceptor {
+ factory TreeWalker(Node root, int whatToShow) {
+ return document._createTreeWalker(root, whatToShow, null);
+ }
+ // To suppress missing implicit constructor warnings.
+ factory TreeWalker._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Node currentNode;
+
+ final NodeFilter filter;
+
+ final Node root;
+
+ final int whatToShow;
+
+ Node firstChild() native;
+
+ Node lastChild() native;
+
+ Node nextNode() native;
+
+ Node nextSibling() native;
+
+ Node parentNode() native;
+
+ Node previousNode() native;
+
+ Node previousSibling() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TrustedHTML")
+class TrustedHtml extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory TrustedHtml._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static TrustedHtml escape(String html) native;
+
+ static TrustedHtml unsafelyCreate(String html) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TrustedScriptURL")
+class TrustedScriptUrl extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory TrustedScriptUrl._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static TrustedScriptUrl unsafelyCreate(String url) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("TrustedURL")
+class TrustedUrl extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory TrustedUrl._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static TrustedUrl create(String url) native;
+
+ static TrustedUrl unsafelyCreate(String url) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+@Native("UIEvent")
+class UIEvent extends Event {
+ // In JS, canBubble and cancelable are technically required parameters to
+ // init*Event. In practice, though, if they aren't provided they simply
+ // default to false (since that's Boolean(undefined)).
+ //
+ // Contrary to JS, we default canBubble and cancelable to true, since that's
+ // what people want most of the time anyway.
+ factory UIEvent(String type,
+ {Window view,
+ int detail: 0,
+ bool canBubble: true,
+ bool cancelable: true}) {
+ if (view == null) {
+ view = window;
+ }
+ UIEvent e = document._createEvent("UIEvent");
+ e._initUIEvent(type, canBubble, cancelable, view, detail);
+ return e;
+ }
+
+ factory UIEvent._(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return UIEvent._create_1(type, eventInitDict_1);
+ }
+ return UIEvent._create_2(type);
+ }
+ static UIEvent _create_1(type, eventInitDict) =>
+ JS('UIEvent', 'new UIEvent(#,#)', type, eventInitDict);
+ static UIEvent _create_2(type) => JS('UIEvent', 'new UIEvent(#)', type);
+
+ final int detail;
+
+ final InputDeviceCapabilities sourceCapabilities;
+
+ WindowBase get view => _convertNativeToDart_Window(this._get_view);
+ @JSName('view')
+ @Creates('Window|=Object')
+ @Returns('Window|=Object')
+ final dynamic _get_view;
+
+ @JSName('which')
+ @Unstable()
+ final int _which;
+
+ @JSName('initUIEvent')
+ void _initUIEvent(String type, bool bubbles, bool cancelable, Window view,
+ int detail) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLUListElement")
+class UListElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory UListElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory UListElement() => JS(
+ 'returns:UListElement;creates:UListElement;new:true',
+ '#.createElement(#)',
+ document,
+ "ul");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ UListElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("UnderlyingSourceBase")
+class UnderlyingSourceBase extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory UnderlyingSourceBase._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future cancel(Object reason) =>
+ promiseToFuture(JS("", "#.cancel(#)", this, reason));
+
+ void notifyLockAcquired() native;
+
+ void notifyLockReleased() native;
+
+ Future pull() => promiseToFuture(JS("", "#.pull()", this));
+
+ Future start(Object stream) =>
+ promiseToFuture(JS("", "#.start(#)", this, stream));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLUnknownElement")
+class UnknownElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory UnknownElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ UnknownElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("URL")
+class Url extends Interceptor {
+ static String createObjectUrl(blob_OR_source_OR_stream) => JS(
+ 'String',
+ '(self.URL || self.webkitURL).createObjectURL(#)',
+ blob_OR_source_OR_stream);
+
+ static String createObjectUrlFromSource(MediaSource source) =>
+ JS('String', '(self.URL || self.webkitURL).createObjectURL(#)', source);
+
+ static String createObjectUrlFromStream(MediaStream stream) =>
+ JS('String', '(self.URL || self.webkitURL).createObjectURL(#)', stream);
+
+ static String createObjectUrlFromBlob(Blob blob) =>
+ JS('String', '(self.URL || self.webkitURL).createObjectURL(#)', blob);
+
+ static void revokeObjectUrl(String url) =>
+ JS('void', '(self.URL || self.webkitURL).revokeObjectURL(#)', url);
+
+ String toString() => JS('String', 'String(#)', this);
+
+ // To suppress missing implicit constructor warnings.
+ factory Url._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String hash;
+
+ String host;
+
+ String hostname;
+
+ String href;
+
+ final String origin;
+
+ String password;
+
+ String pathname;
+
+ String port;
+
+ String protocol;
+
+ String search;
+
+ final UrlSearchParams searchParams;
+
+ String username;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("URLSearchParams")
+class UrlSearchParams extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory UrlSearchParams._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory UrlSearchParams([Object init]) {
+ if (init != null) {
+ return UrlSearchParams._create_1(init);
+ }
+ return UrlSearchParams._create_2();
+ }
+ static UrlSearchParams _create_1(init) =>
+ JS('UrlSearchParams', 'new URLSearchParams(#)', init);
+ static UrlSearchParams _create_2() =>
+ JS('UrlSearchParams', 'new URLSearchParams()');
+
+ void append(String name, String value) native;
+
+ void delete(String name) native;
+
+ String get(String name) native;
+
+ List<String> getAll(String name) native;
+
+ bool has(String name) native;
+
+ void set(String name, String value) native;
+
+ void sort() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class UrlUtilsReadOnly extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory UrlUtilsReadOnly._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String hash;
+
+ final String host;
+
+ final String hostname;
+
+ final String href;
+
+ final String origin;
+
+ final String pathname;
+
+ final String port;
+
+ final String protocol;
+
+ final String search;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VR")
+class VR extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory VR._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future getDevices() => promiseToFuture(JS("", "#.getDevices()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRCoordinateSystem")
+class VRCoordinateSystem extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VRCoordinateSystem._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Float32List getTransformTo(VRCoordinateSystem other) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRDevice")
+class VRDevice extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory VRDevice._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String deviceName;
+
+ final bool isExternal;
+
+ Future requestSession([Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture(JS("", "#.requestSession(#)", this, options_dict));
+ }
+
+ Future supportsSession([Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture(JS("", "#.supportsSession(#)", this, options_dict));
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRDeviceEvent")
+class VRDeviceEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory VRDeviceEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory VRDeviceEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return VRDeviceEvent._create_1(type, eventInitDict_1);
+ }
+ static VRDeviceEvent _create_1(type, eventInitDict) =>
+ JS('VRDeviceEvent', 'new VRDeviceEvent(#,#)', type, eventInitDict);
+
+ final VRDevice device;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRDisplay")
+class VRDisplay extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory VRDisplay._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final VRDisplayCapabilities capabilities;
+
+ num depthFar;
+
+ num depthNear;
+
+ final int displayId;
+
+ final String displayName;
+
+ final bool isPresenting;
+
+ final VRStageParameters stageParameters;
+
+ void cancelAnimationFrame(int handle) native;
+
+ Future exitPresent() => promiseToFuture(JS("", "#.exitPresent()", this));
+
+ VREyeParameters getEyeParameters(String whichEye) native;
+
+ bool getFrameData(VRFrameData frameData) native;
+
+ List<Map> getLayers() native;
+
+ int requestAnimationFrame(FrameRequestCallback callback) native;
+
+ Future requestPresent(List<Map> layers) =>
+ promiseToFuture(JS("", "#.requestPresent(#)", this, layers));
+
+ void submitFrame() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRDisplayCapabilities")
+class VRDisplayCapabilities extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VRDisplayCapabilities._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool canPresent;
+
+ final bool hasExternalDisplay;
+
+ final bool hasPosition;
+
+ final int maxLayers;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRDisplayEvent")
+class VRDisplayEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory VRDisplayEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory VRDisplayEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return VRDisplayEvent._create_1(type, eventInitDict_1);
+ }
+ return VRDisplayEvent._create_2(type);
+ }
+ static VRDisplayEvent _create_1(type, eventInitDict) =>
+ JS('VRDisplayEvent', 'new VRDisplayEvent(#,#)', type, eventInitDict);
+ static VRDisplayEvent _create_2(type) =>
+ JS('VRDisplayEvent', 'new VRDisplayEvent(#)', type);
+
+ final VRDisplay display;
+
+ final String reason;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VREyeParameters")
+class VREyeParameters extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VREyeParameters._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Float32List offset;
+
+ final int renderHeight;
+
+ final int renderWidth;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRFrameData")
+class VRFrameData extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VRFrameData._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory VRFrameData() {
+ return VRFrameData._create_1();
+ }
+ static VRFrameData _create_1() => JS('VRFrameData', 'new VRFrameData()');
+
+ final Float32List leftProjectionMatrix;
+
+ final Float32List leftViewMatrix;
+
+ final VRPose pose;
+
+ final Float32List rightProjectionMatrix;
+
+ final Float32List rightViewMatrix;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRFrameOfReference")
+class VRFrameOfReference extends VRCoordinateSystem {
+ // To suppress missing implicit constructor warnings.
+ factory VRFrameOfReference._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final VRStageBounds bounds;
+
+ final num emulatedHeight;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRPose")
+class VRPose extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VRPose._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Float32List angularAcceleration;
+
+ final Float32List angularVelocity;
+
+ final Float32List linearAcceleration;
+
+ final Float32List linearVelocity;
+
+ final Float32List orientation;
+
+ final Float32List position;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRSession")
+class VRSession extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory VRSession._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> blurEvent =
+ const EventStreamProvider<Event>('blur');
+
+ static const EventStreamProvider<Event> focusEvent =
+ const EventStreamProvider<Event>('focus');
+
+ num depthFar;
+
+ num depthNear;
+
+ final VRDevice device;
+
+ final bool exclusive;
+
+ Future end() => promiseToFuture(JS("", "#.end()", this));
+
+ Future requestFrameOfReference(String type, [Map options]) {
+ var options_dict = null;
+ if (options != null) {
+ options_dict = convertDartToNative_Dictionary(options);
+ }
+ return promiseToFuture(
+ JS("", "#.requestFrameOfReference(#, #)", this, type, options_dict));
+ }
+
+ Stream<Event> get onBlur => blurEvent.forTarget(this);
+
+ Stream<Event> get onFocus => focusEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRSessionEvent")
+class VRSessionEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory VRSessionEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory VRSessionEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return VRSessionEvent._create_1(type, eventInitDict_1);
+ }
+ static VRSessionEvent _create_1(type, eventInitDict) =>
+ JS('VRSessionEvent', 'new VRSessionEvent(#,#)', type, eventInitDict);
+
+ final VRSession session;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRStageBounds")
+class VRStageBounds extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VRStageBounds._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final List<VRStageBoundsPoint> geometry;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRStageBoundsPoint")
+class VRStageBoundsPoint extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VRStageBoundsPoint._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num x;
+
+ final num z;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VRStageParameters")
+class VRStageParameters extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VRStageParameters._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Float32List sittingToStandingTransform;
+
+ final num sizeX;
+
+ final num sizeZ;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ValidityState")
+class ValidityState extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ValidityState._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool badInput;
+
+ final bool customError;
+
+ final bool patternMismatch;
+
+ final bool rangeOverflow;
+
+ final bool rangeUnderflow;
+
+ final bool stepMismatch;
+
+ final bool tooLong;
+
+ final bool tooShort;
+
+ final bool typeMismatch;
+
+ final bool valid;
+
+ final bool valueMissing;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("HTMLVideoElement")
+class VideoElement extends MediaElement implements CanvasImageSource {
+ // To suppress missing implicit constructor warnings.
+ factory VideoElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory VideoElement() => JS(
+ 'returns:VideoElement;creates:VideoElement;new:true',
+ '#.createElement(#)',
+ document,
+ "video");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ VideoElement.created() : super.created();
+
+ int height;
+
+ String poster;
+
+ final int videoHeight;
+
+ final int videoWidth;
+
+ @JSName('webkitDecodedFrameCount')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ final int decodedFrameCount;
+
+ @JSName('webkitDroppedFrameCount')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ final int droppedFrameCount;
+
+ int width;
+
+ VideoPlaybackQuality getVideoPlaybackQuality() native;
+
+ @JSName('webkitEnterFullscreen')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void enterFullscreen() native;
+
+ @JSName('webkitExitFullscreen')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ void exitFullscreen() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VideoPlaybackQuality")
+class VideoPlaybackQuality extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VideoPlaybackQuality._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int corruptedVideoFrames;
+
+ final num creationTime;
+
+ final int droppedVideoFrames;
+
+ final int totalVideoFrames;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VideoTrack")
+class VideoTrack extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VideoTrack._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String id;
+
+ final String kind;
+
+ final String label;
+
+ final String language;
+
+ bool selected;
+
+ final SourceBuffer sourceBuffer;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VideoTrackList")
+class VideoTrackList extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory VideoTrackList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> changeEvent =
+ const EventStreamProvider<Event>('change');
+
+ final int length;
+
+ final int selectedIndex;
+
+ VideoTrack __getter__(int index) native;
+
+ VideoTrack getTrackById(String id) native;
+
+ Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VisualViewport")
+class VisualViewport extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory VisualViewport._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> resizeEvent =
+ const EventStreamProvider<Event>('resize');
+
+ static const EventStreamProvider<Event> scrollEvent =
+ const EventStreamProvider<Event>('scroll');
+
+ final num height;
+
+ final num offsetLeft;
+
+ final num offsetTop;
+
+ final num pageLeft;
+
+ final num pageTop;
+
+ final num scale;
+
+ final num width;
+
+ Stream<Event> get onResize => resizeEvent.forTarget(this);
+
+ Stream<Event> get onScroll => scrollEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void VoidCallback();
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VTTCue")
+class VttCue extends TextTrackCue {
+ // To suppress missing implicit constructor warnings.
+ factory VttCue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory VttCue(num startTime, num endTime, String text) {
+ return VttCue._create_1(startTime, endTime, text);
+ }
+ static VttCue _create_1(startTime, endTime, text) =>
+ JS('VttCue', 'new VTTCue(#,#,#)', startTime, endTime, text);
+
+ String align;
+
+ @Creates('Null')
+ @Returns('num|String')
+ Object line;
+
+ @Creates('Null')
+ @Returns('num|String')
+ Object position;
+
+ VttRegion region;
+
+ num size;
+
+ bool snapToLines;
+
+ String text;
+
+ String vertical;
+
+ @JSName('getCueAsHTML')
+ DocumentFragment getCueAsHtml() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("VTTRegion")
+class VttRegion extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VttRegion._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory VttRegion() {
+ return VttRegion._create_1();
+ }
+ static VttRegion _create_1() => JS('VttRegion', 'new VTTRegion()');
+
+ String id;
+
+ int lines;
+
+ num regionAnchorX;
+
+ num regionAnchorY;
+
+ String scroll;
+
+ num viewportAnchorX;
+
+ num viewportAnchorY;
+
+ num width;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Use the WebSocket interface to connect to a WebSocket,
+ * and to send and receive data on that WebSocket.
+ *
+ * To use a WebSocket in your web app, first create a WebSocket object,
+ * passing the WebSocket URL as an argument to the constructor.
+ *
+ * var webSocket = new WebSocket('ws://127.0.0.1:1337/ws');
+ *
+ * To send data on the WebSocket, use the [send] method.
+ *
+ * if (webSocket != null && webSocket.readyState == WebSocket.OPEN) {
+ * webSocket.send(data);
+ * } else {
+ * print('WebSocket not connected, message $data not sent');
+ * }
+ *
+ * To receive data on the WebSocket, register a listener for message events.
+ *
+ * webSocket.onMessage.listen((MessageEvent e) {
+ * receivedData(e.data);
+ * });
+ *
+ * The message event handler receives a [MessageEvent] object
+ * as its sole argument.
+ * You can also define open, close, and error handlers,
+ * as specified by [WebSocketEvents].
+ *
+ * For more information, see the
+ * [WebSockets](http://www.dartlang.org/docs/library-tour/#html-websockets)
+ * section of the library tour and
+ * [Introducing WebSockets](http://www.html5rocks.com/en/tutorials/websockets/basics/),
+ * an HTML5Rocks.com tutorial.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("WebSocket")
+class WebSocket extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory WebSocket._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `close` events to event
+ * handlers that are not necessarily instances of [WebSocket].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<CloseEvent> closeEvent =
+ const EventStreamProvider<CloseEvent>('close');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [WebSocket].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /**
+ * Static factory designed to expose `message` events to event
+ * handlers that are not necessarily instances of [WebSocket].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ /**
+ * Static factory designed to expose `open` events to event
+ * handlers that are not necessarily instances of [WebSocket].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> openEvent =
+ const EventStreamProvider<Event>('open');
+
+ factory WebSocket(String url, [Object protocols]) {
+ if (protocols != null) {
+ return WebSocket._create_1(url, protocols);
+ }
+ return WebSocket._create_2(url);
+ }
+ static WebSocket _create_1(url, protocols) =>
+ JS('WebSocket', 'new WebSocket(#,#)', url, protocols);
+ static WebSocket _create_2(url) => JS('WebSocket', 'new WebSocket(#)', url);
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ JS('bool', 'typeof window.WebSocket != "undefined"');
+
+ static const int CLOSED = 3;
+
+ static const int CLOSING = 2;
+
+ static const int CONNECTING = 0;
+
+ static const int OPEN = 1;
+
+ String binaryType;
+
+ final int bufferedAmount;
+
+ final String extensions;
+
+ final String protocol;
+
+ final int readyState;
+
+ final String url;
+
+ void close([int code, String reason]) native;
+
+ /**
+ * Transmit data to the server over this connection.
+ *
+ * This method accepts data of type [Blob], [ByteBuffer], [String], or
+ * [TypedData]. Named variants [sendBlob], [sendByteBuffer], [sendString],
+ * or [sendTypedData], in contrast, only accept data of the specified type.
+ */
+ void send(data) native;
+
+ @JSName('send')
+ /**
+ * Transmit data to the server over this connection.
+ *
+ * This method accepts data of type [Blob], [ByteBuffer], [String], or
+ * [TypedData]. Named variants [sendBlob], [sendByteBuffer], [sendString],
+ * or [sendTypedData], in contrast, only accept data of the specified type.
+ */
+ void sendBlob(Blob data) native;
+
+ @JSName('send')
+ /**
+ * Transmit data to the server over this connection.
+ *
+ * This method accepts data of type [Blob], [ByteBuffer], [String], or
+ * [TypedData]. Named variants [sendBlob], [sendByteBuffer], [sendString],
+ * or [sendTypedData], in contrast, only accept data of the specified type.
+ */
+ void sendByteBuffer(ByteBuffer data) native;
+
+ @JSName('send')
+ /**
+ * Transmit data to the server over this connection.
+ *
+ * This method accepts data of type [Blob], [ByteBuffer], [String], or
+ * [TypedData]. Named variants [sendBlob], [sendByteBuffer], [sendString],
+ * or [sendTypedData], in contrast, only accept data of the specified type.
+ */
+ void sendString(String data) native;
+
+ @JSName('send')
+ /**
+ * Transmit data to the server over this connection.
+ *
+ * This method accepts data of type [Blob], [ByteBuffer], [String], or
+ * [TypedData]. Named variants [sendBlob], [sendByteBuffer], [sendString],
+ * or [sendTypedData], in contrast, only accept data of the specified type.
+ */
+ void sendTypedData(TypedData data) native;
+
+ /// Stream of `close` events handled by this [WebSocket].
+ Stream<CloseEvent> get onClose => closeEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [WebSocket].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `message` events handled by this [WebSocket].
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+ /// Stream of `open` events handled by this [WebSocket].
+ Stream<Event> get onOpen => openEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WheelEvent")
+class WheelEvent extends MouseEvent {
+ factory WheelEvent(String type,
+ {Window view,
+ num deltaX: 0,
+ num deltaY: 0,
+ num deltaZ: 0,
+ int deltaMode: 0,
+ int detail: 0,
+ int screenX: 0,
+ int screenY: 0,
+ int clientX: 0,
+ int clientY: 0,
+ int button: 0,
+ bool canBubble: true,
+ bool cancelable: true,
+ bool ctrlKey: false,
+ bool altKey: false,
+ bool shiftKey: false,
+ bool metaKey: false,
+ EventTarget relatedTarget}) {
+ var options = {
+ 'view': view,
+ 'deltaMode': deltaMode,
+ 'deltaX': deltaX,
+ 'deltaY': deltaY,
+ 'deltaZ': deltaZ,
+ 'detail': detail,
+ 'screenX': screenX,
+ 'screenY': screenY,
+ 'clientX': clientX,
+ 'clientY': clientY,
+ 'button': button,
+ 'bubbles': canBubble,
+ 'cancelable': cancelable,
+ 'ctrlKey': ctrlKey,
+ 'altKey': altKey,
+ 'shiftKey': shiftKey,
+ 'metaKey': metaKey,
+ 'relatedTarget': relatedTarget,
+ };
+
+ if (view == null) {
+ view = window;
+ }
+
+ return JS('WheelEvent', 'new WheelEvent(#, #)', type,
+ convertDartToNative_Dictionary(options));
+ }
+
+ factory WheelEvent._(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return WheelEvent._create_1(type, eventInitDict_1);
+ }
+ return WheelEvent._create_2(type);
+ }
+ static WheelEvent _create_1(type, eventInitDict) =>
+ JS('WheelEvent', 'new WheelEvent(#,#)', type, eventInitDict);
+ static WheelEvent _create_2(type) =>
+ JS('WheelEvent', 'new WheelEvent(#)', type);
+
+ static const int DOM_DELTA_LINE = 0x01;
+
+ static const int DOM_DELTA_PAGE = 0x02;
+
+ static const int DOM_DELTA_PIXEL = 0x00;
+
+ @JSName('deltaX')
+ final num _deltaX;
+
+ @JSName('deltaY')
+ final num _deltaY;
+
+ final num deltaZ;
+
+ /**
+ * The amount that is expected to scroll vertically, in units determined by
+ * [deltaMode].
+ *
+ * See also:
+ *
+ * * [WheelEvent.deltaY](http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-WheelEvent-deltaY) from the W3C.
+ */
+ num get deltaY {
+ if (JS('bool', '#.deltaY !== undefined', this)) {
+ // W3C WheelEvent
+ return this._deltaY;
+ }
+ throw new UnsupportedError('deltaY is not supported');
+ }
+
+ /**
+ * The amount that is expected to scroll horizontally, in units determined by
+ * [deltaMode].
+ *
+ * See also:
+ *
+ * * [WheelEvent.deltaX](http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-WheelEvent-deltaX) from the W3C.
+ */
+ num get deltaX {
+ if (JS('bool', '#.deltaX !== undefined', this)) {
+ // W3C WheelEvent
+ return this._deltaX;
+ }
+ throw new UnsupportedError('deltaX is not supported');
+ }
+
+ int get deltaMode {
+ if (JS('bool', '!!(#.deltaMode)', this)) {
+ return JS('int', '#.deltaMode', this);
+ }
+ // If not available then we're poly-filling and doing pixel scroll.
+ return 0;
+ }
+
+ num get _wheelDelta => JS('num', '#.wheelDelta', this);
+ num get _wheelDeltaX => JS('num', '#.wheelDeltaX', this);
+ num get _detail => JS('num', '#.detail', this);
+
+ bool get _hasInitMouseScrollEvent =>
+ JS('bool', '!!(#.initMouseScrollEvent)', this);
+
+ @JSName('initMouseScrollEvent')
+ void _initMouseScrollEvent(
+ String type,
+ bool canBubble,
+ bool cancelable,
+ Window view,
+ int detail,
+ int screenX,
+ int screenY,
+ int clientX,
+ int clientY,
+ bool ctrlKey,
+ bool altKey,
+ bool shiftKey,
+ bool metaKey,
+ int button,
+ EventTarget relatedTarget,
+ int axis) native;
+
+ bool get _hasInitWheelEvent => JS('bool', '!!(#.initWheelEvent)', this);
+ @JSName('initWheelEvent')
+ void _initWheelEvent(
+ String eventType,
+ bool canBubble,
+ bool cancelable,
+ Window view,
+ int detail,
+ int screenX,
+ int screenY,
+ int clientX,
+ int clientY,
+ int button,
+ EventTarget relatedTarget,
+ String modifiersList,
+ int deltaX,
+ int deltaY,
+ int deltaZ,
+ int deltaMode) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Top-level container for the current browser tab or window.
+ *
+ * In a web browser, each window has a [Window] object, but within the context
+ * of a script, this object represents only the current window.
+ * Each other window, tab, and iframe has its own [Window] object.
+ *
+ * Each window contains a [Document] object, which contains all of the window's
+ * content.
+ *
+ * Use the top-level `window` object to access the current window.
+ * For example:
+ *
+ * // Draw a scene when the window repaints.
+ * drawScene(num delta) {...}
+ * window.animationFrame.then(drawScene);.
+ *
+ * // Write to the console.
+ * window.console.log('Jinkies!');
+ * window.console.error('Jeepers!');
+ *
+ * **Note:** This class represents only the current window, while [WindowBase]
+ * is a representation of any window, including other tabs, windows, and frames.
+ *
+ * ## See also
+ *
+ * * [WindowBase]
+ *
+ * ## Other resources
+ *
+ * * [DOM Window](https://developer.mozilla.org/en-US/docs/DOM/window) from MDN.
+ * * [Window](http://www.w3.org/TR/Window/) from the W3C.
+ */
+@Native("Window,DOMWindow")
+class Window extends EventTarget
+ implements
+ WindowEventHandlers,
+ WindowBase,
+ GlobalEventHandlers,
+ _WindowTimers,
+ WindowBase64 {
+ /**
+ * Returns a Future that completes just before the window is about to
+ * repaint so the user can draw an animation frame.
+ *
+ * If you need to later cancel this animation, use [requestAnimationFrame]
+ * instead.
+ *
+ * The [Future] completes to a timestamp that represents a floating
+ * point value of the number of milliseconds that have elapsed since the page
+ * started to load (which is also the timestamp at this call to
+ * animationFrame).
+ *
+ * Note: The code that runs when the future completes should call
+ * [animationFrame] again for the animation to continue.
+ */
+ Future<num> get animationFrame {
+ var completer = new Completer<num>.sync();
+ requestAnimationFrame((time) {
+ completer.complete(time);
+ });
+ return completer.future;
+ }
+
+ /**
+ * The newest document in this window.
+ *
+ * ## Other resources
+ *
+ * * [Loading web
+ * pages](https://html.spec.whatwg.org/multipage/browsers.html)
+ * from WHATWG.
+ */
+ Document get document => JS('Document', '#.document', this);
+
+ WindowBase _open2(url, name) =>
+ JS('Window|Null', '#.open(#,#)', this, url, name);
+
+ WindowBase _open3(url, name, options) =>
+ JS('Window|Null', '#.open(#,#,#)', this, url, name, options);
+
+ /**
+ * Opens a new window.
+ *
+ * ## Other resources
+ *
+ * * [Window.open](https://developer.mozilla.org/en-US/docs/Web/API/Window.open)
+ * from MDN.
+ */
+ WindowBase open(String url, String name, [String options]) {
+ if (options == null) {
+ return _DOMWindowCrossFrame._createSafe(_open2(url, name));
+ } else {
+ return _DOMWindowCrossFrame._createSafe(_open3(url, name, options));
+ }
+ }
+
+ // API level getter and setter for Location.
+ // TODO: The cross domain safe wrapper can be inserted here.
+ /**
+ * The current location of this window.
+ *
+ * Location currentLocation = window.location;
+ * print(currentLocation.href); // 'http://www.example.com:80/'
+ */
+ Location get location => _location;
+
+ // TODO: consider forcing users to do: window.location.assign('string').
+ /**
+ * Sets the window's location, which causes the browser to navigate to the new
+ * location.
+ */
+ set location(value) {
+ _location = value;
+ }
+
+ // Native getter and setter to access raw Location object.
+ dynamic get _location => JS('Location|Null', '#.location', this);
+ set _location(value) {
+ JS('void', '#.location = #', this, value);
+ }
+
+ /**
+ * Called to draw an animation frame and then request the window to repaint
+ * after [callback] has finished (creating the animation).
+ *
+ * Use this method only if you need to later call [cancelAnimationFrame]. If
+ * not, the preferred Dart idiom is to set animation frames by calling
+ * [animationFrame], which returns a Future.
+ *
+ * Returns a non-zero valued integer to represent the request id for this
+ * request. This value only needs to be saved if you intend to call
+ * [cancelAnimationFrame] so you can specify the particular animation to
+ * cancel.
+ *
+ * Note: The supplied [callback] needs to call [requestAnimationFrame] again
+ * for the animation to continue.
+ */
+ int requestAnimationFrame(FrameRequestCallback callback) {
+ _ensureRequestAnimationFrame();
+ return _requestAnimationFrame(_wrapZone(callback));
+ }
+
+ /**
+ * Cancels an animation frame request.
+ *
+ * ## Other resources
+ *
+ * * [Window.cancelAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/Window.cancelAnimationFrame)
+ * from MDN.
+ */
+ void cancelAnimationFrame(int id) {
+ _ensureRequestAnimationFrame();
+ _cancelAnimationFrame(id);
+ }
+
+ @JSName('requestAnimationFrame')
+ int _requestAnimationFrame(FrameRequestCallback callback) native;
+
+ @JSName('cancelAnimationFrame')
+ void _cancelAnimationFrame(int id) native;
+
+ _ensureRequestAnimationFrame() {
+ if (JS<bool>(
+ 'bool',
+ '!!(#.requestAnimationFrame && #.cancelAnimationFrame)',
+ this,
+ this)) return;
+
+ JS(
+ 'void',
+ r"""
+ (function($this) {
+ var vendors = ['ms', 'moz', 'webkit', 'o'];
+ for (var i = 0; i < vendors.length && !$this.requestAnimationFrame; ++i) {
+ $this.requestAnimationFrame = $this[vendors[i] + 'RequestAnimationFrame'];
+ $this.cancelAnimationFrame =
+ $this[vendors[i]+'CancelAnimationFrame'] ||
+ $this[vendors[i]+'CancelRequestAnimationFrame'];
+ }
+ if ($this.requestAnimationFrame && $this.cancelAnimationFrame) return;
+ $this.requestAnimationFrame = function(callback) {
+ return window.setTimeout(function() {
+ callback(Date.now());
+ }, 16 /* 16ms ~= 60fps */);
+ };
+ $this.cancelAnimationFrame = function(id) { clearTimeout(id); }
+ })(#)""",
+ this);
+ }
+
+ /**
+ * Gets an instance of the Indexed DB factory to being using Indexed DB.
+ *
+ * Use [indexed_db.IdbFactory.supported] to check if Indexed DB is supported on the
+ * current platform.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME, '23.0')
+ @SupportedBrowser(SupportedBrowser.FIREFOX, '15.0')
+ @SupportedBrowser(SupportedBrowser.IE, '10.0')
+ IdbFactory get indexedDB => JS(
+ 'IdbFactory|Null', // If not supported, returns null.
+ '#.indexedDB || #.webkitIndexedDB || #.mozIndexedDB',
+ this,
+ this,
+ this);
+
+ /// The debugging console for this window.
+ Console get console => Console._safeConsole;
+
+ /**
+ * Access a sandboxed file system of `size` bytes.
+ *
+ * If `persistent` is true, the application will request permission from the
+ * user to create lasting storage. This storage cannot be freed without the
+ * user's permission. Returns a [Future] whose value stores a reference to
+ * the sandboxed file system for use. Because the file system is sandboxed,
+ * applications cannot access file systems created in other web pages.
+ */
+ Future<FileSystem> requestFileSystem(int size, {bool persistent: false}) {
+ return _requestFileSystem(persistent ? 1 : 0, size);
+ }
+
+ /**
+ * convertPointFromNodeToPage and convertPointFromPageToNode are removed.
+ * see http://dev.w3.org/csswg/cssom-view/#geometry
+ */
+ static bool get supportsPointConversions => DomPoint.supported;
+ // To suppress missing implicit constructor warnings.
+ factory Window._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `contentloaded` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> contentLoadedEvent =
+ const EventStreamProvider<Event>('DOMContentLoaded');
+
+ /**
+ * Static factory designed to expose `devicemotion` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<DeviceMotionEvent> deviceMotionEvent =
+ const EventStreamProvider<DeviceMotionEvent>('devicemotion');
+
+ /**
+ * Static factory designed to expose `deviceorientation` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<DeviceOrientationEvent>
+ deviceOrientationEvent =
+ const EventStreamProvider<DeviceOrientationEvent>('deviceorientation');
+
+ /**
+ * Static factory designed to expose `hashchange` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> hashChangeEvent =
+ const EventStreamProvider<Event>('hashchange');
+
+ static const EventStreamProvider<Event> loadStartEvent =
+ const EventStreamProvider<Event>('loadstart');
+
+ /**
+ * Static factory designed to expose `message` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ /**
+ * Static factory designed to expose `offline` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> offlineEvent =
+ const EventStreamProvider<Event>('offline');
+
+ /**
+ * Static factory designed to expose `online` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> onlineEvent =
+ const EventStreamProvider<Event>('online');
+
+ /**
+ * Static factory designed to expose `pagehide` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> pageHideEvent =
+ const EventStreamProvider<Event>('pagehide');
+
+ /**
+ * Static factory designed to expose `pageshow` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> pageShowEvent =
+ const EventStreamProvider<Event>('pageshow');
+
+ /**
+ * Static factory designed to expose `popstate` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<PopStateEvent> popStateEvent =
+ const EventStreamProvider<PopStateEvent>('popstate');
+
+ static const EventStreamProvider<Event> progressEvent =
+ const EventStreamProvider<Event>('progress');
+
+ /**
+ * Static factory designed to expose `storage` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<StorageEvent> storageEvent =
+ const EventStreamProvider<StorageEvent>('storage');
+
+ /**
+ * Static factory designed to expose `unload` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> unloadEvent =
+ const EventStreamProvider<Event>('unload');
+
+ /**
+ * Static factory designed to expose `animationend` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ static const EventStreamProvider<AnimationEvent> animationEndEvent =
+ const EventStreamProvider<AnimationEvent>('webkitAnimationEnd');
+
+ /**
+ * Static factory designed to expose `animationiteration` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ static const EventStreamProvider<AnimationEvent> animationIterationEvent =
+ const EventStreamProvider<AnimationEvent>('webkitAnimationIteration');
+
+ /**
+ * Static factory designed to expose `animationstart` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ static const EventStreamProvider<AnimationEvent> animationStartEvent =
+ const EventStreamProvider<AnimationEvent>('webkitAnimationStart');
+
+ /**
+ * Indicates that file system data cannot be cleared unless given user
+ * permission.
+ *
+ * ## Other resources
+ *
+ * * [Exploring the FileSystem
+ * APIs](http://www.html5rocks.com/en/tutorials/file/filesystem/)
+ * from HTML5Rocks.
+ * * [File API](http://www.w3.org/TR/file-system-api/#idl-def-LocalFileSystem)
+ * from W3C.
+ */
+ static const int PERSISTENT = 1;
+
+ /**
+ * Indicates that file system data can be cleared at any time.
+ *
+ * ## Other resources
+ *
+ * * [Exploring the FileSystem
+ * APIs](http://www.html5rocks.com/en/tutorials/file/filesystem/) from HTML5Rocks.
+ * * [File API](http://www.w3.org/TR/file-system-api/#idl-def-LocalFileSystem)
+ * from W3C.
+ */
+ static const int TEMPORARY = 0;
+
+ final _Worklet animationWorklet;
+
+ /**
+ * The application cache for this window.
+ *
+ * ## Other resources
+ *
+ * * [A beginner's guide to using the application
+ * cache](http://www.html5rocks.com/en/tutorials/appcache/beginner)
+ * from HTML5Rocks.
+ * * [Application cache
+ * API](https://html.spec.whatwg.org/multipage/browsers.html#application-cache-api)
+ * from WHATWG.
+ */
+ final ApplicationCache applicationCache;
+
+ final _Worklet audioWorklet;
+
+ final CacheStorage caches;
+
+ final bool closed;
+
+ final CookieStore cookieStore;
+
+ /**
+ * Entrypoint for the browser's cryptographic functions.
+ *
+ * ## Other resources
+ *
+ * * [Web cryptography API](http://www.w3.org/TR/WebCryptoAPI/) from W3C.
+ */
+ final Crypto crypto;
+
+ final CustomElementRegistry customElements;
+
+ /// *Deprecated*.
+ String defaultStatus;
+
+ /// *Deprecated*.
+ String defaultstatus;
+
+ /**
+ * The ratio between physical pixels and logical CSS pixels.
+ *
+ * ## Other resources
+ *
+ * * [devicePixelRatio](http://www.quirksmode.org/blog/archives/2012/06/devicepixelrati.html)
+ * from quirksmode.
+ * * [More about devicePixelRatio](http://www.quirksmode.org/blog/archives/2012/07/more_about_devi.html)
+ * from quirksmode.
+ */
+ final num devicePixelRatio;
+
+ final External external;
+
+ /**
+ * The current session history for this window's newest document.
+ *
+ * ## Other resources
+ *
+ * * [Loading web pages](https://html.spec.whatwg.org/multipage/browsers.html)
+ * from WHATWG.
+ */
+ final History history;
+
+ /**
+ * The height of the viewport including scrollbars.
+ *
+ * ## Other resources
+ *
+ * * [Window.innerHeight](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerHeight)
+ * from MDN.
+ */
+ final int innerHeight;
+
+ /**
+ * The width of the viewport including scrollbars.
+ *
+ * ## Other resources
+ *
+ * * [Window.innerWidth](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth)
+ * from MDN.
+ */
+ final int innerWidth;
+
+ final bool isSecureContext;
+
+ /**
+ * Storage for this window that persists across sessions.
+ *
+ * ## Other resources
+ *
+ * * [DOM storage guide](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage)
+ * from MDN.
+ * * [The past, present & future of local storage for web
+ * applications](http://diveintohtml5.info/storage.html) from Dive Into HTML5.
+ * * [Local storage specification](http://www.w3.org/TR/webstorage/#the-localstorage-attribute)
+ * from W3C.
+ */
+ final Storage localStorage;
+
+ /**
+ * This window's location bar, which displays the URL.
+ *
+ * ## Other resources
+ *
+ * * [Browser interface
+ * elements](https://html.spec.whatwg.org/multipage/browsers.html#browser-interface-elements)
+ * from WHATWG.
+ */
+ final BarProp locationbar;
+
+ /**
+ * This window's menu bar, which displays menu commands.
+ *
+ * ## Other resources
+ *
+ * * [Browser interface
+ * elements](https://html.spec.whatwg.org/multipage/browsers.html#browser-interface-elements)
+ * from WHATWG.
+ */
+ final BarProp menubar;
+
+ /**
+ * The name of this window.
+ *
+ * ## Other resources
+ *
+ * * [Window.name](https://developer.mozilla.org/en-US/docs/Web/API/Window/name)
+ * from MDN.
+ */
+ String name;
+
+ /**
+ * The user agent accessing this window.
+ *
+ * ## Other resources
+ *
+ * * [The navigator
+ * object](https://html.spec.whatwg.org/multipage/webappapis.html#the-navigator-object)
+ * from WHATWG.
+ */
+ final Navigator navigator;
+
+ /**
+ * Whether objects are drawn offscreen before being displayed.
+ *
+ * ## Other resources
+ *
+ * * [offscreenBuffering](https://webplatform.github.io/docs/dom/HTMLElement/offscreenBuffering/)
+ * from WebPlatform.org.
+ */
+ final bool offscreenBuffering;
+
+ WindowBase get opener => _convertNativeToDart_Window(this._get_opener);
+ @JSName('opener')
+ @Creates('Window|=Object')
+ @Returns('Window|=Object')
+ final dynamic _get_opener;
+
+ set opener(Window value) {
+ JS("void", "#.opener = #", this, value);
+ }
+
+ final int orientation;
+
+ final String origin;
+
+ /**
+ * The height of this window including all user interface elements.
+ *
+ * ## Other resources
+ *
+ * * [Window.outerHeight](https://developer.mozilla.org/en-US/docs/Web/API/Window/outerHeight)
+ * from MDN.
+ */
+ final int outerHeight;
+
+ /**
+ * The width of the window including all user interface elements.
+ *
+ * ## Other resources
+ *
+ * * [Window.outerWidth](https://developer.mozilla.org/en-US/docs/Web/API/Window/outerWidth)
+ * from MDN.
+ */
+ final int outerWidth;
+
+ @JSName('pageXOffset')
+ /**
+ * The distance this window has been scrolled horizontally.
+ *
+ * This attribute is an alias for [scrollX].
+ *
+ * ## Other resources
+ *
+ * * [The Screen interface
+ * specification](http://www.w3.org/TR/cssom-view/#screen) from W3C.
+ * * [scrollX and
+ * pageXOffset](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollX)
+ * from MDN.
+ */
+ final num _pageXOffset;
+
+ @JSName('pageYOffset')
+ /**
+ * The distance this window has been scrolled vertically.
+ *
+ * This attribute is an alias for [scrollY].
+ *
+ * ## Other resources
+ *
+ * * [The Screen interface
+ * specification](http://www.w3.org/TR/cssom-view/#screen) from W3C.
+ * * [scrollY and
+ * pageYOffset](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY)
+ * from MDN.
+ */
+ final num _pageYOffset;
+
+ WindowBase get parent => _convertNativeToDart_Window(this._get_parent);
+ @JSName('parent')
+ @Creates('Window|=Object')
+ @Returns('Window|=Object')
+ final dynamic _get_parent;
+
+ /**
+ * Timing and navigation data for this window.
+ *
+ * ## Other resources
+ *
+ * * [Measuring page load speed with navigation
+ * timeing](http://www.html5rocks.com/en/tutorials/webperformance/basics/)
+ * from HTML5Rocks.
+ * * [Navigation timing
+ * specification](http://www.w3.org/TR/navigation-timing/) from W3C.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE)
+ final Performance performance;
+
+ /**
+ * Information about the screen displaying this window.
+ *
+ * ## Other resources
+ *
+ * * [The Screen interface specification](http://www.w3.org/TR/cssom-view/#screen)
+ * from W3C.
+ */
+ final Screen screen;
+
+ /**
+ * The distance from the left side of the screen to the left side of this
+ * window.
+ *
+ * ## Other resources
+ *
+ * * [The Screen interface specification](http://www.w3.org/TR/cssom-view/#screen)
+ * from W3C.
+ */
+ final int screenLeft;
+
+ /**
+ * The distance from the top of the screen to the top of this window.
+ *
+ * ## Other resources
+ *
+ * * [The Screen interface specification](http://www.w3.org/TR/cssom-view/#screen)
+ * from W3C.
+ */
+ final int screenTop;
+
+ /**
+ * The distance from the left side of the screen to the mouse pointer.
+ *
+ * ## Other resources
+ *
+ * * [The Screen interface specification](http://www.w3.org/TR/cssom-view/#screen)
+ * from W3C.
+ */
+ final int screenX;
+
+ /**
+ * The distance from the top of the screen to the mouse pointer.
+ *
+ * ## Other resources
+ *
+ * * [The Screen interface specification](http://www.w3.org/TR/cssom-view/#screen)
+ * from W3C.
+ */
+ final int screenY;
+
+ /**
+ * This window's scroll bars.
+ *
+ * ## Other resources
+ *
+ * * [Browser interface
+ * elements](https://html.spec.whatwg.org/multipage/browsers.html#browser-interface-elements)
+ * from WHATWG.
+ */
+ final BarProp scrollbars;
+
+ /**
+ * The current window.
+ *
+ * ## Other resources
+ *
+ * * [Window.self](https://developer.mozilla.org/en-US/docs/Web/API/Window.self)
+ * from MDN.
+ */
+ WindowBase get self => _convertNativeToDart_Window(this._get_self);
+ @JSName('self')
+ /**
+ * The current window.
+ *
+ * ## Other resources
+ *
+ * * [Window.self](https://developer.mozilla.org/en-US/docs/Web/API/Window.self)
+ * from MDN.
+ */
+ @Creates('Window|=Object')
+ @Returns('Window|=Object')
+ final dynamic _get_self;
+
+ /**
+ * Storage for this window that is cleared when this session ends.
+ *
+ * ## Other resources
+ *
+ * * [DOM storage
+ * guide](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage)
+ * from MDN.
+ * * [The past, present & future of local storage for web
+ * applications](http://diveintohtml5.info/storage.html) from Dive Into HTML5.
+ * * [Local storage
+ * specification](http://www.w3.org/TR/webstorage/#dom-sessionstorage) from W3C.
+ */
+ final Storage sessionStorage;
+
+ /**
+ * Access to speech synthesis in the browser.
+ *
+ * ## Other resources
+ *
+ * * [Web speech
+ * specification](https://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html#tts-section)
+ * from W3C.
+ */
+ final SpeechSynthesis speechSynthesis;
+
+ /// *Deprecated*.
+ String status;
+
+ /**
+ * This window's status bar.
+ *
+ * ## Other resources
+ *
+ * * [Browser interface
+ * elements](https://html.spec.whatwg.org/multipage/browsers.html#browser-interface-elements)
+ * from WHATWG.
+ */
+ final BarProp statusbar;
+
+ /**
+ * Access to CSS media queries.
+ *
+ * ## Other resources
+ *
+ * * [StyleMedia class
+ * reference](https://developer.apple.com/library/safari/documentation/SafariDOMAdditions/Reference/StyleMedia/)
+ * from Safari Developer Library.
+ */
+ final StyleMedia styleMedia;
+
+ /**
+ * This window's tool bar.
+ *
+ * ## Other resources
+ *
+ * * [Browser interface
+ * elements](https://html.spec.whatwg.org/multipage/browsers.html#browser-interface-elements)
+ * from WHATWG.
+ */
+ final BarProp toolbar;
+
+ WindowBase get top => _convertNativeToDart_Window(this._get_top);
+ @JSName('top')
+ @Creates('Window|=Object')
+ @Returns('Window|=Object')
+ final dynamic _get_top;
+
+ final VisualViewport visualViewport;
+
+ /**
+ * The current window.
+ *
+ * ## Other resources
+ *
+ * * [Window.window](https://developer.mozilla.org/en-US/docs/Web/API/Window.window)
+ * from MDN.
+ */
+ WindowBase get window => _convertNativeToDart_Window(this._get_window);
+ @JSName('window')
+ /**
+ * The current window.
+ *
+ * ## Other resources
+ *
+ * * [Window.window](https://developer.mozilla.org/en-US/docs/Web/API/Window.window)
+ * from MDN.
+ */
+ @Creates('Window|=Object')
+ @Returns('Window|=Object')
+ final dynamic _get_window;
+
+ @Creates('Window|=Object')
+ @Returns('Window|=Object')
+ WindowBase __getter__(index_OR_name) {
+ if ((index_OR_name is int)) {
+ return _convertNativeToDart_Window(__getter___1(index_OR_name));
+ }
+ if ((index_OR_name is String)) {
+ return _convertNativeToDart_Window(__getter___2(index_OR_name));
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('__getter__')
+ @Creates('Window|=Object')
+ @Returns('Window|=Object')
+ __getter___1(int index) native;
+ @JSName('__getter__')
+ @Creates('Window|=Object')
+ @Returns('Window|=Object')
+ __getter___2(String name) native;
+
+ /**
+ * Displays a modal alert to the user.
+ *
+ * ## Other resources
+ *
+ * * [User prompts](https://html.spec.whatwg.org/multipage/webappapis.html#user-prompts)
+ * from WHATWG.
+ */
+ void alert([String message]) native;
+
+ void cancelIdleCallback(int handle) native;
+
+ void close() native;
+
+ /**
+ * Displays a modal OK/Cancel prompt to the user.
+ *
+ * ## Other resources
+ *
+ * * [User prompts](https://html.spec.whatwg.org/multipage/webappapis.html#user-prompts)
+ * from WHATWG.
+ */
+ bool confirm([String message]) native;
+
+ Future fetch(/*RequestInfo*/ input, [Map init]) {
+ var init_dict = null;
+ if (init != null) {
+ init_dict = convertDartToNative_Dictionary(init);
+ }
+ return promiseToFuture(JS("", "#.fetch(#, #)", this, input, init_dict));
+ }
+
+ /**
+ * Finds text in this window.
+ *
+ * ## Other resources
+ *
+ * * [Window.find](https://developer.mozilla.org/en-US/docs/Web/API/Window.find)
+ * from MDN.
+ */
+ bool find(String string, bool caseSensitive, bool backwards, bool wrap,
+ bool wholeWord, bool searchInFrames, bool showDialog) native;
+
+ @JSName('getComputedStyle')
+ CssStyleDeclaration _getComputedStyle(Element elt, [String pseudoElt]) native;
+
+ StylePropertyMapReadonly getComputedStyleMap(
+ Element element, String pseudoElement) native;
+
+ @JSName('getMatchedCSSRules')
+ /**
+ * Returns all CSS rules that apply to the element's pseudo-element.
+ */
+ @Returns('_CssRuleList|Null')
+ @Creates('_CssRuleList')
+ List<CssRule> getMatchedCssRules(Element element, String pseudoElement)
+ native;
+
+ /**
+ * Returns the currently selected text.
+ *
+ * ## Other resources
+ *
+ * * [Window.getSelection](https://developer.mozilla.org/en-US/docs/Web/API/Window.getSelection)
+ * from MDN.
+ */
+ Selection getSelection() native;
+
+ /**
+ * Returns a list of media queries for the given query string.
+ *
+ * ## Other resources
+ *
+ * * [Testing media
+ * queries](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Testing_media_queries)
+ * from MDN.
+ * * [The MediaQueryList
+ * specification](http://www.w3.org/TR/cssom-view/#the-mediaquerylist-interface) from W3C.
+ */
+ MediaQueryList matchMedia(String query) native;
+
+ /**
+ * Moves this window.
+ *
+ * x and y can be negative.
+ *
+ * ## Other resources
+ *
+ * * [Window.moveBy](https://developer.mozilla.org/en-US/docs/Web/API/Window.moveBy)
+ * from MDN.
+ * * [Window.moveBy](http://dev.w3.org/csswg/cssom-view/#dom-window-moveby) from W3C.
+ */
+ void moveBy(int x, int y) native;
+
+ @JSName('moveTo')
+ void _moveTo(int x, int y) native;
+
+ @JSName('openDatabase')
+
+ /// *Deprecated.*
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @Creates('SqlDatabase')
+ SqlDatabase _openDatabase(
+ String name, String version, String displayName, int estimatedSize,
+ [DatabaseCallback creationCallback]) native;
+
+ void postMessage(/*any*/ message, String targetOrigin,
+ [List<Object> transfer]) {
+ if (transfer != null) {
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_1(message_1, targetOrigin, transfer);
+ return;
+ }
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_2(message_1, targetOrigin);
+ return;
+ }
+
+ @JSName('postMessage')
+ void _postMessage_1(message, targetOrigin, List<Object> transfer) native;
+ @JSName('postMessage')
+ void _postMessage_2(message, targetOrigin) native;
+
+ /**
+ * Opens the print dialog for this window.
+ *
+ * ## Other resources
+ *
+ * * [Window.print](https://developer.mozilla.org/en-US/docs/Web/API/Window.print)
+ * from MDN.
+ */
+ void print() native;
+
+ int requestIdleCallback(IdleRequestCallback callback, [Map options]) {
+ if (options != null) {
+ var callback_1 = convertDartClosureToJS(callback, 1);
+ var options_2 = convertDartToNative_Dictionary(options);
+ return _requestIdleCallback_1(callback_1, options_2);
+ }
+ var callback_1 = convertDartClosureToJS(callback, 1);
+ return _requestIdleCallback_2(callback_1);
+ }
+
+ @JSName('requestIdleCallback')
+ int _requestIdleCallback_1(callback, options) native;
+ @JSName('requestIdleCallback')
+ int _requestIdleCallback_2(callback) native;
+
+ /**
+ * Resizes this window by an offset.
+ *
+ * ## Other resources
+ *
+ * * [Window.resizeBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/resizeBy)
+ * from MDN.
+ */
+ void resizeBy(int x, int y) native;
+
+ /**
+ * Resizes this window to a specific width and height.
+ *
+ * ## Other resources
+ *
+ * * [Window.resizeTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/resizeTo)
+ * from MDN.
+ */
+ void resizeTo(int x, int y) native;
+
+ /**
+ * Scrolls the page horizontally and vertically to a specific point.
+ *
+ * This method is identical to [scrollTo].
+ *
+ * ## Other resources
+ *
+ * * [Window.scroll](https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll)
+ * from MDN.
+ */
+ void scroll([options_OR_x, y, Map scrollOptions]) {
+ if (options_OR_x == null && y == null && scrollOptions == null) {
+ _scroll_1();
+ return;
+ }
+ if ((options_OR_x is Map) && y == null && scrollOptions == null) {
+ var options_1 = convertDartToNative_Dictionary(options_OR_x);
+ _scroll_2(options_1);
+ return;
+ }
+ if ((y is num) && (options_OR_x is num) && scrollOptions == null) {
+ _scroll_3(options_OR_x, y);
+ return;
+ }
+ if ((y is int) && (options_OR_x is int) && scrollOptions == null) {
+ _scroll_4(options_OR_x, y);
+ return;
+ }
+ if (scrollOptions != null && (y is int) && (options_OR_x is int)) {
+ var scrollOptions_1 = convertDartToNative_Dictionary(scrollOptions);
+ _scroll_5(options_OR_x, y, scrollOptions_1);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('scroll')
+ /**
+ * Scrolls the page horizontally and vertically to a specific point.
+ *
+ * This method is identical to [scrollTo].
+ *
+ * ## Other resources
+ *
+ * * [Window.scroll](https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll)
+ * from MDN.
+ */
+ void _scroll_1() native;
+ @JSName('scroll')
+ /**
+ * Scrolls the page horizontally and vertically to a specific point.
+ *
+ * This method is identical to [scrollTo].
+ *
+ * ## Other resources
+ *
+ * * [Window.scroll](https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll)
+ * from MDN.
+ */
+ void _scroll_2(options) native;
+ @JSName('scroll')
+ /**
+ * Scrolls the page horizontally and vertically to a specific point.
+ *
+ * This method is identical to [scrollTo].
+ *
+ * ## Other resources
+ *
+ * * [Window.scroll](https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll)
+ * from MDN.
+ */
+ void _scroll_3(num x, num y) native;
+ @JSName('scroll')
+ /**
+ * Scrolls the page horizontally and vertically to a specific point.
+ *
+ * This method is identical to [scrollTo].
+ *
+ * ## Other resources
+ *
+ * * [Window.scroll](https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll)
+ * from MDN.
+ */
+ void _scroll_4(int x, int y) native;
+ @JSName('scroll')
+ /**
+ * Scrolls the page horizontally and vertically to a specific point.
+ *
+ * This method is identical to [scrollTo].
+ *
+ * ## Other resources
+ *
+ * * [Window.scroll](https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll)
+ * from MDN.
+ */
+ void _scroll_5(int x, int y, scrollOptions) native;
+
+ /**
+ * Scrolls the page horizontally and vertically by an offset.
+ *
+ * ## Other resources
+ *
+ * * [Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy)
+ * from MDN.
+ */
+ void scrollBy([options_OR_x, y, Map scrollOptions]) {
+ if (options_OR_x == null && y == null && scrollOptions == null) {
+ _scrollBy_1();
+ return;
+ }
+ if ((options_OR_x is Map) && y == null && scrollOptions == null) {
+ var options_1 = convertDartToNative_Dictionary(options_OR_x);
+ _scrollBy_2(options_1);
+ return;
+ }
+ if ((y is num) && (options_OR_x is num) && scrollOptions == null) {
+ _scrollBy_3(options_OR_x, y);
+ return;
+ }
+ if ((y is int) && (options_OR_x is int) && scrollOptions == null) {
+ _scrollBy_4(options_OR_x, y);
+ return;
+ }
+ if (scrollOptions != null && (y is int) && (options_OR_x is int)) {
+ var scrollOptions_1 = convertDartToNative_Dictionary(scrollOptions);
+ _scrollBy_5(options_OR_x, y, scrollOptions_1);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('scrollBy')
+ /**
+ * Scrolls the page horizontally and vertically by an offset.
+ *
+ * ## Other resources
+ *
+ * * [Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy)
+ * from MDN.
+ */
+ void _scrollBy_1() native;
+ @JSName('scrollBy')
+ /**
+ * Scrolls the page horizontally and vertically by an offset.
+ *
+ * ## Other resources
+ *
+ * * [Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy)
+ * from MDN.
+ */
+ void _scrollBy_2(options) native;
+ @JSName('scrollBy')
+ /**
+ * Scrolls the page horizontally and vertically by an offset.
+ *
+ * ## Other resources
+ *
+ * * [Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy)
+ * from MDN.
+ */
+ void _scrollBy_3(num x, num y) native;
+ @JSName('scrollBy')
+ /**
+ * Scrolls the page horizontally and vertically by an offset.
+ *
+ * ## Other resources
+ *
+ * * [Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy)
+ * from MDN.
+ */
+ void _scrollBy_4(int x, int y) native;
+ @JSName('scrollBy')
+ /**
+ * Scrolls the page horizontally and vertically by an offset.
+ *
+ * ## Other resources
+ *
+ * * [Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy)
+ * from MDN.
+ */
+ void _scrollBy_5(int x, int y, scrollOptions) native;
+
+ /**
+ * Scrolls the page horizontally and vertically to a specific point.
+ *
+ * This method is identical to [scroll].
+ *
+ * ## Other resources
+ *
+ * * [Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
+ * from MDN.
+ */
+ void scrollTo([options_OR_x, y, Map scrollOptions]) {
+ if (options_OR_x == null && y == null && scrollOptions == null) {
+ _scrollTo_1();
+ return;
+ }
+ if ((options_OR_x is Map) && y == null && scrollOptions == null) {
+ var options_1 = convertDartToNative_Dictionary(options_OR_x);
+ _scrollTo_2(options_1);
+ return;
+ }
+ if ((y is num) && (options_OR_x is num) && scrollOptions == null) {
+ _scrollTo_3(options_OR_x, y);
+ return;
+ }
+ if ((y is int) && (options_OR_x is int) && scrollOptions == null) {
+ _scrollTo_4(options_OR_x, y);
+ return;
+ }
+ if (scrollOptions != null && (y is int) && (options_OR_x is int)) {
+ var scrollOptions_1 = convertDartToNative_Dictionary(scrollOptions);
+ _scrollTo_5(options_OR_x, y, scrollOptions_1);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('scrollTo')
+ /**
+ * Scrolls the page horizontally and vertically to a specific point.
+ *
+ * This method is identical to [scroll].
+ *
+ * ## Other resources
+ *
+ * * [Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
+ * from MDN.
+ */
+ void _scrollTo_1() native;
+ @JSName('scrollTo')
+ /**
+ * Scrolls the page horizontally and vertically to a specific point.
+ *
+ * This method is identical to [scroll].
+ *
+ * ## Other resources
+ *
+ * * [Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
+ * from MDN.
+ */
+ void _scrollTo_2(options) native;
+ @JSName('scrollTo')
+ /**
+ * Scrolls the page horizontally and vertically to a specific point.
+ *
+ * This method is identical to [scroll].
+ *
+ * ## Other resources
+ *
+ * * [Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
+ * from MDN.
+ */
+ void _scrollTo_3(num x, num y) native;
+ @JSName('scrollTo')
+ /**
+ * Scrolls the page horizontally and vertically to a specific point.
+ *
+ * This method is identical to [scroll].
+ *
+ * ## Other resources
+ *
+ * * [Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
+ * from MDN.
+ */
+ void _scrollTo_4(int x, int y) native;
+ @JSName('scrollTo')
+ /**
+ * Scrolls the page horizontally and vertically to a specific point.
+ *
+ * This method is identical to [scroll].
+ *
+ * ## Other resources
+ *
+ * * [Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo)
+ * from MDN.
+ */
+ void _scrollTo_5(int x, int y, scrollOptions) native;
+
+ /**
+ * Stops the window from loading.
+ *
+ * ## Other resources
+ *
+ * * [The Window
+ * object](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-window-object)
+ * from W3C.
+ */
+ void stop() native;
+
+ @JSName('webkitRequestFileSystem')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ void __requestFileSystem(
+ int type, int size, _FileSystemCallback successCallback,
+ [_ErrorCallback errorCallback]) native;
+
+ @JSName('webkitRequestFileSystem')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ Future<FileSystem> _requestFileSystem(int type, int size) {
+ var completer = new Completer<FileSystem>();
+ __requestFileSystem(type, size, (value) {
+ applyExtension('DOMFileSystem', value);
+ applyExtension('DirectoryEntry', value.root);
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ @JSName('webkitResolveLocalFileSystemURL')
+ /**
+ * Asynchronously retrieves a local filesystem entry.
+ *
+ * ## Other resources
+ *
+ * * [Obtaining access to file system entry
+ * points](http://www.w3.org/TR/file-system-api/#obtaining-access-to-file-system-entry-points)
+ * from W3C.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ void _resolveLocalFileSystemUrl(String url, _EntryCallback successCallback,
+ [_ErrorCallback errorCallback]) native;
+
+ @JSName('webkitResolveLocalFileSystemURL')
+ /**
+ * Asynchronously retrieves a local filesystem entry.
+ *
+ * ## Other resources
+ *
+ * * [Obtaining access to file system entry
+ * points](http://www.w3.org/TR/file-system-api/#obtaining-access-to-file-system-entry-points)
+ * from W3C.
+ */
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ Future<Entry> resolveLocalFileSystemUrl(String url) {
+ var completer = new Completer<Entry>();
+ _resolveLocalFileSystemUrl(url, (value) {
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ // From WindowBase64
+
+ String atob(String atob) native;
+
+ String btoa(String btoa) native;
+
+ // From WindowTimers
+
+ @JSName('setInterval')
+ int _setInterval_String(String handler, [int timeout, Object arguments])
+ native;
+
+ @JSName('setTimeout')
+ int _setTimeout_String(String handler, [int timeout, Object arguments])
+ native;
+
+ @JSName('clearInterval')
+ void _clearInterval([int handle]) native;
+
+ @JSName('clearTimeout')
+ void _clearTimeout([int handle]) native;
+
+ @JSName('setInterval')
+ int _setInterval(Object handler, [int timeout]) native;
+
+ @JSName('setTimeout')
+ int _setTimeout(Object handler, [int timeout]) native;
+
+ /// Stream of `contentloaded` events handled by this [Window].
+ Stream<Event> get onContentLoaded => contentLoadedEvent.forTarget(this);
+
+ /// Stream of `abort` events handled by this [Window].
+ Stream<Event> get onAbort => Element.abortEvent.forTarget(this);
+
+ /// Stream of `blur` events handled by this [Window].
+ Stream<Event> get onBlur => Element.blurEvent.forTarget(this);
+
+ Stream<Event> get onCanPlay => Element.canPlayEvent.forTarget(this);
+
+ Stream<Event> get onCanPlayThrough =>
+ Element.canPlayThroughEvent.forTarget(this);
+
+ /// Stream of `change` events handled by this [Window].
+ Stream<Event> get onChange => Element.changeEvent.forTarget(this);
+
+ /// Stream of `click` events handled by this [Window].
+ Stream<MouseEvent> get onClick => Element.clickEvent.forTarget(this);
+
+ /// Stream of `contextmenu` events handled by this [Window].
+ Stream<MouseEvent> get onContextMenu =>
+ Element.contextMenuEvent.forTarget(this);
+
+ /// Stream of `doubleclick` events handled by this [Window].
+ @DomName('Window.ondblclick')
+ Stream<Event> get onDoubleClick => Element.doubleClickEvent.forTarget(this);
+
+ /// Stream of `devicemotion` events handled by this [Window].
+ Stream<DeviceMotionEvent> get onDeviceMotion =>
+ deviceMotionEvent.forTarget(this);
+
+ /// Stream of `deviceorientation` events handled by this [Window].
+ Stream<DeviceOrientationEvent> get onDeviceOrientation =>
+ deviceOrientationEvent.forTarget(this);
+
+ /// Stream of `drag` events handled by this [Window].
+ Stream<MouseEvent> get onDrag => Element.dragEvent.forTarget(this);
+
+ /// Stream of `dragend` events handled by this [Window].
+ Stream<MouseEvent> get onDragEnd => Element.dragEndEvent.forTarget(this);
+
+ /// Stream of `dragenter` events handled by this [Window].
+ Stream<MouseEvent> get onDragEnter => Element.dragEnterEvent.forTarget(this);
+
+ /// Stream of `dragleave` events handled by this [Window].
+ Stream<MouseEvent> get onDragLeave => Element.dragLeaveEvent.forTarget(this);
+
+ /// Stream of `dragover` events handled by this [Window].
+ Stream<MouseEvent> get onDragOver => Element.dragOverEvent.forTarget(this);
+
+ /// Stream of `dragstart` events handled by this [Window].
+ Stream<MouseEvent> get onDragStart => Element.dragStartEvent.forTarget(this);
+
+ /// Stream of `drop` events handled by this [Window].
+ Stream<MouseEvent> get onDrop => Element.dropEvent.forTarget(this);
+
+ Stream<Event> get onDurationChange =>
+ Element.durationChangeEvent.forTarget(this);
+
+ Stream<Event> get onEmptied => Element.emptiedEvent.forTarget(this);
+
+ Stream<Event> get onEnded => Element.endedEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [Window].
+ Stream<Event> get onError => Element.errorEvent.forTarget(this);
+
+ /// Stream of `focus` events handled by this [Window].
+ Stream<Event> get onFocus => Element.focusEvent.forTarget(this);
+
+ /// Stream of `hashchange` events handled by this [Window].
+ Stream<Event> get onHashChange => hashChangeEvent.forTarget(this);
+
+ /// Stream of `input` events handled by this [Window].
+ Stream<Event> get onInput => Element.inputEvent.forTarget(this);
+
+ /// Stream of `invalid` events handled by this [Window].
+ Stream<Event> get onInvalid => Element.invalidEvent.forTarget(this);
+
+ /// Stream of `keydown` events handled by this [Window].
+ Stream<KeyboardEvent> get onKeyDown => Element.keyDownEvent.forTarget(this);
+
+ /// Stream of `keypress` events handled by this [Window].
+ Stream<KeyboardEvent> get onKeyPress => Element.keyPressEvent.forTarget(this);
+
+ /// Stream of `keyup` events handled by this [Window].
+ Stream<KeyboardEvent> get onKeyUp => Element.keyUpEvent.forTarget(this);
+
+ /// Stream of `load` events handled by this [Window].
+ Stream<Event> get onLoad => Element.loadEvent.forTarget(this);
+
+ Stream<Event> get onLoadedData => Element.loadedDataEvent.forTarget(this);
+
+ Stream<Event> get onLoadedMetadata =>
+ Element.loadedMetadataEvent.forTarget(this);
+
+ Stream<Event> get onLoadStart => loadStartEvent.forTarget(this);
+
+ /// Stream of `message` events handled by this [Window].
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+ /// Stream of `mousedown` events handled by this [Window].
+ Stream<MouseEvent> get onMouseDown => Element.mouseDownEvent.forTarget(this);
+
+ /// Stream of `mouseenter` events handled by this [Window].
+ Stream<MouseEvent> get onMouseEnter =>
+ Element.mouseEnterEvent.forTarget(this);
+
+ /// Stream of `mouseleave` events handled by this [Window].
+ Stream<MouseEvent> get onMouseLeave =>
+ Element.mouseLeaveEvent.forTarget(this);
+
+ /// Stream of `mousemove` events handled by this [Window].
+ Stream<MouseEvent> get onMouseMove => Element.mouseMoveEvent.forTarget(this);
+
+ /// Stream of `mouseout` events handled by this [Window].
+ Stream<MouseEvent> get onMouseOut => Element.mouseOutEvent.forTarget(this);
+
+ /// Stream of `mouseover` events handled by this [Window].
+ Stream<MouseEvent> get onMouseOver => Element.mouseOverEvent.forTarget(this);
+
+ /// Stream of `mouseup` events handled by this [Window].
+ Stream<MouseEvent> get onMouseUp => Element.mouseUpEvent.forTarget(this);
+
+ /// Stream of `mousewheel` events handled by this [Window].
+ Stream<WheelEvent> get onMouseWheel =>
+ Element.mouseWheelEvent.forTarget(this);
+
+ /// Stream of `offline` events handled by this [Window].
+ Stream<Event> get onOffline => offlineEvent.forTarget(this);
+
+ /// Stream of `online` events handled by this [Window].
+ Stream<Event> get onOnline => onlineEvent.forTarget(this);
+
+ /// Stream of `pagehide` events handled by this [Window].
+ Stream<Event> get onPageHide => pageHideEvent.forTarget(this);
+
+ /// Stream of `pageshow` events handled by this [Window].
+ Stream<Event> get onPageShow => pageShowEvent.forTarget(this);
+
+ Stream<Event> get onPause => Element.pauseEvent.forTarget(this);
+
+ Stream<Event> get onPlay => Element.playEvent.forTarget(this);
+
+ Stream<Event> get onPlaying => Element.playingEvent.forTarget(this);
+
+ /// Stream of `popstate` events handled by this [Window].
+ Stream<PopStateEvent> get onPopState => popStateEvent.forTarget(this);
+
+ Stream<Event> get onProgress => progressEvent.forTarget(this);
+
+ Stream<Event> get onRateChange => Element.rateChangeEvent.forTarget(this);
+
+ /// Stream of `reset` events handled by this [Window].
+ Stream<Event> get onReset => Element.resetEvent.forTarget(this);
+
+ /// Stream of `resize` events handled by this [Window].
+ Stream<Event> get onResize => Element.resizeEvent.forTarget(this);
+
+ /// Stream of `scroll` events handled by this [Window].
+ Stream<Event> get onScroll => Element.scrollEvent.forTarget(this);
+
+ /// Stream of `search` events handled by this [Window].
+ Stream<Event> get onSearch => Element.searchEvent.forTarget(this);
+
+ Stream<Event> get onSeeked => Element.seekedEvent.forTarget(this);
+
+ Stream<Event> get onSeeking => Element.seekingEvent.forTarget(this);
+
+ /// Stream of `select` events handled by this [Window].
+ Stream<Event> get onSelect => Element.selectEvent.forTarget(this);
+
+ Stream<Event> get onStalled => Element.stalledEvent.forTarget(this);
+
+ /// Stream of `storage` events handled by this [Window].
+ Stream<StorageEvent> get onStorage => storageEvent.forTarget(this);
+
+ /// Stream of `submit` events handled by this [Window].
+ Stream<Event> get onSubmit => Element.submitEvent.forTarget(this);
+
+ Stream<Event> get onSuspend => Element.suspendEvent.forTarget(this);
+
+ Stream<Event> get onTimeUpdate => Element.timeUpdateEvent.forTarget(this);
+
+ /// Stream of `touchcancel` events handled by this [Window].
+ Stream<TouchEvent> get onTouchCancel =>
+ Element.touchCancelEvent.forTarget(this);
+
+ /// Stream of `touchend` events handled by this [Window].
+ Stream<TouchEvent> get onTouchEnd => Element.touchEndEvent.forTarget(this);
+
+ /// Stream of `touchmove` events handled by this [Window].
+ Stream<TouchEvent> get onTouchMove => Element.touchMoveEvent.forTarget(this);
+
+ /// Stream of `touchstart` events handled by this [Window].
+ Stream<TouchEvent> get onTouchStart =>
+ Element.touchStartEvent.forTarget(this);
+
+ /// Stream of `transitionend` events handled by this [Window].
+ Stream<TransitionEvent> get onTransitionEnd =>
+ Element.transitionEndEvent.forTarget(this);
+
+ /// Stream of `unload` events handled by this [Window].
+ Stream<Event> get onUnload => unloadEvent.forTarget(this);
+
+ Stream<Event> get onVolumeChange => Element.volumeChangeEvent.forTarget(this);
+
+ Stream<Event> get onWaiting => Element.waitingEvent.forTarget(this);
+
+ /// Stream of `animationend` events handled by this [Window].
+ Stream<AnimationEvent> get onAnimationEnd =>
+ animationEndEvent.forTarget(this);
+
+ /// Stream of `animationiteration` events handled by this [Window].
+ Stream<AnimationEvent> get onAnimationIteration =>
+ animationIterationEvent.forTarget(this);
+
+ /// Stream of `animationstart` events handled by this [Window].
+ Stream<AnimationEvent> get onAnimationStart =>
+ animationStartEvent.forTarget(this);
+
+ /**
+ * Static factory designed to expose `beforeunload` events to event
+ * handlers that are not necessarily instances of [Window].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<BeforeUnloadEvent> beforeUnloadEvent =
+ const _BeforeUnloadEventStreamProvider('beforeunload');
+
+ /// Stream of `beforeunload` events handled by this [Window].
+ Stream<Event> get onBeforeUnload => beforeUnloadEvent.forTarget(this);
+
+ /// Stream of `wheel` events handled by this [Window].
+ Stream<WheelEvent> get onWheel => Element.wheelEvent.forTarget(this);
+
+ /**
+ * Moves this window to a specific position.
+ *
+ * x and y can be negative.
+ *
+ * ## Other resources
+ *
+ * * [Window.moveTo](https://developer.mozilla.org/en-US/docs/Web/API/Window.moveTo)
+ * from MDN.
+ * * [Window.moveTo](http://dev.w3.org/csswg/cssom-view/#dom-window-moveto)
+ * from W3C.
+ */
+ void moveTo(Point p) {
+ _moveTo(p.x, p.y);
+ }
+
+ @JSName('openDatabase')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @Creates('SqlDatabase')
+ SqlDatabase openDatabase(
+ String name, String version, String displayName, int estimatedSize,
+ [DatabaseCallback creationCallback]) {
+ var db;
+ if (creationCallback == null)
+ db = _openDatabase(name, version, displayName, estimatedSize);
+ else
+ db = _openDatabase(
+ name, version, displayName, estimatedSize, creationCallback);
+
+ applyExtension('Database', db);
+
+ return db;
+ }
+
+ int get pageXOffset => JS<num>('num', '#.pageXOffset', this).round();
+
+ int get pageYOffset => JS<num>('num', '#.pageYOffset', this).round();
+
+ /**
+ * The distance this window has been scrolled horizontally.
+ *
+ * ## Other resources
+ *
+ * * [The Screen interface
+ * specification](http://www.w3.org/TR/cssom-view/#screen) from W3C.
+ * * [scrollX](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollX)
+ * from MDN.
+ */
+ int get scrollX => JS<bool>('bool', '("scrollX" in #)', this)
+ ? JS<num>('num', '#.scrollX', this).round()
+ : document.documentElement.scrollLeft;
+
+ /**
+ * The distance this window has been scrolled vertically.
+ *
+ * ## Other resources
+ *
+ * * [The Screen interface
+ * specification](http://www.w3.org/TR/cssom-view/#screen) from W3C.
+ * * [scrollY](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY)
+ * from MDN.
+ */
+ int get scrollY => JS<bool>('bool', '("scrollY" in #)', this)
+ ? JS<num>('num', '#.scrollY', this).round()
+ : document.documentElement.scrollTop;
+}
+
+class _BeforeUnloadEvent extends _WrappedEvent implements BeforeUnloadEvent {
+ String _returnValue;
+
+ _BeforeUnloadEvent(Event base) : super(base);
+
+ String get returnValue => _returnValue;
+
+ set returnValue(String value) {
+ _returnValue = value;
+ // FF and IE use the value as the return value, Chrome will return this from
+ // the event callback function.
+ if (JS<bool>('bool', '("returnValue" in #)', wrapped)) {
+ JS('void', '#.returnValue = #', wrapped, value);
+ }
+ }
+}
+
+class _BeforeUnloadEventStreamProvider
+ implements EventStreamProvider<BeforeUnloadEvent> {
+ final String _eventType;
+
+ const _BeforeUnloadEventStreamProvider(this._eventType);
+
+ Stream<BeforeUnloadEvent> forTarget(EventTarget e, {bool useCapture: false}) {
+ // Specify the generic type for EventStream only in dart2js.
+ var stream = new _EventStream<BeforeUnloadEvent>(e, _eventType, useCapture);
+ var controller = new StreamController<BeforeUnloadEvent>(sync: true);
+
+ stream.listen((event) {
+ var wrapped = new _BeforeUnloadEvent(event);
+ controller.add(wrapped);
+ });
+
+ return controller.stream;
+ }
+
+ String getEventType(EventTarget target) {
+ return _eventType;
+ }
+
+ ElementStream<BeforeUnloadEvent> forElement(Element e,
+ {bool useCapture: false}) {
+ // Specify the generic type for _ElementEventStreamImpl only in dart2js.
+ return new _ElementEventStreamImpl<BeforeUnloadEvent>(
+ e, _eventType, useCapture);
+ }
+
+ ElementStream<BeforeUnloadEvent> _forElementList(ElementList<Element> e,
+ {bool useCapture: false}) {
+ // Specify the generic type for _ElementEventStreamImpl only in dart2js.
+ return new _ElementListEventStreamImpl<BeforeUnloadEvent>(
+ e, _eventType, useCapture);
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class WindowBase64 extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory WindowBase64._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String atob(String atob);
+
+ String btoa(String btoa);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WindowClient")
+class WindowClient extends Client {
+ // To suppress missing implicit constructor warnings.
+ factory WindowClient._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool focused;
+
+ final String visibilityState;
+
+ Future<WindowClient> focus() =>
+ promiseToFuture<WindowClient>(JS("", "#.focus()", this));
+
+ Future<WindowClient> navigate(String url) =>
+ promiseToFuture<WindowClient>(JS("", "#.navigate(#)", this, url));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class WindowEventHandlers extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory WindowEventHandlers._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> hashChangeEvent =
+ const EventStreamProvider<Event>('hashchange');
+
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ static const EventStreamProvider<Event> offlineEvent =
+ const EventStreamProvider<Event>('offline');
+
+ static const EventStreamProvider<Event> onlineEvent =
+ const EventStreamProvider<Event>('online');
+
+ static const EventStreamProvider<PopStateEvent> popStateEvent =
+ const EventStreamProvider<PopStateEvent>('popstate');
+
+ static const EventStreamProvider<StorageEvent> storageEvent =
+ const EventStreamProvider<StorageEvent>('storage');
+
+ static const EventStreamProvider<Event> unloadEvent =
+ const EventStreamProvider<Event>('unload');
+
+ Stream<Event> get onHashChange => hashChangeEvent.forTarget(this);
+
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+
+ Stream<Event> get onOffline => offlineEvent.forTarget(this);
+
+ Stream<Event> get onOnline => onlineEvent.forTarget(this);
+
+ Stream<PopStateEvent> get onPopState => popStateEvent.forTarget(this);
+
+ Stream<StorageEvent> get onStorage => storageEvent.forTarget(this);
+
+ Stream<Event> get onUnload => unloadEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("Worker")
+class Worker extends EventTarget implements AbstractWorker {
+ // To suppress missing implicit constructor warnings.
+ factory Worker._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [Worker].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /**
+ * Static factory designed to expose `message` events to event
+ * handlers that are not necessarily instances of [Worker].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<MessageEvent> messageEvent =
+ const EventStreamProvider<MessageEvent>('message');
+
+ factory Worker(String scriptUrl) {
+ return Worker._create_1(scriptUrl);
+ }
+ static Worker _create_1(scriptUrl) =>
+ JS('Worker', 'new Worker(#)', scriptUrl);
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ JS('bool', '(typeof window.Worker != "undefined")');
+
+ void postMessage(/*any*/ message, [List<Object> transfer]) {
+ if (transfer != null) {
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_1(message_1, transfer);
+ return;
+ }
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_2(message_1);
+ return;
+ }
+
+ @JSName('postMessage')
+ void _postMessage_1(message, List<Object> transfer) native;
+ @JSName('postMessage')
+ void _postMessage_2(message) native;
+
+ void terminate() native;
+
+ /// Stream of `error` events handled by this [Worker].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `message` events handled by this [Worker].
+ Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WorkerGlobalScope")
+class WorkerGlobalScope extends EventTarget
+ implements _WindowTimers, WindowBase64 {
+ // To suppress missing implicit constructor warnings.
+ factory WorkerGlobalScope._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [WorkerGlobalScope].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ final String addressSpace;
+
+ final CacheStorage caches;
+
+ final Crypto crypto;
+
+ final IdbFactory indexedDB;
+
+ final bool isSecureContext;
+
+ final _WorkerLocation location;
+
+ final _WorkerNavigator navigator;
+
+ final String origin;
+
+ final WorkerPerformance performance;
+
+ final WorkerGlobalScope self;
+
+ Future fetch(/*RequestInfo*/ input, [Map init]) {
+ var init_dict = null;
+ if (init != null) {
+ init_dict = convertDartToNative_Dictionary(init);
+ }
+ return promiseToFuture(JS("", "#.fetch(#, #)", this, input, init_dict));
+ }
+
+ void importScripts(String urls) native;
+
+ // From WindowBase64
+
+ String atob(String atob) native;
+
+ String btoa(String btoa) native;
+
+ // From WindowTimers
+
+ @JSName('setInterval')
+ int _setInterval_String(String handler, [int timeout, Object arguments])
+ native;
+
+ @JSName('setTimeout')
+ int _setTimeout_String(String handler, [int timeout, Object arguments])
+ native;
+
+ @JSName('clearInterval')
+ void _clearInterval([int handle]) native;
+
+ @JSName('clearTimeout')
+ void _clearTimeout([int handle]) native;
+
+ @JSName('setInterval')
+ int _setInterval(Object handler, [int timeout]) native;
+
+ @JSName('setTimeout')
+ int _setTimeout(Object handler, [int timeout]) native;
+
+ /// Stream of `error` events handled by this [WorkerGlobalScope].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ static WorkerGlobalScope get instance => _workerSelf;
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WorkerPerformance")
+class WorkerPerformance extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory WorkerPerformance._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final MemoryInfo memory;
+
+ final num timeOrigin;
+
+ void clearMarks(String markName) native;
+
+ void clearMeasures(String measureName) native;
+
+ void clearResourceTimings() native;
+
+ List<PerformanceEntry> getEntries() native;
+
+ List<PerformanceEntry> getEntriesByName(String name, String entryType) native;
+
+ List<PerformanceEntry> getEntriesByType(String entryType) native;
+
+ void mark(String markName) native;
+
+ void measure(String measureName, String startMark, String endMark) native;
+
+ double now() native;
+
+ void setResourceTimingBufferSize(int maxSize) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WorkletAnimation")
+class WorkletAnimation extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory WorkletAnimation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory WorkletAnimation(
+ String animatorName,
+ List<KeyframeEffectReadOnly> effects,
+ List<Object> timelines,
+ /*SerializedScriptValue*/ options) {
+ var options_1 = convertDartToNative_SerializedScriptValue(options);
+ return WorkletAnimation._create_1(
+ animatorName, effects, timelines, options_1);
+ }
+ static WorkletAnimation _create_1(
+ animatorName, effects, timelines, options) =>
+ JS('WorkletAnimation', 'new WorkletAnimation(#,#,#,#)', animatorName,
+ effects, timelines, options);
+
+ final String playState;
+
+ void cancel() native;
+
+ void play() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WorkletGlobalScope")
+class WorkletGlobalScope extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory WorkletGlobalScope._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathEvaluator
+@deprecated // experimental
+@Native("XPathEvaluator")
+class XPathEvaluator extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory XPathEvaluator._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory XPathEvaluator() {
+ return XPathEvaluator._create_1();
+ }
+ static XPathEvaluator _create_1() =>
+ JS('XPathEvaluator', 'new XPathEvaluator()');
+
+ XPathExpression createExpression(String expression, XPathNSResolver resolver)
+ native;
+
+ XPathNSResolver createNSResolver(Node nodeResolver) native;
+
+ XPathResult evaluate(
+ String expression, Node contextNode, XPathNSResolver resolver,
+ [int type, Object inResult]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathExpression
+@deprecated // experimental
+@Native("XPathExpression")
+class XPathExpression extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory XPathExpression._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ XPathResult evaluate(Node contextNode, [int type, Object inResult]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathNSResolver
+@deprecated // experimental
+@Native("XPathNSResolver")
+class XPathNSResolver extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory XPathNSResolver._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('lookupNamespaceURI')
+ String lookupNamespaceUri(String prefix) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathResult
+@deprecated // experimental
+@Native("XPathResult")
+class XPathResult extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory XPathResult._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int ANY_TYPE = 0;
+
+ static const int ANY_UNORDERED_NODE_TYPE = 8;
+
+ static const int BOOLEAN_TYPE = 3;
+
+ static const int FIRST_ORDERED_NODE_TYPE = 9;
+
+ static const int NUMBER_TYPE = 1;
+
+ static const int ORDERED_NODE_ITERATOR_TYPE = 5;
+
+ static const int ORDERED_NODE_SNAPSHOT_TYPE = 7;
+
+ static const int STRING_TYPE = 2;
+
+ static const int UNORDERED_NODE_ITERATOR_TYPE = 4;
+
+ static const int UNORDERED_NODE_SNAPSHOT_TYPE = 6;
+
+ final bool booleanValue;
+
+ final bool invalidIteratorState;
+
+ final num numberValue;
+
+ final int resultType;
+
+ final Node singleNodeValue;
+
+ final int snapshotLength;
+
+ final String stringValue;
+
+ Node iterateNext() native;
+
+ Node snapshotItem(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("XMLDocument")
+class XmlDocument extends Document {
+ // To suppress missing implicit constructor warnings.
+ factory XmlDocument._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://domparsing.spec.whatwg.org/#the-xmlserializer-interface
+@deprecated // stable
+@Native("XMLSerializer")
+class XmlSerializer extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory XmlSerializer._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory XmlSerializer() {
+ return XmlSerializer._create_1();
+ }
+ static XmlSerializer _create_1() =>
+ JS('XmlSerializer', 'new XMLSerializer()');
+
+ String serializeToString(Node root) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@deprecated // nonstandard
+@Native("XSLTProcessor")
+class XsltProcessor extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory XsltProcessor._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory XsltProcessor() {
+ return XsltProcessor._create_1();
+ }
+ static XsltProcessor _create_1() =>
+ JS('XsltProcessor', 'new XSLTProcessor()');
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => JS('bool', '!!(window.XSLTProcessor)');
+
+ void clearParameters() native;
+
+ String getParameter(String namespaceURI, String localName) native;
+
+ void importStylesheet(Node style) native;
+
+ void removeParameter(String namespaceURI, String localName) native;
+
+ void reset() native;
+
+ void setParameter(String namespaceURI, String localName, String value) native;
+
+ Document transformToDocument(Node source) native;
+
+ DocumentFragment transformToFragment(Node source, Document output) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Attr")
+class _Attr extends Node {
+ // To suppress missing implicit constructor warnings.
+ factory _Attr._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('localName')
+ final String _localName;
+
+ final String name;
+
+ @JSName('namespaceURI')
+ final String _namespaceUri;
+
+ String value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Bluetooth")
+abstract class _Bluetooth extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _Bluetooth._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothCharacteristicProperties")
+abstract class _BluetoothCharacteristicProperties extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _BluetoothCharacteristicProperties._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothDevice")
+abstract class _BluetoothDevice extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory _BluetoothDevice._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothRemoteGATTCharacteristic")
+abstract class _BluetoothRemoteGATTCharacteristic extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory _BluetoothRemoteGATTCharacteristic._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothRemoteGATTServer")
+abstract class _BluetoothRemoteGATTServer extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _BluetoothRemoteGATTServer._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothRemoteGATTService")
+abstract class _BluetoothRemoteGATTService extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _BluetoothRemoteGATTService._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BluetoothUUID")
+abstract class _BluetoothUUID extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _BluetoothUUID._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BudgetService")
+class _BudgetService extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _BudgetService._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future<BudgetState> getBudget() =>
+ promiseToFuture<BudgetState>(JS("", "#.getBudget()", this));
+
+ Future<double> getCost(String operation) =>
+ promiseToFuture<double>(JS("", "#.getCost(#)", this, operation));
+
+ Future<bool> reserve(String operation) =>
+ promiseToFuture<bool>(JS("", "#.reserve(#)", this, operation));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Cache")
+abstract class _Cache extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _Cache._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class _CanvasPath extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _CanvasPath._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Clipboard")
+class _Clipboard extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory _Clipboard._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future<DataTransfer> read() =>
+ promiseToFuture<DataTransfer>(JS("", "#.read()", this));
+
+ Future<String> readText() =>
+ promiseToFuture<String>(JS("", "#.readText()", this));
+
+ Future write(DataTransfer data) =>
+ promiseToFuture(JS("", "#.write(#)", this, data));
+
+ Future writeText(String data) =>
+ promiseToFuture(JS("", "#.writeText(#)", this, data));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("CSSRuleList")
+class _CssRuleList extends Interceptor
+ with ListMixin<CssRule>, ImmutableListMixin<CssRule>
+ implements JavaScriptIndexingBehavior<CssRule>, List<CssRule> {
+ // To suppress missing implicit constructor warnings.
+ factory _CssRuleList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ CssRule operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("CssRule", "#[#]", this, index);
+ }
+
+ void operator []=(int index, CssRule value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<CssRule> mixins.
+ // CssRule is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ CssRule get first {
+ if (this.length > 0) {
+ return JS('CssRule', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ CssRule get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('CssRule', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ CssRule get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('CssRule', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ CssRule elementAt(int index) => this[index];
+ // -- end List<CssRule> mixins.
+
+ CssRule item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Native("DOMFileSystemSync")
+abstract class _DOMFileSystemSync extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _DOMFileSystemSync._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DirectoryEntrySync")
+abstract class _DirectoryEntrySync extends _EntrySync {
+ // To suppress missing implicit constructor warnings.
+ factory _DirectoryEntrySync._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DirectoryReaderSync")
+abstract class _DirectoryReaderSync extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _DirectoryReaderSync._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-412266927
+@deprecated // stable
+@Native("DocumentType")
+abstract class _DocumentType extends Node implements ChildNode {
+ // To suppress missing implicit constructor warnings.
+ factory _DocumentType._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ // From ChildNode
+
+}
+
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ClientRect,DOMRect")
+class _DomRect extends DomRectReadOnly implements Rectangle {
+ // NOTE! All code below should be common with RectangleBase.
+ String toString() {
+ return 'Rectangle ($left, $top) $width x $height';
+ }
+
+ bool operator ==(other) {
+ if (other is! Rectangle) return false;
+ return left == other.left &&
+ top == other.top &&
+ width == other.width &&
+ height == other.height;
+ }
+
+ int get hashCode => _JenkinsSmiHash.hash4(
+ left.hashCode, top.hashCode, width.hashCode, height.hashCode);
+
+ /**
+ * Computes the intersection of `this` and [other].
+ *
+ * The intersection of two axis-aligned rectangles, if any, is always another
+ * axis-aligned rectangle.
+ *
+ * Returns the intersection of this and `other`, or null if they don't
+ * intersect.
+ */
+ Rectangle intersection(Rectangle other) {
+ var x0 = max(left, other.left);
+ var x1 = min(left + width, other.left + other.width);
+
+ if (x0 <= x1) {
+ var y0 = max(top, other.top);
+ var y1 = min(top + height, other.top + other.height);
+
+ if (y0 <= y1) {
+ return new Rectangle(x0, y0, x1 - x0, y1 - y0);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if `this` intersects [other].
+ */
+ bool intersects(Rectangle<num> other) {
+ return (left <= other.left + other.width &&
+ other.left <= left + width &&
+ top <= other.top + other.height &&
+ other.top <= top + height);
+ }
+
+ /**
+ * Returns a new rectangle which completely contains `this` and [other].
+ */
+ Rectangle boundingBox(Rectangle other) {
+ var right = max(this.left + this.width, other.left + other.width);
+ var bottom = max(this.top + this.height, other.top + other.height);
+
+ var left = min(this.left, other.left);
+ var top = min(this.top, other.top);
+
+ return new Rectangle(left, top, right - left, bottom - top);
+ }
+
+ /**
+ * Tests whether `this` entirely contains [another].
+ */
+ bool containsRectangle(Rectangle<num> another) {
+ return left <= another.left &&
+ left + width >= another.left + another.width &&
+ top <= another.top &&
+ top + height >= another.top + another.height;
+ }
+
+ /**
+ * Tests whether [another] is inside or along the edges of `this`.
+ */
+ bool containsPoint(Point<num> another) {
+ return another.x >= left &&
+ another.x <= left + width &&
+ another.y >= top &&
+ another.y <= top + height;
+ }
+
+ Point get topLeft => new Point(this.left, this.top);
+ Point get topRight => new Point(this.left + this.width, this.top);
+ Point get bottomRight =>
+ new Point(this.left + this.width, this.top + this.height);
+ Point get bottomLeft => new Point(this.left, this.top + this.height);
+
+ // To suppress missing implicit constructor warnings.
+ factory _DomRect._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _DomRect([num x, num y, num width, num height]) {
+ if (height != null) {
+ return _DomRect._create_1(x, y, width, height);
+ }
+ if (width != null) {
+ return _DomRect._create_2(x, y, width);
+ }
+ if (y != null) {
+ return _DomRect._create_3(x, y);
+ }
+ if (x != null) {
+ return _DomRect._create_4(x);
+ }
+ return _DomRect._create_5();
+ }
+ static _DomRect _create_1(x, y, width, height) =>
+ JS('_DomRect', 'new DOMRect(#,#,#,#)', x, y, width, height);
+ static _DomRect _create_2(x, y, width) =>
+ JS('_DomRect', 'new DOMRect(#,#,#)', x, y, width);
+ static _DomRect _create_3(x, y) => JS('_DomRect', 'new DOMRect(#,#)', x, y);
+ static _DomRect _create_4(x) => JS('_DomRect', 'new DOMRect(#)', x);
+ static _DomRect _create_5() => JS('_DomRect', 'new DOMRect()');
+
+ // Shadowing definition.
+ num get height => JS("num", "#.height", this);
+
+ set height(num value) {
+ JS("void", "#.height = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get width => JS("num", "#.width", this);
+
+ set width(num value) {
+ JS("void", "#.width = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get x => JS("num", "#.x", this);
+
+ set x(num value) {
+ JS("void", "#.x = #", this, value);
+ }
+
+ // Shadowing definition.
+ num get y => JS("num", "#.y", this);
+
+ set y(num value) {
+ JS("void", "#.y = #", this, value);
+ }
+}
+
+/**
+ * This is the [Jenkins hash function][1] but using masking to keep
+ * values in SMI range.
+ *
+ * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+ *
+ * Use:
+ * Hash each value with the hash of the previous value, then get the final
+ * hash by calling finish.
+ *
+ * var hash = 0;
+ * for (var value in values) {
+ * hash = JenkinsSmiHash.combine(hash, value.hashCode);
+ * }
+ * hash = JenkinsSmiHash.finish(hash);
+ */
+class _JenkinsSmiHash {
+ // TODO(11617): This class should be optimized and standardized elsewhere.
+
+ static int combine(int hash, int value) {
+ hash = 0x1fffffff & (hash + value);
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+ return hash ^ (hash >> 6);
+ }
+
+ static int finish(int hash) {
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+ hash = hash ^ (hash >> 11);
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+ }
+
+ static int hash2(a, b) => finish(combine(combine(0, a), b));
+
+ static int hash4(a, b, c, d) =>
+ finish(combine(combine(combine(combine(0, a), b), c), d));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EntrySync")
+abstract class _EntrySync extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _EntrySync._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileEntrySync")
+abstract class _FileEntrySync extends _EntrySync {
+ // To suppress missing implicit constructor warnings.
+ factory _FileEntrySync._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileReaderSync")
+abstract class _FileReaderSync extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _FileReaderSync._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _FileReaderSync() {
+ return _FileReaderSync._create_1();
+ }
+ static _FileReaderSync _create_1() =>
+ JS('_FileReaderSync', 'new FileReaderSync()');
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("FileWriterSync")
+abstract class _FileWriterSync extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _FileWriterSync._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("GamepadList")
+class _GamepadList extends Interceptor
+ with ListMixin<Gamepad>, ImmutableListMixin<Gamepad>
+ implements List<Gamepad>, JavaScriptIndexingBehavior<Gamepad> {
+ // To suppress missing implicit constructor warnings.
+ factory _GamepadList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ Gamepad operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("Gamepad|Null", "#[#]", this, index);
+ }
+
+ void operator []=(int index, Gamepad value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<Gamepad> mixins.
+ // Gamepad is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ Gamepad get first {
+ if (this.length > 0) {
+ return JS('Gamepad|Null', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ Gamepad get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('Gamepad|Null', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ Gamepad get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('Gamepad|Null', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ Gamepad elementAt(int index) => this[index];
+ // -- end List<Gamepad> mixins.
+
+ Gamepad item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#dom-document-all
+@deprecated // deprecated
+@Native("HTMLAllCollection")
+abstract class _HTMLAllCollection extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _HTMLAllCollection._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('item')
+ Element _item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#dir
+@deprecated // deprecated
+@Native("HTMLDirectoryElement")
+abstract class _HTMLDirectoryElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory _HTMLDirectoryElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ _HTMLDirectoryElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#htmlfontelement
+@deprecated // deprecated
+@Native("HTMLFontElement")
+abstract class _HTMLFontElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory _HTMLFontElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ _HTMLFontElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#htmlframeelement
+@deprecated // deprecated
+@Native("HTMLFrameElement")
+abstract class _HTMLFrameElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory _HTMLFrameElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ _HTMLFrameElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#frameset
+@deprecated // deprecated
+@Native("HTMLFrameSetElement")
+abstract class _HTMLFrameSetElement extends HtmlElement
+ implements WindowEventHandlers {
+ // To suppress missing implicit constructor warnings.
+ factory _HTMLFrameSetElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ _HTMLFrameSetElement.created() : super.created();
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#the-marquee-element
+@deprecated // deprecated
+@Native("HTMLMarqueeElement")
+abstract class _HTMLMarqueeElement extends HtmlElement {
+ // To suppress missing implicit constructor warnings.
+ factory _HTMLMarqueeElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ _HTMLMarqueeElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Mojo")
+abstract class _Mojo extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _Mojo._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MojoHandle")
+abstract class _MojoHandle extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _MojoHandle._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MojoInterfaceInterceptor")
+abstract class _MojoInterfaceInterceptor extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory _MojoInterfaceInterceptor._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _MojoInterfaceInterceptor(String interfaceName, [String scope]) {
+ if (scope != null) {
+ return _MojoInterfaceInterceptor._create_1(interfaceName, scope);
+ }
+ return _MojoInterfaceInterceptor._create_2(interfaceName);
+ }
+ static _MojoInterfaceInterceptor _create_1(interfaceName, scope) => JS(
+ '_MojoInterfaceInterceptor',
+ 'new MojoInterfaceInterceptor(#,#)',
+ interfaceName,
+ scope);
+ static _MojoInterfaceInterceptor _create_2(interfaceName) => JS(
+ '_MojoInterfaceInterceptor',
+ 'new MojoInterfaceInterceptor(#)',
+ interfaceName);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MojoInterfaceRequestEvent")
+abstract class _MojoInterfaceRequestEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory _MojoInterfaceRequestEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _MojoInterfaceRequestEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return _MojoInterfaceRequestEvent._create_1(type, eventInitDict_1);
+ }
+ return _MojoInterfaceRequestEvent._create_2(type);
+ }
+ static _MojoInterfaceRequestEvent _create_1(type, eventInitDict) => JS(
+ '_MojoInterfaceRequestEvent',
+ 'new MojoInterfaceRequestEvent(#,#)',
+ type,
+ eventInitDict);
+ static _MojoInterfaceRequestEvent _create_2(type) => JS(
+ '_MojoInterfaceRequestEvent', 'new MojoInterfaceRequestEvent(#)', type);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MojoWatcher")
+abstract class _MojoWatcher extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _MojoWatcher._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("NFC")
+abstract class _NFC extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _NFC._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// http://dom.spec.whatwg.org/#namednodemap
+@deprecated // deprecated
+@Native("NamedNodeMap,MozNamedAttrMap")
+class _NamedNodeMap extends Interceptor
+ with ListMixin<Node>, ImmutableListMixin<Node>
+ implements JavaScriptIndexingBehavior<Node>, List<Node> {
+ // To suppress missing implicit constructor warnings.
+ factory _NamedNodeMap._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ Node operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("Node", "#[#]", this, index);
+ }
+
+ void operator []=(int index, Node value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<Node> mixins.
+ // Node is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ Node get first {
+ if (this.length > 0) {
+ return JS('Node', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ Node get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('Node', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ Node get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('Node', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ Node elementAt(int index) => this[index];
+ // -- end List<Node> mixins.
+
+ _Attr getNamedItem(String name) native;
+
+ _Attr getNamedItemNS(String namespaceURI, String localName) native;
+
+ _Attr item(int index) native;
+
+ _Attr removeNamedItem(String name) native;
+
+ _Attr removeNamedItemNS(String namespaceURI, String localName) native;
+
+ _Attr setNamedItem(_Attr attr) native;
+
+ _Attr setNamedItemNS(_Attr attr) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@deprecated // nonstandard
+@Native("PagePopupController")
+abstract class _PagePopupController extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _PagePopupController._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Omit RadioNodeList for dart2js. The Dart Form and FieldSet APIs don't
+// currently expose an API the returns RadioNodeList. The only use of a
+// RadioNodeList is to get the selected value and it will be cleaner to
+// introduce a different API for that purpose.
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Report")
+class _Report extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _Report._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final ReportBody body;
+
+ final String type;
+
+ final String url;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Request")
+class _Request extends Body {
+ // To suppress missing implicit constructor warnings.
+ factory _Request._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _Request(Object input, [Map requestInitDict]) {
+ if (requestInitDict != null) {
+ var requestInitDict_1 = convertDartToNative_Dictionary(requestInitDict);
+ return _Request._create_1(input, requestInitDict_1);
+ }
+ return _Request._create_2(input);
+ }
+ static _Request _create_1(input, requestInitDict) =>
+ JS('_Request', 'new Request(#,#)', input, requestInitDict);
+ static _Request _create_2(input) => JS('_Request', 'new Request(#)', input);
+
+ final String cache;
+
+ final String credentials;
+
+ final Headers headers;
+
+ final String integrity;
+
+ final String mode;
+
+ final String redirect;
+
+ final String referrer;
+
+ final String referrerPolicy;
+
+ final String url;
+
+ _Request clone() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// https://chromiumcodereview.appspot.com/14773025/
+@deprecated // experimental
+@Native("ResourceProgressEvent")
+abstract class _ResourceProgressEvent extends ProgressEvent {
+ // To suppress missing implicit constructor warnings.
+ factory _ResourceProgressEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Response")
+abstract class _Response extends Body {
+ // To suppress missing implicit constructor warnings.
+ factory _Response._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _Response([Object body, Map init]) {
+ if (init != null) {
+ var init_1 = convertDartToNative_Dictionary(init);
+ return _Response._create_1(body, init_1);
+ }
+ if (body != null) {
+ return _Response._create_2(body);
+ }
+ return _Response._create_3();
+ }
+ static _Response _create_1(body, init) =>
+ JS('_Response', 'new Response(#,#)', body, init);
+ static _Response _create_2(body) => JS('_Response', 'new Response(#)', body);
+ static _Response _create_3() => JS('_Response', 'new Response()');
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SpeechRecognitionResultList")
+class _SpeechRecognitionResultList extends Interceptor
+ with
+ ListMixin<SpeechRecognitionResult>,
+ ImmutableListMixin<SpeechRecognitionResult>
+ implements
+ JavaScriptIndexingBehavior<SpeechRecognitionResult>,
+ List<SpeechRecognitionResult> {
+ // To suppress missing implicit constructor warnings.
+ factory _SpeechRecognitionResultList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ SpeechRecognitionResult operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("SpeechRecognitionResult", "#[#]", this, index);
+ }
+
+ void operator []=(int index, SpeechRecognitionResult value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<SpeechRecognitionResult> mixins.
+ // SpeechRecognitionResult is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ SpeechRecognitionResult get first {
+ if (this.length > 0) {
+ return JS('SpeechRecognitionResult', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ SpeechRecognitionResult get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('SpeechRecognitionResult', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ SpeechRecognitionResult get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('SpeechRecognitionResult', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ SpeechRecognitionResult elementAt(int index) => this[index];
+ // -- end List<SpeechRecognitionResult> mixins.
+
+ SpeechRecognitionResult item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StyleSheetList")
+class _StyleSheetList extends Interceptor
+ with ListMixin<StyleSheet>, ImmutableListMixin<StyleSheet>
+ implements List<StyleSheet>, JavaScriptIndexingBehavior<StyleSheet> {
+ // To suppress missing implicit constructor warnings.
+ factory _StyleSheetList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ StyleSheet operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return JS("StyleSheet", "#[#]", this, index);
+ }
+
+ void operator []=(int index, StyleSheet value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<StyleSheet> mixins.
+ // StyleSheet is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ StyleSheet get first {
+ if (this.length > 0) {
+ return JS('StyleSheet', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ StyleSheet get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('StyleSheet', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ StyleSheet get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('StyleSheet', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ StyleSheet elementAt(int index) => this[index];
+ // -- end List<StyleSheet> mixins.
+
+ CssStyleSheet __getter__(String name) native;
+
+ StyleSheet item(int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SubtleCrypto")
+abstract class _SubtleCrypto extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _SubtleCrypto._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USB")
+abstract class _USB extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory _USB._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBAlternateInterface")
+abstract class _USBAlternateInterface extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _USBAlternateInterface._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _USBAlternateInterface(
+ _USBInterface deviceInterface, int alternateSetting) {
+ return _USBAlternateInterface._create_1(deviceInterface, alternateSetting);
+ }
+ static _USBAlternateInterface _create_1(deviceInterface, alternateSetting) =>
+ JS('_USBAlternateInterface', 'new USBAlternateInterface(#,#)',
+ deviceInterface, alternateSetting);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBConfiguration")
+abstract class _USBConfiguration extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _USBConfiguration._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _USBConfiguration(_USBDevice device, int configurationValue) {
+ return _USBConfiguration._create_1(device, configurationValue);
+ }
+ static _USBConfiguration _create_1(device, configurationValue) => JS(
+ '_USBConfiguration',
+ 'new USBConfiguration(#,#)',
+ device,
+ configurationValue);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBConnectionEvent")
+abstract class _USBConnectionEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory _USBConnectionEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _USBConnectionEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return _USBConnectionEvent._create_1(type, eventInitDict_1);
+ }
+ static _USBConnectionEvent _create_1(type, eventInitDict) => JS(
+ '_USBConnectionEvent',
+ 'new USBConnectionEvent(#,#)',
+ type,
+ eventInitDict);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBDevice")
+abstract class _USBDevice extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _USBDevice._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBEndpoint")
+abstract class _USBEndpoint extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _USBEndpoint._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _USBEndpoint(
+ _USBAlternateInterface alternate, int endpointNumber, String direction) {
+ return _USBEndpoint._create_1(alternate, endpointNumber, direction);
+ }
+ static _USBEndpoint _create_1(alternate, endpointNumber, direction) => JS(
+ '_USBEndpoint',
+ 'new USBEndpoint(#,#,#)',
+ alternate,
+ endpointNumber,
+ direction);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBInTransferResult")
+abstract class _USBInTransferResult extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _USBInTransferResult._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _USBInTransferResult(String status, [ByteData data]) {
+ if (data != null) {
+ return _USBInTransferResult._create_1(status, data);
+ }
+ return _USBInTransferResult._create_2(status);
+ }
+ static _USBInTransferResult _create_1(status, data) =>
+ JS('_USBInTransferResult', 'new USBInTransferResult(#,#)', status, data);
+ static _USBInTransferResult _create_2(status) =>
+ JS('_USBInTransferResult', 'new USBInTransferResult(#)', status);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBInterface")
+abstract class _USBInterface extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _USBInterface._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _USBInterface(_USBConfiguration configuration, int interfaceNumber) {
+ return _USBInterface._create_1(configuration, interfaceNumber);
+ }
+ static _USBInterface _create_1(configuration, interfaceNumber) => JS(
+ '_USBInterface', 'new USBInterface(#,#)', configuration, interfaceNumber);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBIsochronousInTransferPacket")
+abstract class _USBIsochronousInTransferPacket extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _USBIsochronousInTransferPacket._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _USBIsochronousInTransferPacket(String status, [ByteData data]) {
+ if (data != null) {
+ return _USBIsochronousInTransferPacket._create_1(status, data);
+ }
+ return _USBIsochronousInTransferPacket._create_2(status);
+ }
+ static _USBIsochronousInTransferPacket _create_1(status, data) => JS(
+ '_USBIsochronousInTransferPacket',
+ 'new USBIsochronousInTransferPacket(#,#)',
+ status,
+ data);
+ static _USBIsochronousInTransferPacket _create_2(status) => JS(
+ '_USBIsochronousInTransferPacket',
+ 'new USBIsochronousInTransferPacket(#)',
+ status);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBIsochronousInTransferResult")
+abstract class _USBIsochronousInTransferResult extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _USBIsochronousInTransferResult._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _USBIsochronousInTransferResult(
+ List<_USBIsochronousInTransferPacket> packets,
+ [ByteData data]) {
+ if (data != null) {
+ return _USBIsochronousInTransferResult._create_1(packets, data);
+ }
+ return _USBIsochronousInTransferResult._create_2(packets);
+ }
+ static _USBIsochronousInTransferResult _create_1(packets, data) => JS(
+ '_USBIsochronousInTransferResult',
+ 'new USBIsochronousInTransferResult(#,#)',
+ packets,
+ data);
+ static _USBIsochronousInTransferResult _create_2(packets) => JS(
+ '_USBIsochronousInTransferResult',
+ 'new USBIsochronousInTransferResult(#)',
+ packets);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBIsochronousOutTransferPacket")
+abstract class _USBIsochronousOutTransferPacket extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _USBIsochronousOutTransferPacket._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _USBIsochronousOutTransferPacket(String status, [int bytesWritten]) {
+ if (bytesWritten != null) {
+ return _USBIsochronousOutTransferPacket._create_1(status, bytesWritten);
+ }
+ return _USBIsochronousOutTransferPacket._create_2(status);
+ }
+ static _USBIsochronousOutTransferPacket _create_1(status, bytesWritten) => JS(
+ '_USBIsochronousOutTransferPacket',
+ 'new USBIsochronousOutTransferPacket(#,#)',
+ status,
+ bytesWritten);
+ static _USBIsochronousOutTransferPacket _create_2(status) => JS(
+ '_USBIsochronousOutTransferPacket',
+ 'new USBIsochronousOutTransferPacket(#)',
+ status);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBIsochronousOutTransferResult")
+abstract class _USBIsochronousOutTransferResult extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _USBIsochronousOutTransferResult._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _USBIsochronousOutTransferResult(
+ List<_USBIsochronousOutTransferPacket> packets) {
+ return _USBIsochronousOutTransferResult._create_1(packets);
+ }
+ static _USBIsochronousOutTransferResult _create_1(packets) => JS(
+ '_USBIsochronousOutTransferResult',
+ 'new USBIsochronousOutTransferResult(#)',
+ packets);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("USBOutTransferResult")
+abstract class _USBOutTransferResult extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _USBOutTransferResult._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _USBOutTransferResult(String status, [int bytesWritten]) {
+ if (bytesWritten != null) {
+ return _USBOutTransferResult._create_1(status, bytesWritten);
+ }
+ return _USBOutTransferResult._create_2(status);
+ }
+ static _USBOutTransferResult _create_1(status, bytesWritten) => JS(
+ '_USBOutTransferResult',
+ 'new USBOutTransferResult(#,#)',
+ status,
+ bytesWritten);
+ static _USBOutTransferResult _create_2(status) =>
+ JS('_USBOutTransferResult', 'new USBOutTransferResult(#)', status);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class _WindowTimers extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _WindowTimers._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int _setInterval_String(String handler, [int timeout, Object arguments]);
+
+ int _setTimeout_String(String handler, [int timeout, Object arguments]);
+
+ void _clearInterval([int handle]);
+
+ void _clearTimeout([int handle]);
+
+ int _setInterval(Object handler, [int timeout]);
+
+ int _setTimeout(Object handler, [int timeout]);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WorkerLocation")
+abstract class _WorkerLocation extends Interceptor implements UrlUtilsReadOnly {
+ // To suppress missing implicit constructor warnings.
+ factory _WorkerLocation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ // From URLUtilsReadOnly
+
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WorkerNavigator")
+abstract class _WorkerNavigator extends NavigatorConcurrentHardware
+ implements NavigatorOnLine, NavigatorID {
+ // To suppress missing implicit constructor warnings.
+ factory _WorkerNavigator._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ // From NavigatorID
+
+ // From NavigatorOnLine
+
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("Worklet")
+abstract class _Worklet extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _Worklet._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class _AttributeMap extends MapBase<String, String> {
+ final Element _element;
+
+ _AttributeMap(this._element);
+
+ void addAll(Map<String, String> other) {
+ other.forEach((k, v) {
+ this[k] = v;
+ });
+ }
+
+ Map<K, V> cast<K, V>() => Map.castFrom<String, String, K, V>(this);
+ bool containsValue(Object value) {
+ for (var v in this.values) {
+ if (value == v) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ String putIfAbsent(String key, String ifAbsent()) {
+ if (!containsKey(key)) {
+ this[key] = ifAbsent();
+ }
+ return this[key];
+ }
+
+ void clear() {
+ for (var key in keys) {
+ remove(key);
+ }
+ }
+
+ void forEach(void f(String key, String value)) {
+ for (var key in keys) {
+ var value = this[key];
+ f(key, value);
+ }
+ }
+
+ Iterable<String> get keys {
+ // TODO: generate a lazy collection instead.
+ var attributes = _element._attributes;
+ var keys = <String>[];
+ for (int i = 0, len = attributes.length; i < len; i++) {
+ _Attr attr = attributes[i];
+ if (_matches(attr)) {
+ keys.add(attr.name);
+ }
+ }
+ return keys;
+ }
+
+ Iterable<String> get values {
+ // TODO: generate a lazy collection instead.
+ var attributes = _element._attributes;
+ var values = <String>[];
+ for (int i = 0, len = attributes.length; i < len; i++) {
+ _Attr attr = attributes[i];
+ if (_matches(attr)) {
+ values.add(attr.value);
+ }
+ }
+ return values;
+ }
+
+ /**
+ * Returns true if there is no {key, value} pair in the map.
+ */
+ bool get isEmpty {
+ return length == 0;
+ }
+
+ /**
+ * Returns true if there is at least one {key, value} pair in the map.
+ */
+ bool get isNotEmpty => !isEmpty;
+
+ /**
+ * Checks to see if the node should be included in this map.
+ */
+ bool _matches(_Attr node);
+}
+
+/**
+ * Wrapper to expose [Element.attributes] as a typed map.
+ */
+class _ElementAttributeMap extends _AttributeMap {
+ _ElementAttributeMap(Element element) : super(element);
+
+ bool containsKey(Object key) {
+ return _element._hasAttribute(key);
+ }
+
+ String operator [](Object key) {
+ return _element.getAttribute(key);
+ }
+
+ void operator []=(String key, String value) {
+ _element.setAttribute(key, value);
+ }
+
+ @pragma('dart2js:tryInline')
+ String remove(Object key) => key is String ? _remove(_element, key) : null;
+
+ /**
+ * The number of {key, value} pairs in the map.
+ */
+ int get length {
+ return keys.length;
+ }
+
+ bool _matches(_Attr node) => node._namespaceUri == null;
+
+ // Inline this because almost all call sites of [remove] do not use [value],
+ // and the annotations on the `getAttribute` call allow it to be removed.
+ @pragma('dart2js:tryInline')
+ static String _remove(Element element, String key) {
+ String value = JS(
+ // throws:null(1) is not accurate since [key] could be malformed, but
+ // [key] is checked again by `removeAttributeNS`.
+ 'returns:String|Null;depends:all;effects:none;throws:null(1)',
+ '#.getAttribute(#)',
+ element,
+ key);
+ JS('', '#.removeAttribute(#)', element, key);
+ return value;
+ }
+}
+
+/**
+ * Wrapper to expose namespaced attributes as a typed map.
+ */
+class _NamespacedAttributeMap extends _AttributeMap {
+ final String _namespace;
+
+ _NamespacedAttributeMap(Element element, this._namespace) : super(element);
+
+ bool containsKey(Object key) {
+ return _element._hasAttributeNS(_namespace, key);
+ }
+
+ String operator [](Object key) {
+ return _element.getAttributeNS(_namespace, key);
+ }
+
+ void operator []=(String key, String value) {
+ _element.setAttributeNS(_namespace, key, value);
+ }
+
+ @pragma('dart2js:tryInline')
+ String remove(Object key) =>
+ key is String ? _remove(_namespace, _element, key) : null;
+
+ /**
+ * The number of {key, value} pairs in the map.
+ */
+ int get length {
+ return keys.length;
+ }
+
+ bool _matches(_Attr node) => node._namespaceUri == _namespace;
+
+ // Inline this because almost all call sites of [remove] do not use the
+ // returned [value], and the annotations on the `getAttributeNS` call allow it
+ // to be removed.
+ @pragma('dart2js:tryInline')
+ static String _remove(String namespace, Element element, String key) {
+ String value = JS(
+ // throws:null(1) is not accurate since [key] could be malformed, but
+ // [key] is checked again by `removeAttributeNS`.
+ 'returns:String|Null;depends:all;effects:none;throws:null(1)',
+ '#.getAttributeNS(#, #)',
+ element,
+ namespace,
+ key);
+ JS('', '#.removeAttributeNS(#, #)', element, namespace, key);
+ return value;
+ }
+}
+
+/**
+ * Provides a Map abstraction on top of data-* attributes, similar to the
+ * dataSet in the old DOM.
+ */
+class _DataAttributeMap extends MapBase<String, String> {
+ final Map<String, String> _attributes;
+
+ _DataAttributeMap(this._attributes);
+
+ // interface Map
+
+ void addAll(Map<String, String> other) {
+ other.forEach((k, v) {
+ this[k] = v;
+ });
+ }
+
+ Map<K, V> cast<K, V>() => Map.castFrom<String, String, K, V>(this);
+ // TODO: Use lazy iterator when it is available on Map.
+ bool containsValue(Object value) => values.any((v) => v == value);
+
+ bool containsKey(Object key) => _attributes.containsKey(_attr(key));
+
+ String operator [](Object key) => _attributes[_attr(key)];
+
+ void operator []=(String key, String value) {
+ _attributes[_attr(key)] = value;
+ }
+
+ String putIfAbsent(String key, String ifAbsent()) =>
+ _attributes.putIfAbsent(_attr(key), ifAbsent);
+
+ String remove(Object key) => _attributes.remove(_attr(key));
+
+ void clear() {
+ // Needs to operate on a snapshot since we are mutating the collection.
+ for (String key in keys) {
+ remove(key);
+ }
+ }
+
+ void forEach(void f(String key, String value)) {
+ _attributes.forEach((String key, String value) {
+ if (_matches(key)) {
+ f(_strip(key), value);
+ }
+ });
+ }
+
+ Iterable<String> get keys {
+ final keys = <String>[];
+ _attributes.forEach((String key, String value) {
+ if (_matches(key)) {
+ keys.add(_strip(key));
+ }
+ });
+ return keys;
+ }
+
+ Iterable<String> get values {
+ final values = <String>[];
+ _attributes.forEach((String key, String value) {
+ if (_matches(key)) {
+ values.add(value);
+ }
+ });
+ return values;
+ }
+
+ int get length => keys.length;
+
+ // TODO: Use lazy iterator when it is available on Map.
+ bool get isEmpty => length == 0;
+
+ bool get isNotEmpty => !isEmpty;
+
+ // Helpers.
+ String _attr(String key) => 'data-${_toHyphenedName(key)}';
+ bool _matches(String key) => key.startsWith('data-');
+ String _strip(String key) => _toCamelCase(key.substring(5));
+
+ /**
+ * Converts a string name with hyphens into an identifier, by removing hyphens
+ * and capitalizing the following letter. Optionally [startUppercase] to
+ * capitalize the first letter.
+ */
+ String _toCamelCase(String hyphenedName, {bool startUppercase: false}) {
+ var segments = hyphenedName.split('-');
+ int start = startUppercase ? 0 : 1;
+ for (int i = start; i < segments.length; i++) {
+ var segment = segments[i];
+ if (segment.length > 0) {
+ // Character between 'a'..'z' mapped to 'A'..'Z'
+ segments[i] = '${segment[0].toUpperCase()}${segment.substring(1)}';
+ }
+ }
+ return segments.join('');
+ }
+
+ /** Reverse of [toCamelCase]. */
+ String _toHyphenedName(String word) {
+ var sb = new StringBuffer();
+ for (int i = 0; i < word.length; i++) {
+ var lower = word[i].toLowerCase();
+ if (word[i] != lower && i > 0) sb.write('-');
+ sb.write(lower);
+ }
+ return sb.toString();
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An object that can be drawn to a 2D canvas rendering context.
+ *
+ * The image drawn to the canvas depends on the type of this object:
+ *
+ * * If this object is an [ImageElement], then this element's image is
+ * drawn to the canvas. If this element is an animated image, then this
+ * element's poster frame is drawn. If this element has no poster frame, then
+ * the first frame of animation is drawn.
+ *
+ * * If this object is a [VideoElement], then the frame at this element's current
+ * playback position is drawn to the canvas.
+ *
+ * * If this object is a [CanvasElement], then this element's bitmap is drawn to
+ * the canvas.
+ *
+ * **Note:** Currently all versions of Internet Explorer do not support
+ * drawing a video element to a canvas. You may also encounter problems drawing
+ * a video to a canvas in Firefox if the source of the video is a data URL.
+ *
+ * ## See also
+ *
+ * * [CanvasRenderingContext2D.drawImage]
+ * * [CanvasRenderingContext2D.drawImageToRect]
+ * * [CanvasRenderingContext2D.drawImageScaled]
+ * * [CanvasRenderingContext2D.drawImageScaledFromSource]
+ *
+ * ## Other resources
+ *
+ * * [Image sources for 2D rendering
+ * contexts](https://html.spec.whatwg.org/multipage/scripting.html#image-sources-for-2d-rendering-contexts)
+ * from WHATWG.
+ * * [Drawing images](https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-drawimage)
+ * from WHATWG.
+ */
+abstract class CanvasImageSource {}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Top-level container for a browser tab or window.
+ *
+ * In a web browser, a [WindowBase] object represents any browser window. This
+ * object contains the window's state and its relation to other
+ * windows, such as which window opened this window.
+ *
+ * **Note:** This class represents any window, while [Window] is
+ * used to access the properties and content of the current window or tab.
+ *
+ * ## See also
+ *
+ * * [Window]
+ *
+ * ## Other resources
+ *
+ * * [DOM Window](https://developer.mozilla.org/en-US/docs/DOM/window) from MDN.
+ * * [Window](http://www.w3.org/TR/Window/) from the W3C.
+ */
+abstract class WindowBase implements EventTarget {
+ // Fields.
+
+ /**
+ * The current location of this window.
+ *
+ * Location currentLocation = window.location;
+ * print(currentLocation.href); // 'http://www.example.com:80/'
+ */
+ LocationBase get location;
+
+ /**
+ * The current session history for this window.
+ *
+ * ## Other resources
+ *
+ * * [Session history and navigation
+ * specification](https://html.spec.whatwg.org/multipage/browsers.html#history)
+ * from WHATWG.
+ */
+ HistoryBase get history;
+
+ /**
+ * Indicates whether this window has been closed.
+ *
+ * print(window.closed); // 'false'
+ * window.close();
+ * print(window.closed); // 'true'
+ */
+ bool get closed;
+
+ /**
+ * A reference to the window that opened this one.
+ *
+ * Window thisWindow = window;
+ * WindowBase otherWindow = thisWindow.open('http://www.example.com/', 'foo');
+ * print(otherWindow.opener == thisWindow); // 'true'
+ */
+ WindowBase get opener;
+
+ /**
+ * A reference to the parent of this window.
+ *
+ * If this [WindowBase] has no parent, [parent] will return a reference to
+ * the [WindowBase] itself.
+ *
+ * IFrameElement myIFrame = new IFrameElement();
+ * window.document.body.elements.add(myIFrame);
+ * print(myIframe.contentWindow.parent == window) // 'true'
+ *
+ * print(window.parent == window) // 'true'
+ */
+ WindowBase get parent;
+
+ /**
+ * A reference to the topmost window in the window hierarchy.
+ *
+ * If this [WindowBase] is the topmost [WindowBase], [top] will return a
+ * reference to the [WindowBase] itself.
+ *
+ * // Add an IFrame to the current window.
+ * IFrameElement myIFrame = new IFrameElement();
+ * window.document.body.elements.add(myIFrame);
+ *
+ * // Add an IFrame inside of the other IFrame.
+ * IFrameElement innerIFrame = new IFrameElement();
+ * myIFrame.elements.add(innerIFrame);
+ *
+ * print(myIframe.contentWindow.top == window) // 'true'
+ * print(innerIFrame.contentWindow.top == window) // 'true'
+ *
+ * print(window.top == window) // 'true'
+ */
+ WindowBase get top;
+
+ // Methods.
+ /**
+ * Closes the window.
+ *
+ * This method should only succeed if the [WindowBase] object is
+ * **script-closeable** and the window calling [close] is allowed to navigate
+ * the window.
+ *
+ * A window is script-closeable if it is either a window
+ * that was opened by another window, or if it is a window with only one
+ * document in its history.
+ *
+ * A window might not be allowed to navigate, and therefore close, another
+ * window due to browser security features.
+ *
+ * var other = window.open('http://www.example.com', 'foo');
+ * // Closes other window, as it is script-closeable.
+ * other.close();
+ * print(other.closed); // 'true'
+ *
+ * var newLocation = window.location
+ * ..href = 'http://www.mysite.com';
+ * window.location = newLocation;
+ * // Does not close this window, as the history has changed.
+ * window.close();
+ * print(window.closed); // 'false'
+ *
+ * See also:
+ *
+ * * [Window close discussion](http://www.w3.org/TR/html5/browsers.html#dom-window-close) from the W3C
+ */
+ void close();
+
+ /**
+ * Sends a cross-origin message.
+ *
+ * ## Other resources
+ *
+ * * [window.postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage)
+ * from MDN.
+ * * [Cross-document messaging](https://html.spec.whatwg.org/multipage/comms.html#web-messaging)
+ * from WHATWG.
+ */
+ void postMessage(var message, String targetOrigin,
+ [List<MessagePort> messagePorts]);
+}
+
+abstract class LocationBase {
+ void set href(String val);
+}
+
+abstract class HistoryBase {
+ void back();
+ void forward();
+ void go(int distance);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/** A Set that stores the CSS class names for an element. */
+abstract class CssClassSet implements Set<String> {
+ /**
+ * Adds the class [value] to the element if it is not on it, removes it if it
+ * is.
+ *
+ * If [shouldAdd] is true, then we always add that [value] to the element. If
+ * [shouldAdd] is false then we always remove [value] from the element.
+ *
+ * If this corresponds to one element, returns `true` if [value] is present
+ * after the operation, and returns `false` if [value] is absent after the
+ * operation.
+ *
+ * If this corresponds to many elements, `null` is always returned.
+ *
+ * [value] must be a valid 'token' representing a single class, i.e. a
+ * non-empty string containing no whitespace. To toggle multiple classes, use
+ * [toggleAll].
+ */
+ bool toggle(String value, [bool shouldAdd]);
+
+ /**
+ * Returns [:true:] if classes cannot be added or removed from this
+ * [:CssClassSet:].
+ */
+ bool get frozen;
+
+ /**
+ * Determine if this element contains the class [value].
+ *
+ * This is the Dart equivalent of jQuery's
+ * [hasClass](http://api.jquery.com/hasClass/).
+ *
+ * [value] must be a valid 'token' representing a single class, i.e. a
+ * non-empty string containing no whitespace.
+ */
+ bool contains(Object value);
+
+ /**
+ * Add the class [value] to element.
+ *
+ * [add] and [addAll] are the Dart equivalent of jQuery's
+ * [addClass](http://api.jquery.com/addClass/).
+ *
+ * If this CssClassSet corresponds to one element. Returns true if [value] was
+ * added to the set, otherwise false.
+ *
+ * If this corresponds to many elements, `null` is always returned.
+ *
+ * [value] must be a valid 'token' representing a single class, i.e. a
+ * non-empty string containing no whitespace. To add multiple classes use
+ * [addAll].
+ */
+ bool add(String value);
+
+ /**
+ * Remove the class [value] from element, and return true on successful
+ * removal.
+ *
+ * [remove] and [removeAll] are the Dart equivalent of jQuery's
+ * [removeClass](http://api.jquery.com/removeClass/).
+ *
+ * [value] must be a valid 'token' representing a single class, i.e. a
+ * non-empty string containing no whitespace. To remove multiple classes, use
+ * [removeAll].
+ */
+ bool remove(Object value);
+
+ /**
+ * Add all classes specified in [iterable] to element.
+ *
+ * [add] and [addAll] are the Dart equivalent of jQuery's
+ * [addClass](http://api.jquery.com/addClass/).
+ *
+ * Each element of [iterable] must be a valid 'token' representing a single
+ * class, i.e. a non-empty string containing no whitespace.
+ */
+ void addAll(Iterable<String> iterable);
+
+ /**
+ * Remove all classes specified in [iterable] from element.
+ *
+ * [remove] and [removeAll] are the Dart equivalent of jQuery's
+ * [removeClass](http://api.jquery.com/removeClass/).
+ *
+ * Each element of [iterable] must be a valid 'token' representing a single
+ * class, i.e. a non-empty string containing no whitespace.
+ */
+ void removeAll(Iterable<Object> iterable);
+
+ /**
+ * Toggles all classes specified in [iterable] on element.
+ *
+ * Iterate through [iterable]'s items, and add it if it is not on it, or
+ * remove it if it is. This is the Dart equivalent of jQuery's
+ * [toggleClass](http://api.jquery.com/toggleClass/).
+ * If [shouldAdd] is true, then we always add all the classes in [iterable]
+ * element. If [shouldAdd] is false then we always remove all the classes in
+ * [iterable] from the element.
+ *
+ * Each element of [iterable] must be a valid 'token' representing a single
+ * class, i.e. a non-empty string containing no whitespace.
+ */
+ void toggleAll(Iterable<String> iterable, [bool shouldAdd]);
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A rectangle representing all the content of the element in the
+ * [box model](http://www.w3.org/TR/CSS2/box.html).
+ */
+class _ContentCssRect extends CssRect {
+ _ContentCssRect(Element element) : super(element);
+
+ num get height =>
+ _element.offsetHeight + _addOrSubtractToBoxModel(_HEIGHT, _CONTENT);
+
+ num get width =>
+ _element.offsetWidth + _addOrSubtractToBoxModel(_WIDTH, _CONTENT);
+
+ /**
+ * Set the height to `newHeight`.
+ *
+ * newHeight can be either a [num] representing the height in pixels or a
+ * [Dimension] object. Values of newHeight that are less than zero are
+ * converted to effectively setting the height to 0. This is equivalent to the
+ * `height` function in jQuery and the calculated `height` CSS value,
+ * converted to a num in pixels.
+ */
+ set height(dynamic newHeight) {
+ if (newHeight is Dimension) {
+ Dimension newHeightAsDimension = newHeight;
+ if (newHeightAsDimension.value < 0) newHeight = new Dimension.px(0);
+ _element.style.height = newHeight.toString();
+ } else if (newHeight is num) {
+ if (newHeight < 0) newHeight = 0;
+ _element.style.height = '${newHeight}px';
+ } else {
+ throw new ArgumentError("newHeight is not a Dimension or num");
+ }
+ }
+
+ /**
+ * Set the current computed width in pixels of this element.
+ *
+ * newWidth can be either a [num] representing the width in pixels or a
+ * [Dimension] object. This is equivalent to the `width` function in jQuery
+ * and the calculated
+ * `width` CSS value, converted to a dimensionless num in pixels.
+ */
+ set width(dynamic newWidth) {
+ if (newWidth is Dimension) {
+ Dimension newWidthAsDimension = newWidth;
+ if (newWidthAsDimension.value < 0) newWidth = new Dimension.px(0);
+ _element.style.width = newWidth.toString();
+ } else if (newWidth is num) {
+ if (newWidth < 0) newWidth = 0;
+ _element.style.width = '${newWidth}px';
+ } else {
+ throw new ArgumentError("newWidth is not a Dimension or num");
+ }
+ }
+
+ num get left =>
+ _element.getBoundingClientRect().left -
+ _addOrSubtractToBoxModel(['left'], _CONTENT);
+ num get top =>
+ _element.getBoundingClientRect().top -
+ _addOrSubtractToBoxModel(['top'], _CONTENT);
+}
+
+/**
+ * A list of element content rectangles in the
+ * [box model](http://www.w3.org/TR/CSS2/box.html).
+ */
+class _ContentCssListRect extends _ContentCssRect {
+ List<Element> _elementList;
+
+ _ContentCssListRect(List<Element> elementList) : super(elementList.first) {
+ _elementList = elementList;
+ }
+
+ /**
+ * Set the height to `newHeight`.
+ *
+ * Values of newHeight that are less than zero are converted to effectively
+ * setting the height to 0. This is equivalent to the `height`
+ * function in jQuery and the calculated `height` CSS value, converted to a
+ * num in pixels.
+ */
+ set height(newHeight) {
+ _elementList.forEach((e) => e.contentEdge.height = newHeight);
+ }
+
+ /**
+ * Set the current computed width in pixels of this element.
+ *
+ * This is equivalent to the `width` function in jQuery and the calculated
+ * `width` CSS value, converted to a dimensionless num in pixels.
+ */
+ set width(newWidth) {
+ _elementList.forEach((e) => e.contentEdge.width = newWidth);
+ }
+}
+
+/**
+ * A rectangle representing the dimensions of the space occupied by the
+ * element's content + padding in the
+ * [box model](http://www.w3.org/TR/CSS2/box.html).
+ */
+class _PaddingCssRect extends CssRect {
+ _PaddingCssRect(element) : super(element);
+ num get height =>
+ _element.offsetHeight + _addOrSubtractToBoxModel(_HEIGHT, _PADDING);
+ num get width =>
+ _element.offsetWidth + _addOrSubtractToBoxModel(_WIDTH, _PADDING);
+
+ num get left =>
+ _element.getBoundingClientRect().left -
+ _addOrSubtractToBoxModel(['left'], _PADDING);
+ num get top =>
+ _element.getBoundingClientRect().top -
+ _addOrSubtractToBoxModel(['top'], _PADDING);
+}
+
+/**
+ * A rectangle representing the dimensions of the space occupied by the
+ * element's content + padding + border in the
+ * [box model](http://www.w3.org/TR/CSS2/box.html).
+ */
+class _BorderCssRect extends CssRect {
+ _BorderCssRect(element) : super(element);
+ num get height => _element.offsetHeight;
+ num get width => _element.offsetWidth;
+
+ num get left => _element.getBoundingClientRect().left;
+ num get top => _element.getBoundingClientRect().top;
+}
+
+/**
+ * A rectangle representing the dimensions of the space occupied by the
+ * element's content + padding + border + margin in the
+ * [box model](http://www.w3.org/TR/CSS2/box.html).
+ */
+class _MarginCssRect extends CssRect {
+ _MarginCssRect(element) : super(element);
+ num get height =>
+ _element.offsetHeight + _addOrSubtractToBoxModel(_HEIGHT, _MARGIN);
+ num get width =>
+ _element.offsetWidth + _addOrSubtractToBoxModel(_WIDTH, _MARGIN);
+
+ num get left =>
+ _element.getBoundingClientRect().left -
+ _addOrSubtractToBoxModel(['left'], _MARGIN);
+ num get top =>
+ _element.getBoundingClientRect().top -
+ _addOrSubtractToBoxModel(['top'], _MARGIN);
+}
+
+/**
+ * A class for representing CSS dimensions.
+ *
+ * In contrast to the more general purpose [Rectangle] class, this class's
+ * values are mutable, so one can change the height of an element
+ * programmatically.
+ *
+ * _Important_ _note_: use of these methods will perform CSS calculations that
+ * can trigger a browser reflow. Therefore, use of these properties _during_ an
+ * animation frame is discouraged. See also:
+ * [Browser Reflow](https://developers.google.com/speed/articles/reflow)
+ */
+abstract class CssRect implements Rectangle<num> {
+ Element _element;
+
+ CssRect(this._element);
+
+ num get left;
+
+ num get top;
+
+ /**
+ * The height of this rectangle.
+ *
+ * This is equivalent to the `height` function in jQuery and the calculated
+ * `height` CSS value, converted to a dimensionless num in pixels. Unlike
+ * [getBoundingClientRect], `height` will return the same numerical width if
+ * the element is hidden or not.
+ */
+ num get height;
+
+ /**
+ * The width of this rectangle.
+ *
+ * This is equivalent to the `width` function in jQuery and the calculated
+ * `width` CSS value, converted to a dimensionless num in pixels. Unlike
+ * [getBoundingClientRect], `width` will return the same numerical width if
+ * the element is hidden or not.
+ */
+ num get width;
+
+ /**
+ * Set the height to `newHeight`.
+ *
+ * newHeight can be either a [num] representing the height in pixels or a
+ * [Dimension] object. Values of newHeight that are less than zero are
+ * converted to effectively setting the height to 0. This is equivalent to the
+ * `height` function in jQuery and the calculated `height` CSS value,
+ * converted to a num in pixels.
+ *
+ * Note that only the content height can actually be set via this method.
+ */
+ set height(dynamic newHeight) {
+ throw new UnsupportedError("Can only set height for content rect.");
+ }
+
+ /**
+ * Set the current computed width in pixels of this element.
+ *
+ * newWidth can be either a [num] representing the width in pixels or a
+ * [Dimension] object. This is equivalent to the `width` function in jQuery
+ * and the calculated
+ * `width` CSS value, converted to a dimensionless num in pixels.
+ *
+ * Note that only the content width can be set via this method.
+ */
+ set width(dynamic newWidth) {
+ throw new UnsupportedError("Can only set width for content rect.");
+ }
+
+ /**
+ * Return a value that is used to modify the initial height or width
+ * measurement of an element. Depending on the value (ideally an enum) passed
+ * to augmentingMeasurement, we may need to add or subtract margin, padding,
+ * or border values, depending on the measurement we're trying to obtain.
+ */
+ num _addOrSubtractToBoxModel(
+ List<String> dimensions, String augmentingMeasurement) {
+ // getComputedStyle always returns pixel values (hence, computed), so we're
+ // always dealing with pixels in this method.
+ var styles = _element.getComputedStyle();
+
+ var val = 0;
+
+ for (String measurement in dimensions) {
+ // The border-box and default box model both exclude margin in the regular
+ // height/width calculation, so add it if we want it for this measurement.
+ if (augmentingMeasurement == _MARGIN) {
+ val += new Dimension.css(
+ styles.getPropertyValue('$augmentingMeasurement-$measurement'))
+ .value;
+ }
+
+ // The border-box includes padding and border, so remove it if we want
+ // just the content itself.
+ if (augmentingMeasurement == _CONTENT) {
+ val -= new Dimension.css(
+ styles.getPropertyValue('${_PADDING}-$measurement'))
+ .value;
+ }
+
+ // At this point, we don't wan't to augment with border or margin,
+ // so remove border.
+ if (augmentingMeasurement != _MARGIN) {
+ val -= new Dimension.css(
+ styles.getPropertyValue('border-${measurement}-width'))
+ .value;
+ }
+ }
+ return val;
+ }
+
+ // TODO(jacobr): these methods are duplicated from _RectangleBase in dart:math
+ // Ideally we would provide a RectangleMixin class that provides this implementation.
+ // In an ideal world we would exp
+ /** The x-coordinate of the right edge. */
+ num get right => left + width;
+ /** The y-coordinate of the bottom edge. */
+ num get bottom => top + height;
+
+ String toString() {
+ return 'Rectangle ($left, $top) $width x $height';
+ }
+
+ bool operator ==(other) {
+ if (other is! Rectangle) return false;
+ return left == other.left &&
+ top == other.top &&
+ right == other.right &&
+ bottom == other.bottom;
+ }
+
+ int get hashCode => _JenkinsSmiHash.hash4(
+ left.hashCode, top.hashCode, right.hashCode, bottom.hashCode);
+
+ /**
+ * Computes the intersection of `this` and [other].
+ *
+ * The intersection of two axis-aligned rectangles, if any, is always another
+ * axis-aligned rectangle.
+ *
+ * Returns the intersection of this and `other`, or `null` if they don't
+ * intersect.
+ */
+ Rectangle<num> intersection(Rectangle<num> other) {
+ var x0 = max(left, other.left);
+ var x1 = min(left + width, other.left + other.width);
+
+ if (x0 <= x1) {
+ var y0 = max(top, other.top);
+ var y1 = min(top + height, other.top + other.height);
+
+ if (y0 <= y1) {
+ return new Rectangle<num>(x0, y0, x1 - x0, y1 - y0);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if `this` intersects [other].
+ */
+ bool intersects(Rectangle<num> other) {
+ return (left <= other.left + other.width &&
+ other.left <= left + width &&
+ top <= other.top + other.height &&
+ other.top <= top + height);
+ }
+
+ /**
+ * Returns a new rectangle which completely contains `this` and [other].
+ */
+ Rectangle<num> boundingBox(Rectangle<num> other) {
+ var right = max(this.left + this.width, other.left + other.width);
+ var bottom = max(this.top + this.height, other.top + other.height);
+
+ var left = min(this.left, other.left);
+ var top = min(this.top, other.top);
+
+ return new Rectangle<num>(left, top, right - left, bottom - top);
+ }
+
+ /**
+ * Tests whether `this` entirely contains [another].
+ */
+ bool containsRectangle(Rectangle<num> another) {
+ return left <= another.left &&
+ left + width >= another.left + another.width &&
+ top <= another.top &&
+ top + height >= another.top + another.height;
+ }
+
+ /**
+ * Tests whether [another] is inside or along the edges of `this`.
+ */
+ bool containsPoint(Point<num> another) {
+ return another.x >= left &&
+ another.x <= left + width &&
+ another.y >= top &&
+ another.y <= top + height;
+ }
+
+ Point<num> get topLeft => new Point<num>(this.left, this.top);
+ Point<num> get topRight => new Point<num>(this.left + this.width, this.top);
+ Point<num> get bottomRight =>
+ new Point<num>(this.left + this.width, this.top + this.height);
+ Point<num> get bottomLeft =>
+ new Point<num>(this.left, this.top + this.height);
+}
+
+final _HEIGHT = ['top', 'bottom'];
+final _WIDTH = ['right', 'left'];
+final _CONTENT = 'content';
+final _PADDING = 'padding';
+final _MARGIN = 'margin';
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A set (union) of the CSS classes that are present in a set of elements.
+ * Implemented separately from _ElementCssClassSet for performance.
+ */
+class _MultiElementCssClassSet extends CssClassSetImpl {
+ final Iterable<Element> _elementIterable;
+
+ // TODO(sra): Perhaps we should store the DomTokenList instead.
+ final List<CssClassSetImpl> _sets;
+
+ factory _MultiElementCssClassSet(Iterable<Element> elements) {
+ return new _MultiElementCssClassSet._(elements,
+ new List<CssClassSetImpl>.from(elements.map((Element e) => e.classes)));
+ }
+
+ _MultiElementCssClassSet._(this._elementIterable, this._sets);
+
+ Set<String> readClasses() {
+ var s = new LinkedHashSet<String>();
+ _sets.forEach((CssClassSetImpl e) => s.addAll(e.readClasses()));
+ return s;
+ }
+
+ void writeClasses(Set<String> s) {
+ var classes = s.join(' ');
+ for (Element e in _elementIterable) {
+ e.className = classes;
+ }
+ }
+
+ /**
+ * Helper method used to modify the set of css classes on this element.
+ *
+ * f - callback with:
+ * s - a Set of all the css class name currently on this element.
+ *
+ * After f returns, the modified set is written to the
+ * className property of this element.
+ */
+ modify(f(Set<String> s)) {
+ _sets.forEach((CssClassSetImpl e) => e.modify(f));
+ }
+
+ /**
+ * Adds the class [value] to the element if it is not on it, removes it if it
+ * is.
+ *
+ * TODO(sra): It seems wrong to collect a 'changed' flag like this when the
+ * underlying toggle returns an 'is set' flag.
+ */
+ bool toggle(String value, [bool shouldAdd]) => _sets.fold(
+ false,
+ (bool changed, CssClassSetImpl e) =>
+ e.toggle(value, shouldAdd) || changed);
+
+ /**
+ * Remove the class [value] from element, and return true on successful
+ * removal.
+ *
+ * This is the Dart equivalent of jQuery's
+ * [removeClass](http://api.jquery.com/removeClass/).
+ */
+ bool remove(Object value) => _sets.fold(
+ false, (bool changed, CssClassSetImpl e) => e.remove(value) || changed);
+}
+
+class _ElementCssClassSet extends CssClassSetImpl {
+ final Element _element;
+
+ _ElementCssClassSet(this._element);
+
+ Set<String> readClasses() {
+ var s = new LinkedHashSet<String>();
+ var classname = _element.className;
+
+ for (String name in classname.split(' ')) {
+ String trimmed = name.trim();
+ if (!trimmed.isEmpty) {
+ s.add(trimmed);
+ }
+ }
+ return s;
+ }
+
+ void writeClasses(Set<String> s) {
+ _element.className = s.join(' ');
+ }
+
+ int get length => _classListLength(_classListOf(_element));
+ bool get isEmpty => length == 0;
+ bool get isNotEmpty => length != 0;
+
+ void clear() {
+ _element.className = '';
+ }
+
+ bool contains(Object value) {
+ return _contains(_element, value);
+ }
+
+ bool add(String value) {
+ return _add(_element, value);
+ }
+
+ bool remove(Object value) {
+ return value is String && _remove(_element, value);
+ }
+
+ bool toggle(String value, [bool shouldAdd]) {
+ return _toggle(_element, value, shouldAdd);
+ }
+
+ void addAll(Iterable<String> iterable) {
+ _addAll(_element, iterable);
+ }
+
+ void removeAll(Iterable<Object> iterable) {
+ _removeAll(_element, iterable);
+ }
+
+ void retainAll(Iterable<Object> iterable) {
+ _removeWhere(_element, iterable.toSet().contains, false);
+ }
+
+ void removeWhere(bool test(String name)) {
+ _removeWhere(_element, test, true);
+ }
+
+ void retainWhere(bool test(String name)) {
+ _removeWhere(_element, test, false);
+ }
+
+ static bool _contains(Element _element, Object value) {
+ return value is String && _classListContains(_classListOf(_element), value);
+ }
+
+ @pragma('dart2js:tryInline')
+ static bool _add(Element _element, String value) {
+ DomTokenList list = _classListOf(_element);
+ // Compute returned result independently of action upon the set.
+ bool added = !_classListContainsBeforeAddOrRemove(list, value);
+ _classListAdd(list, value);
+ return added;
+ }
+
+ @pragma('dart2js:tryInline')
+ static bool _remove(Element _element, String value) {
+ DomTokenList list = _classListOf(_element);
+ bool removed = _classListContainsBeforeAddOrRemove(list, value);
+ _classListRemove(list, value);
+ return removed;
+ }
+
+ static bool _toggle(Element _element, String value, bool shouldAdd) {
+ // There is no value that can be passed as the second argument of
+ // DomTokenList.toggle that behaves the same as passing one argument.
+ // `null` is seen as false, meaning 'remove'.
+ return shouldAdd == null
+ ? _toggleDefault(_element, value)
+ : _toggleOnOff(_element, value, shouldAdd);
+ }
+
+ static bool _toggleDefault(Element _element, String value) {
+ DomTokenList list = _classListOf(_element);
+ return _classListToggle1(list, value);
+ }
+
+ static bool _toggleOnOff(Element _element, String value, bool shouldAdd) {
+ DomTokenList list = _classListOf(_element);
+ // IE's toggle does not take a second parameter. We would prefer:
+ //
+ // return _classListToggle2(list, value, shouldAdd);
+ //
+ if (shouldAdd) {
+ _classListAdd(list, value);
+ return true;
+ } else {
+ _classListRemove(list, value);
+ return false;
+ }
+ }
+
+ static void _addAll(Element _element, Iterable<String> iterable) {
+ DomTokenList list = _classListOf(_element);
+ for (String value in iterable) {
+ _classListAdd(list, value);
+ }
+ }
+
+ static void _removeAll(Element _element, Iterable<Object> iterable) {
+ DomTokenList list = _classListOf(_element);
+ for (String value in iterable) {
+ _classListRemove(list, value);
+ }
+ }
+
+ static void _removeWhere(
+ Element _element, bool test(String name), bool doRemove) {
+ DomTokenList list = _classListOf(_element);
+ int i = 0;
+ while (i < _classListLength(list)) {
+ String item = list.item(i);
+ if (doRemove == test(item)) {
+ _classListRemove(list, item);
+ } else {
+ ++i;
+ }
+ }
+ }
+
+ // A collection of static methods for DomTokenList. These methods are a
+ // work-around for the lack of annotations to express the full behaviour of
+ // the DomTokenList methods.
+
+ static DomTokenList _classListOf(Element e) => JS(
+ 'returns:DomTokenList;creates:DomTokenList;effects:none;depends:all;',
+ '#.classList',
+ e);
+
+ static int _classListLength(DomTokenList list) =>
+ JS('returns:JSUInt31;effects:none;depends:all;', '#.length', list);
+
+ static bool _classListContains(DomTokenList list, String value) =>
+ JS('returns:bool;effects:none;depends:all', '#.contains(#)', list, value);
+
+ static bool _classListContainsBeforeAddOrRemove(
+ DomTokenList list, String value) =>
+ // 'throws:never' is a lie, since 'contains' will throw on an illegal
+ // token. However, we always call this function immediately prior to
+ // add/remove/toggle with the same token. Often the result of 'contains'
+ // is unused and the lie makes it possible for the 'contains' instruction
+ // to be removed.
+ JS('returns:bool;effects:none;depends:all;throws:null(1)',
+ '#.contains(#)', list, value);
+
+ static void _classListAdd(DomTokenList list, String value) {
+ // list.add(value);
+ JS('', '#.add(#)', list, value);
+ }
+
+ static void _classListRemove(DomTokenList list, String value) {
+ // list.remove(value);
+ JS('', '#.remove(#)', list, value);
+ }
+
+ static bool _classListToggle1(DomTokenList list, String value) {
+ return JS('bool', '#.toggle(#)', list, value);
+ }
+
+ static bool _classListToggle2(
+ DomTokenList list, String value, bool shouldAdd) {
+ return JS('bool', '#.toggle(#, #)', list, value, shouldAdd);
+ }
+}
+
+/**
+ * Class representing a
+ * [length measurement](https://developer.mozilla.org/en-US/docs/Web/CSS/length)
+ * in CSS.
+ */
+class Dimension {
+ num _value;
+ String _unit;
+
+ /** Set this CSS Dimension to a percentage `value`. */
+ Dimension.percent(this._value) : _unit = '%';
+
+ /** Set this CSS Dimension to a pixel `value`. */
+ Dimension.px(this._value) : _unit = 'px';
+
+ /** Set this CSS Dimension to a pica `value`. */
+ Dimension.pc(this._value) : _unit = 'pc';
+
+ /** Set this CSS Dimension to a point `value`. */
+ Dimension.pt(this._value) : _unit = 'pt';
+
+ /** Set this CSS Dimension to an inch `value`. */
+ Dimension.inch(this._value) : _unit = 'in';
+
+ /** Set this CSS Dimension to a centimeter `value`. */
+ Dimension.cm(this._value) : _unit = 'cm';
+
+ /** Set this CSS Dimension to a millimeter `value`. */
+ Dimension.mm(this._value) : _unit = 'mm';
+
+ /**
+ * Set this CSS Dimension to the specified number of ems.
+ *
+ * 1em is equal to the current font size. (So 2ems is equal to double the font
+ * size). This is useful for producing website layouts that scale nicely with
+ * the user's desired font size.
+ */
+ Dimension.em(this._value) : _unit = 'em';
+
+ /**
+ * Set this CSS Dimension to the specified number of x-heights.
+ *
+ * One ex is equal to the x-height of a font's baseline to its mean line,
+ * generally the height of the letter "x" in the font, which is usually about
+ * half the font-size.
+ */
+ Dimension.ex(this._value) : _unit = 'ex';
+
+ /**
+ * Construct a Dimension object from the valid, simple CSS string `cssValue`
+ * that represents a distance measurement.
+ *
+ * This constructor is intended as a convenience method for working with
+ * simplistic CSS length measurements. Non-numeric values such as `auto` or
+ * `inherit` or invalid CSS will cause this constructor to throw a
+ * FormatError.
+ */
+ Dimension.css(String cssValue) {
+ if (cssValue == '') cssValue = '0px';
+ if (cssValue.endsWith('%')) {
+ _unit = '%';
+ } else {
+ _unit = cssValue.substring(cssValue.length - 2);
+ }
+ if (cssValue.contains('.')) {
+ _value =
+ double.parse(cssValue.substring(0, cssValue.length - _unit.length));
+ } else {
+ _value = int.parse(cssValue.substring(0, cssValue.length - _unit.length));
+ }
+ }
+
+ /** Print out the CSS String representation of this value. */
+ String toString() {
+ return '${_value}${_unit}';
+ }
+
+ /** Return a unitless, numerical value of this CSS value. */
+ num get value => this._value;
+}
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+typedef EventListener(Event event);
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A factory to expose DOM events as Streams.
+ */
+class EventStreamProvider<T extends Event> {
+ final String _eventType;
+
+ const EventStreamProvider(this._eventType);
+
+ /**
+ * Gets a [Stream] for this event type, on the specified target.
+ *
+ * This will always return a broadcast stream so multiple listeners can be
+ * used simultaneously.
+ *
+ * This may be used to capture DOM events:
+ *
+ * Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
+ *
+ * // Alternate method:
+ * Element.keyDownEvent.forTarget(element).capture(...);
+ *
+ * Or for listening to an event which will bubble through the DOM tree:
+ *
+ * MediaElement.pauseEvent.forTarget(document.body).listen(...);
+ *
+ * See also:
+ *
+ * * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
+ * from MDN.
+ */
+ Stream<T> forTarget(EventTarget e, {bool useCapture: false}) =>
+ new _EventStream<T>(e, _eventType, useCapture);
+
+ /**
+ * Gets an [ElementEventStream] for this event type, on the specified element.
+ *
+ * This will always return a broadcast stream so multiple listeners can be
+ * used simultaneously.
+ *
+ * This may be used to capture DOM events:
+ *
+ * Element.keyDownEvent.forElement(element, useCapture: true).listen(...);
+ *
+ * // Alternate method:
+ * Element.keyDownEvent.forElement(element).capture(...);
+ *
+ * Or for listening to an event which will bubble through the DOM tree:
+ *
+ * MediaElement.pauseEvent.forElement(document.body).listen(...);
+ *
+ * See also:
+ *
+ * * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
+ * from MDN.
+ */
+ ElementStream<T> forElement(Element e, {bool useCapture: false}) {
+ return new _ElementEventStreamImpl<T>(e, _eventType, useCapture);
+ }
+
+ /**
+ * Gets an [ElementEventStream] for this event type, on the list of elements.
+ *
+ * This will always return a broadcast stream so multiple listeners can be
+ * used simultaneously.
+ *
+ * This may be used to capture DOM events:
+ *
+ * Element.keyDownEvent._forElementList(element, useCapture: true).listen(...);
+ *
+ * See also:
+ *
+ * * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
+ * from MDN.
+ */
+ ElementStream<T> _forElementList(ElementList<Element> e,
+ {bool useCapture: false}) {
+ return new _ElementListEventStreamImpl<T>(e, _eventType, useCapture);
+ }
+
+ /**
+ * Gets the type of the event which this would listen for on the specified
+ * event target.
+ *
+ * The target is necessary because some browsers may use different event names
+ * for the same purpose and the target allows differentiating browser support.
+ */
+ String getEventType(EventTarget target) {
+ return _eventType;
+ }
+}
+
+/** A specialized Stream available to [Element]s to enable event delegation. */
+abstract class ElementStream<T extends Event> implements Stream<T> {
+ /**
+ * Return a stream that only fires when the particular event fires for
+ * elements matching the specified CSS selector.
+ *
+ * This is the Dart equivalent to jQuery's
+ * [delegate](http://api.jquery.com/delegate/).
+ */
+ Stream<T> matches(String selector);
+
+ /**
+ * Adds a capturing subscription to this stream.
+ *
+ * If the target of the event is a descendant of the element from which this
+ * stream derives then [onData] is called before the event propagates down to
+ * the target. This is the opposite of bubbling behavior, where the event
+ * is first processed for the event target and then bubbles upward.
+ *
+ * ## Other resources
+ *
+ * * [Event Capture](http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture)
+ * from the W3C DOM Events specification.
+ */
+ StreamSubscription<T> capture(void onData(T event));
+}
+
+/**
+ * Adapter for exposing DOM events as Dart streams.
+ */
+class _EventStream<T extends Event> extends Stream<T> {
+ final EventTarget _target;
+ final String _eventType;
+ final bool _useCapture;
+
+ _EventStream(this._target, this._eventType, this._useCapture);
+
+ // DOM events are inherently multi-subscribers.
+ Stream<T> asBroadcastStream(
+ {void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)}) =>
+ this;
+ bool get isBroadcast => true;
+
+ // TODO(9757): Inlining should be smart and inline only when inlining would
+ // enable scalar replacement of an immediately allocated receiver.
+ @pragma('dart2js:tryInline')
+ StreamSubscription<T> listen(void onData(T event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ return new _EventStreamSubscription<T>(
+ this._target, this._eventType, onData, this._useCapture);
+ }
+}
+
+bool _matchesWithAncestors(Event event, String selector) {
+ var target = event.target;
+ return target is Element ? target.matchesWithAncestors(selector) : false;
+}
+
+/**
+ * Adapter for exposing DOM Element events as streams, while also allowing
+ * event delegation.
+ */
+class _ElementEventStreamImpl<T extends Event> extends _EventStream<T>
+ implements ElementStream<T> {
+ _ElementEventStreamImpl(target, eventType, useCapture)
+ : super(target, eventType, useCapture);
+
+ Stream<T> matches(String selector) =>
+ this.where((event) => _matchesWithAncestors(event, selector)).map((e) {
+ e._selector = selector;
+ return e;
+ });
+
+ StreamSubscription<T> capture(void onData(T event)) =>
+ new _EventStreamSubscription<T>(
+ this._target, this._eventType, onData, true);
+}
+
+/**
+ * Adapter for exposing events on a collection of DOM Elements as streams,
+ * while also allowing event delegation.
+ */
+class _ElementListEventStreamImpl<T extends Event> extends Stream<T>
+ implements ElementStream<T> {
+ final Iterable<Element> _targetList;
+ final bool _useCapture;
+ final String _eventType;
+
+ _ElementListEventStreamImpl(
+ this._targetList, this._eventType, this._useCapture);
+
+ Stream<T> matches(String selector) =>
+ this.where((event) => _matchesWithAncestors(event, selector)).map((e) {
+ e._selector = selector;
+ return e;
+ });
+
+ // Delegate all regular Stream behavior to a wrapped Stream.
+ StreamSubscription<T> listen(void onData(T event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ var pool = new _StreamPool<T>.broadcast();
+ for (var target in _targetList) {
+ pool.add(new _EventStream<T>(target, _eventType, _useCapture));
+ }
+ return pool.stream.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ StreamSubscription<T> capture(void onData(T event)) {
+ var pool = new _StreamPool<T>.broadcast();
+ for (var target in _targetList) {
+ pool.add(new _EventStream<T>(target, _eventType, true));
+ }
+ return pool.stream.listen(onData);
+ }
+
+ Stream<T> asBroadcastStream(
+ {void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)}) =>
+ this;
+ bool get isBroadcast => true;
+}
+
+// We would like this to just be EventListener<T> but that typdef cannot
+// use generics until dartbug/26276 is fixed.
+typedef _EventListener<T extends Event>(T event);
+
+class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
+ int _pauseCount = 0;
+ EventTarget _target;
+ final String _eventType;
+ EventListener _onData;
+ final bool _useCapture;
+
+ // TODO(leafp): It would be better to write this as
+ // _onData = onData == null ? null :
+ // onData is void Function(Event)
+ // ? _wrapZone<Event>(onData)
+ // : _wrapZone<Event>((e) => onData(e as T))
+ // In order to support existing tests which pass the wrong type of events but
+ // use a more general listener, without causing as much slowdown for things
+ // which are typed correctly. But this currently runs afoul of restrictions
+ // on is checks for compatibility with the VM.
+ _EventStreamSubscription(
+ this._target, this._eventType, void onData(T event), this._useCapture)
+ : _onData = onData == null
+ ? null
+ : _wrapZone<Event>((e) => (onData as dynamic)(e)) {
+ _tryResume();
+ }
+
+ Future cancel() {
+ if (_canceled) return null;
+
+ _unlisten();
+ // Clear out the target to indicate this is complete.
+ _target = null;
+ _onData = null;
+ return null;
+ }
+
+ bool get _canceled => _target == null;
+
+ void onData(void handleData(T event)) {
+ if (_canceled) {
+ throw new StateError("Subscription has been canceled.");
+ }
+ // Remove current event listener.
+ _unlisten();
+ _onData = _wrapZone<Event>(handleData);
+ _tryResume();
+ }
+
+ /// Has no effect.
+ void onError(Function handleError) {}
+
+ /// Has no effect.
+ void onDone(void handleDone()) {}
+
+ void pause([Future resumeSignal]) {
+ if (_canceled) return;
+ ++_pauseCount;
+ _unlisten();
+
+ if (resumeSignal != null) {
+ resumeSignal.whenComplete(resume);
+ }
+ }
+
+ bool get isPaused => _pauseCount > 0;
+
+ void resume() {
+ if (_canceled || !isPaused) return;
+ --_pauseCount;
+ _tryResume();
+ }
+
+ void _tryResume() {
+ if (_onData != null && !isPaused) {
+ _target.addEventListener(_eventType, _onData, _useCapture);
+ }
+ }
+
+ void _unlisten() {
+ if (_onData != null) {
+ _target.removeEventListener(_eventType, _onData, _useCapture);
+ }
+ }
+
+ Future<E> asFuture<E>([E futureValue]) {
+ // We just need a future that will never succeed or fail.
+ var completer = new Completer<E>();
+ return completer.future;
+ }
+}
+
+/**
+ * A stream of custom events, which enables the user to "fire" (add) their own
+ * custom events to a stream.
+ */
+abstract class CustomStream<T extends Event> implements Stream<T> {
+ /**
+ * Add the following custom event to the stream for dispatching to interested
+ * listeners.
+ */
+ void add(T event);
+}
+
+class _CustomEventStreamImpl<T extends Event> extends Stream<T>
+ implements CustomStream<T> {
+ StreamController<T> _streamController;
+ /** The type of event this stream is providing (e.g. "keydown"). */
+ String _type;
+
+ _CustomEventStreamImpl(String type) {
+ _type = type;
+ _streamController = new StreamController.broadcast(sync: true);
+ }
+
+ // Delegate all regular Stream behavior to our wrapped Stream.
+ StreamSubscription<T> listen(void onData(T event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ return _streamController.stream.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ Stream<T> asBroadcastStream(
+ {void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)}) =>
+ _streamController.stream;
+
+ bool get isBroadcast => true;
+
+ void add(T event) {
+ if (event.type == _type) _streamController.add(event);
+ }
+}
+
+class _CustomKeyEventStreamImpl extends _CustomEventStreamImpl<KeyEvent>
+ implements CustomStream<KeyEvent> {
+ _CustomKeyEventStreamImpl(String type) : super(type);
+
+ void add(KeyEvent event) {
+ if (event.type == _type) {
+ event.currentTarget.dispatchEvent(event._parent);
+ _streamController.add(event);
+ }
+ }
+}
+
+/**
+ * A pool of streams whose events are unified and emitted through a central
+ * stream.
+ */
+// TODO (efortuna): Remove this when Issue 12218 is addressed.
+class _StreamPool<T> {
+ StreamController<T> _controller;
+
+ /// Subscriptions to the streams that make up the pool.
+ var _subscriptions = new Map<Stream<T>, StreamSubscription<T>>();
+
+ /**
+ * Creates a new stream pool where [stream] can be listened to more than
+ * once.
+ *
+ * Any events from buffered streams in the pool will be emitted immediately,
+ * regardless of whether [stream] has any subscribers.
+ */
+ _StreamPool.broadcast() {
+ _controller =
+ new StreamController<T>.broadcast(sync: true, onCancel: close);
+ }
+
+ /**
+ * The stream through which all events from streams in the pool are emitted.
+ */
+ Stream<T> get stream => _controller.stream;
+
+ /**
+ * Adds [stream] as a member of this pool.
+ *
+ * Any events from [stream] will be emitted through [this.stream]. If
+ * [stream] is sync, they'll be emitted synchronously; if [stream] is async,
+ * they'll be emitted asynchronously.
+ */
+ void add(Stream<T> stream) {
+ if (_subscriptions.containsKey(stream)) return;
+ _subscriptions[stream] = stream.listen(_controller.add,
+ onError: _controller.addError, onDone: () => remove(stream));
+ }
+
+ /** Removes [stream] as a member of this pool. */
+ void remove(Stream<T> stream) {
+ var subscription = _subscriptions.remove(stream);
+ if (subscription != null) subscription.cancel();
+ }
+
+ /** Removes all streams from this pool and closes [stream]. */
+ void close() {
+ for (var subscription in _subscriptions.values) {
+ subscription.cancel();
+ }
+ _subscriptions.clear();
+ _controller.close();
+ }
+}
+
+/**
+ * A factory to expose DOM events as streams, where the DOM event name has to
+ * be determined on the fly (for example, mouse wheel events).
+ */
+class _CustomEventStreamProvider<T extends Event>
+ implements EventStreamProvider<T> {
+ final _eventTypeGetter;
+ const _CustomEventStreamProvider(this._eventTypeGetter);
+
+ Stream<T> forTarget(EventTarget e, {bool useCapture: false}) {
+ return new _EventStream<T>(e, _eventTypeGetter(e), useCapture);
+ }
+
+ ElementStream<T> forElement(Element e, {bool useCapture: false}) {
+ return new _ElementEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture);
+ }
+
+ ElementStream<T> _forElementList(ElementList<Element> e,
+ {bool useCapture: false}) {
+ return new _ElementListEventStreamImpl<T>(
+ e, _eventTypeGetter(e), useCapture);
+ }
+
+ String getEventType(EventTarget target) {
+ return _eventTypeGetter(target);
+ }
+
+ String get _eventType =>
+ throw new UnsupportedError('Access type through getEventType method.');
+}
+// DO NOT EDIT- this file is generated from running tool/generator.sh.
+
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A Dart DOM validator generated from Caja whitelists.
+ *
+ * This contains a whitelist of known HTML tagNames and attributes and will only
+ * accept known good values.
+ *
+ * See also:
+ *
+ * * <https://code.google.com/p/google-caja/wiki/CajaWhitelists>
+ */
+class _Html5NodeValidator implements NodeValidator {
+ static final Set<String> _allowedElements = new Set.from([
+ 'A',
+ 'ABBR',
+ 'ACRONYM',
+ 'ADDRESS',
+ 'AREA',
+ 'ARTICLE',
+ 'ASIDE',
+ 'AUDIO',
+ 'B',
+ 'BDI',
+ 'BDO',
+ 'BIG',
+ 'BLOCKQUOTE',
+ 'BR',
+ 'BUTTON',
+ 'CANVAS',
+ 'CAPTION',
+ 'CENTER',
+ 'CITE',
+ 'CODE',
+ 'COL',
+ 'COLGROUP',
+ 'COMMAND',
+ 'DATA',
+ 'DATALIST',
+ 'DD',
+ 'DEL',
+ 'DETAILS',
+ 'DFN',
+ 'DIR',
+ 'DIV',
+ 'DL',
+ 'DT',
+ 'EM',
+ 'FIELDSET',
+ 'FIGCAPTION',
+ 'FIGURE',
+ 'FONT',
+ 'FOOTER',
+ 'FORM',
+ 'H1',
+ 'H2',
+ 'H3',
+ 'H4',
+ 'H5',
+ 'H6',
+ 'HEADER',
+ 'HGROUP',
+ 'HR',
+ 'I',
+ 'IFRAME',
+ 'IMG',
+ 'INPUT',
+ 'INS',
+ 'KBD',
+ 'LABEL',
+ 'LEGEND',
+ 'LI',
+ 'MAP',
+ 'MARK',
+ 'MENU',
+ 'METER',
+ 'NAV',
+ 'NOBR',
+ 'OL',
+ 'OPTGROUP',
+ 'OPTION',
+ 'OUTPUT',
+ 'P',
+ 'PRE',
+ 'PROGRESS',
+ 'Q',
+ 'S',
+ 'SAMP',
+ 'SECTION',
+ 'SELECT',
+ 'SMALL',
+ 'SOURCE',
+ 'SPAN',
+ 'STRIKE',
+ 'STRONG',
+ 'SUB',
+ 'SUMMARY',
+ 'SUP',
+ 'TABLE',
+ 'TBODY',
+ 'TD',
+ 'TEXTAREA',
+ 'TFOOT',
+ 'TH',
+ 'THEAD',
+ 'TIME',
+ 'TR',
+ 'TRACK',
+ 'TT',
+ 'U',
+ 'UL',
+ 'VAR',
+ 'VIDEO',
+ 'WBR',
+ ]);
+
+ static const _standardAttributes = const <String>[
+ '*::class',
+ '*::dir',
+ '*::draggable',
+ '*::hidden',
+ '*::id',
+ '*::inert',
+ '*::itemprop',
+ '*::itemref',
+ '*::itemscope',
+ '*::lang',
+ '*::spellcheck',
+ '*::title',
+ '*::translate',
+ 'A::accesskey',
+ 'A::coords',
+ 'A::hreflang',
+ 'A::name',
+ 'A::shape',
+ 'A::tabindex',
+ 'A::target',
+ 'A::type',
+ 'AREA::accesskey',
+ 'AREA::alt',
+ 'AREA::coords',
+ 'AREA::nohref',
+ 'AREA::shape',
+ 'AREA::tabindex',
+ 'AREA::target',
+ 'AUDIO::controls',
+ 'AUDIO::loop',
+ 'AUDIO::mediagroup',
+ 'AUDIO::muted',
+ 'AUDIO::preload',
+ 'BDO::dir',
+ 'BODY::alink',
+ 'BODY::bgcolor',
+ 'BODY::link',
+ 'BODY::text',
+ 'BODY::vlink',
+ 'BR::clear',
+ 'BUTTON::accesskey',
+ 'BUTTON::disabled',
+ 'BUTTON::name',
+ 'BUTTON::tabindex',
+ 'BUTTON::type',
+ 'BUTTON::value',
+ 'CANVAS::height',
+ 'CANVAS::width',
+ 'CAPTION::align',
+ 'COL::align',
+ 'COL::char',
+ 'COL::charoff',
+ 'COL::span',
+ 'COL::valign',
+ 'COL::width',
+ 'COLGROUP::align',
+ 'COLGROUP::char',
+ 'COLGROUP::charoff',
+ 'COLGROUP::span',
+ 'COLGROUP::valign',
+ 'COLGROUP::width',
+ 'COMMAND::checked',
+ 'COMMAND::command',
+ 'COMMAND::disabled',
+ 'COMMAND::label',
+ 'COMMAND::radiogroup',
+ 'COMMAND::type',
+ 'DATA::value',
+ 'DEL::datetime',
+ 'DETAILS::open',
+ 'DIR::compact',
+ 'DIV::align',
+ 'DL::compact',
+ 'FIELDSET::disabled',
+ 'FONT::color',
+ 'FONT::face',
+ 'FONT::size',
+ 'FORM::accept',
+ 'FORM::autocomplete',
+ 'FORM::enctype',
+ 'FORM::method',
+ 'FORM::name',
+ 'FORM::novalidate',
+ 'FORM::target',
+ 'FRAME::name',
+ 'H1::align',
+ 'H2::align',
+ 'H3::align',
+ 'H4::align',
+ 'H5::align',
+ 'H6::align',
+ 'HR::align',
+ 'HR::noshade',
+ 'HR::size',
+ 'HR::width',
+ 'HTML::version',
+ 'IFRAME::align',
+ 'IFRAME::frameborder',
+ 'IFRAME::height',
+ 'IFRAME::marginheight',
+ 'IFRAME::marginwidth',
+ 'IFRAME::width',
+ 'IMG::align',
+ 'IMG::alt',
+ 'IMG::border',
+ 'IMG::height',
+ 'IMG::hspace',
+ 'IMG::ismap',
+ 'IMG::name',
+ 'IMG::usemap',
+ 'IMG::vspace',
+ 'IMG::width',
+ 'INPUT::accept',
+ 'INPUT::accesskey',
+ 'INPUT::align',
+ 'INPUT::alt',
+ 'INPUT::autocomplete',
+ 'INPUT::autofocus',
+ 'INPUT::checked',
+ 'INPUT::disabled',
+ 'INPUT::inputmode',
+ 'INPUT::ismap',
+ 'INPUT::list',
+ 'INPUT::max',
+ 'INPUT::maxlength',
+ 'INPUT::min',
+ 'INPUT::multiple',
+ 'INPUT::name',
+ 'INPUT::placeholder',
+ 'INPUT::readonly',
+ 'INPUT::required',
+ 'INPUT::size',
+ 'INPUT::step',
+ 'INPUT::tabindex',
+ 'INPUT::type',
+ 'INPUT::usemap',
+ 'INPUT::value',
+ 'INS::datetime',
+ 'KEYGEN::disabled',
+ 'KEYGEN::keytype',
+ 'KEYGEN::name',
+ 'LABEL::accesskey',
+ 'LABEL::for',
+ 'LEGEND::accesskey',
+ 'LEGEND::align',
+ 'LI::type',
+ 'LI::value',
+ 'LINK::sizes',
+ 'MAP::name',
+ 'MENU::compact',
+ 'MENU::label',
+ 'MENU::type',
+ 'METER::high',
+ 'METER::low',
+ 'METER::max',
+ 'METER::min',
+ 'METER::value',
+ 'OBJECT::typemustmatch',
+ 'OL::compact',
+ 'OL::reversed',
+ 'OL::start',
+ 'OL::type',
+ 'OPTGROUP::disabled',
+ 'OPTGROUP::label',
+ 'OPTION::disabled',
+ 'OPTION::label',
+ 'OPTION::selected',
+ 'OPTION::value',
+ 'OUTPUT::for',
+ 'OUTPUT::name',
+ 'P::align',
+ 'PRE::width',
+ 'PROGRESS::max',
+ 'PROGRESS::min',
+ 'PROGRESS::value',
+ 'SELECT::autocomplete',
+ 'SELECT::disabled',
+ 'SELECT::multiple',
+ 'SELECT::name',
+ 'SELECT::required',
+ 'SELECT::size',
+ 'SELECT::tabindex',
+ 'SOURCE::type',
+ 'TABLE::align',
+ 'TABLE::bgcolor',
+ 'TABLE::border',
+ 'TABLE::cellpadding',
+ 'TABLE::cellspacing',
+ 'TABLE::frame',
+ 'TABLE::rules',
+ 'TABLE::summary',
+ 'TABLE::width',
+ 'TBODY::align',
+ 'TBODY::char',
+ 'TBODY::charoff',
+ 'TBODY::valign',
+ 'TD::abbr',
+ 'TD::align',
+ 'TD::axis',
+ 'TD::bgcolor',
+ 'TD::char',
+ 'TD::charoff',
+ 'TD::colspan',
+ 'TD::headers',
+ 'TD::height',
+ 'TD::nowrap',
+ 'TD::rowspan',
+ 'TD::scope',
+ 'TD::valign',
+ 'TD::width',
+ 'TEXTAREA::accesskey',
+ 'TEXTAREA::autocomplete',
+ 'TEXTAREA::cols',
+ 'TEXTAREA::disabled',
+ 'TEXTAREA::inputmode',
+ 'TEXTAREA::name',
+ 'TEXTAREA::placeholder',
+ 'TEXTAREA::readonly',
+ 'TEXTAREA::required',
+ 'TEXTAREA::rows',
+ 'TEXTAREA::tabindex',
+ 'TEXTAREA::wrap',
+ 'TFOOT::align',
+ 'TFOOT::char',
+ 'TFOOT::charoff',
+ 'TFOOT::valign',
+ 'TH::abbr',
+ 'TH::align',
+ 'TH::axis',
+ 'TH::bgcolor',
+ 'TH::char',
+ 'TH::charoff',
+ 'TH::colspan',
+ 'TH::headers',
+ 'TH::height',
+ 'TH::nowrap',
+ 'TH::rowspan',
+ 'TH::scope',
+ 'TH::valign',
+ 'TH::width',
+ 'THEAD::align',
+ 'THEAD::char',
+ 'THEAD::charoff',
+ 'THEAD::valign',
+ 'TR::align',
+ 'TR::bgcolor',
+ 'TR::char',
+ 'TR::charoff',
+ 'TR::valign',
+ 'TRACK::default',
+ 'TRACK::kind',
+ 'TRACK::label',
+ 'TRACK::srclang',
+ 'UL::compact',
+ 'UL::type',
+ 'VIDEO::controls',
+ 'VIDEO::height',
+ 'VIDEO::loop',
+ 'VIDEO::mediagroup',
+ 'VIDEO::muted',
+ 'VIDEO::preload',
+ 'VIDEO::width',
+ ];
+
+ static const _uriAttributes = const <String>[
+ 'A::href',
+ 'AREA::href',
+ 'BLOCKQUOTE::cite',
+ 'BODY::background',
+ 'COMMAND::icon',
+ 'DEL::cite',
+ 'FORM::action',
+ 'IMG::src',
+ 'INPUT::src',
+ 'INS::cite',
+ 'Q::cite',
+ 'VIDEO::poster',
+ ];
+
+ final UriPolicy uriPolicy;
+
+ static final Map<String, Function> _attributeValidators = {};
+
+ /**
+ * All known URI attributes will be validated against the UriPolicy, if
+ * [uriPolicy] is null then a default UriPolicy will be used.
+ */
+ _Html5NodeValidator({UriPolicy uriPolicy})
+ : uriPolicy = uriPolicy != null ? uriPolicy : new UriPolicy() {
+ if (_attributeValidators.isEmpty) {
+ for (var attr in _standardAttributes) {
+ _attributeValidators[attr] = _standardAttributeValidator;
+ }
+
+ for (var attr in _uriAttributes) {
+ _attributeValidators[attr] = _uriAttributeValidator;
+ }
+ }
+ }
+
+ bool allowsElement(Element element) {
+ return _allowedElements.contains(Element._safeTagName(element));
+ }
+
+ bool allowsAttribute(Element element, String attributeName, String value) {
+ var tagName = Element._safeTagName(element);
+ var validator = _attributeValidators['$tagName::$attributeName'];
+ if (validator == null) {
+ validator = _attributeValidators['*::$attributeName'];
+ }
+ if (validator == null) {
+ return false;
+ }
+ return validator(element, attributeName, value, this);
+ }
+
+ static bool _standardAttributeValidator(Element element, String attributeName,
+ String value, _Html5NodeValidator context) {
+ return true;
+ }
+
+ static bool _uriAttributeValidator(Element element, String attributeName,
+ String value, _Html5NodeValidator context) {
+ return context.uriPolicy.allowsUri(value);
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class ImmutableListMixin<E> implements List<E> {
+ // From Iterable<$E>:
+ Iterator<E> get iterator {
+ // Note: NodeLists are not fixed size. And most probably length shouldn't
+ // be cached in both iterator _and_ forEach method. For now caching it
+ // for consistency.
+ return new FixedSizeListIterator<E>(this);
+ }
+
+ // From List<E>:
+ void add(E value) {
+ throw new UnsupportedError("Cannot add to immutable List.");
+ }
+
+ void addAll(Iterable<E> iterable) {
+ throw new UnsupportedError("Cannot add to immutable List.");
+ }
+
+ void sort([int compare(E a, E b)]) {
+ throw new UnsupportedError("Cannot sort immutable List.");
+ }
+
+ void shuffle([Random random]) {
+ throw new UnsupportedError("Cannot shuffle immutable List.");
+ }
+
+ void insert(int index, E element) {
+ throw new UnsupportedError("Cannot add to immutable List.");
+ }
+
+ void insertAll(int index, Iterable<E> iterable) {
+ throw new UnsupportedError("Cannot add to immutable List.");
+ }
+
+ void setAll(int index, Iterable<E> iterable) {
+ throw new UnsupportedError("Cannot modify an immutable List.");
+ }
+
+ E removeAt(int pos) {
+ throw new UnsupportedError("Cannot remove from immutable List.");
+ }
+
+ E removeLast() {
+ throw new UnsupportedError("Cannot remove from immutable List.");
+ }
+
+ bool remove(Object object) {
+ throw new UnsupportedError("Cannot remove from immutable List.");
+ }
+
+ void removeWhere(bool test(E element)) {
+ throw new UnsupportedError("Cannot remove from immutable List.");
+ }
+
+ void retainWhere(bool test(E element)) {
+ throw new UnsupportedError("Cannot remove from immutable List.");
+ }
+
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+ throw new UnsupportedError("Cannot setRange on immutable List.");
+ }
+
+ void removeRange(int start, int end) {
+ throw new UnsupportedError("Cannot removeRange on immutable List.");
+ }
+
+ void replaceRange(int start, int end, Iterable<E> iterable) {
+ throw new UnsupportedError("Cannot modify an immutable List.");
+ }
+
+ void fillRange(int start, int end, [E fillValue]) {
+ throw new UnsupportedError("Cannot modify an immutable List.");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Defines the keycode values for keys that are returned by
+ * KeyboardEvent.keyCode.
+ *
+ * Important note: There is substantial divergence in how different browsers
+ * handle keycodes and their variants in different locales/keyboard layouts. We
+ * provide these constants to help make code processing keys more readable.
+ */
+abstract class KeyCode {
+ // These constant names were borrowed from Closure's Keycode enumeration
+ // class.
+ // https://github.com/google/closure-library/blob/master/closure/goog/events/keycodes.js
+ static const int WIN_KEY_FF_LINUX = 0;
+ static const int MAC_ENTER = 3;
+ static const int BACKSPACE = 8;
+ static const int TAB = 9;
+ /** NUM_CENTER is also NUMLOCK for FF and Safari on Mac. */
+ static const int NUM_CENTER = 12;
+ static const int ENTER = 13;
+ static const int SHIFT = 16;
+ static const int CTRL = 17;
+ static const int ALT = 18;
+ static const int PAUSE = 19;
+ static const int CAPS_LOCK = 20;
+ static const int ESC = 27;
+ static const int SPACE = 32;
+ static const int PAGE_UP = 33;
+ static const int PAGE_DOWN = 34;
+ static const int END = 35;
+ static const int HOME = 36;
+ static const int LEFT = 37;
+ static const int UP = 38;
+ static const int RIGHT = 39;
+ static const int DOWN = 40;
+ static const int NUM_NORTH_EAST = 33;
+ static const int NUM_SOUTH_EAST = 34;
+ static const int NUM_SOUTH_WEST = 35;
+ static const int NUM_NORTH_WEST = 36;
+ static const int NUM_WEST = 37;
+ static const int NUM_NORTH = 38;
+ static const int NUM_EAST = 39;
+ static const int NUM_SOUTH = 40;
+ static const int PRINT_SCREEN = 44;
+ static const int INSERT = 45;
+ static const int NUM_INSERT = 45;
+ static const int DELETE = 46;
+ static const int NUM_DELETE = 46;
+ static const int ZERO = 48;
+ static const int ONE = 49;
+ static const int TWO = 50;
+ static const int THREE = 51;
+ static const int FOUR = 52;
+ static const int FIVE = 53;
+ static const int SIX = 54;
+ static const int SEVEN = 55;
+ static const int EIGHT = 56;
+ static const int NINE = 57;
+ static const int FF_SEMICOLON = 59;
+ static const int FF_EQUALS = 61;
+ /**
+ * CAUTION: The question mark is for US-keyboard layouts. It varies
+ * for other locales and keyboard layouts.
+ */
+ static const int QUESTION_MARK = 63;
+ static const int A = 65;
+ static const int B = 66;
+ static const int C = 67;
+ static const int D = 68;
+ static const int E = 69;
+ static const int F = 70;
+ static const int G = 71;
+ static const int H = 72;
+ static const int I = 73;
+ static const int J = 74;
+ static const int K = 75;
+ static const int L = 76;
+ static const int M = 77;
+ static const int N = 78;
+ static const int O = 79;
+ static const int P = 80;
+ static const int Q = 81;
+ static const int R = 82;
+ static const int S = 83;
+ static const int T = 84;
+ static const int U = 85;
+ static const int V = 86;
+ static const int W = 87;
+ static const int X = 88;
+ static const int Y = 89;
+ static const int Z = 90;
+ static const int META = 91;
+ static const int WIN_KEY_LEFT = 91;
+ static const int WIN_KEY_RIGHT = 92;
+ static const int CONTEXT_MENU = 93;
+ static const int NUM_ZERO = 96;
+ static const int NUM_ONE = 97;
+ static const int NUM_TWO = 98;
+ static const int NUM_THREE = 99;
+ static const int NUM_FOUR = 100;
+ static const int NUM_FIVE = 101;
+ static const int NUM_SIX = 102;
+ static const int NUM_SEVEN = 103;
+ static const int NUM_EIGHT = 104;
+ static const int NUM_NINE = 105;
+ static const int NUM_MULTIPLY = 106;
+ static const int NUM_PLUS = 107;
+ static const int NUM_MINUS = 109;
+ static const int NUM_PERIOD = 110;
+ static const int NUM_DIVISION = 111;
+ static const int F1 = 112;
+ static const int F2 = 113;
+ static const int F3 = 114;
+ static const int F4 = 115;
+ static const int F5 = 116;
+ static const int F6 = 117;
+ static const int F7 = 118;
+ static const int F8 = 119;
+ static const int F9 = 120;
+ static const int F10 = 121;
+ static const int F11 = 122;
+ static const int F12 = 123;
+ static const int NUMLOCK = 144;
+ static const int SCROLL_LOCK = 145;
+
+ // OS-specific media keys like volume controls and browser controls.
+ static const int FIRST_MEDIA_KEY = 166;
+ static const int LAST_MEDIA_KEY = 183;
+
+ /**
+ * CAUTION: This constant requires localization for other locales and keyboard
+ * layouts.
+ */
+ static const int SEMICOLON = 186;
+ /**
+ * CAUTION: This constant requires localization for other locales and keyboard
+ * layouts.
+ */
+ static const int DASH = 189;
+ /**
+ * CAUTION: This constant requires localization for other locales and keyboard
+ * layouts.
+ */
+ static const int EQUALS = 187;
+ /**
+ * CAUTION: This constant requires localization for other locales and keyboard
+ * layouts.
+ */
+ static const int COMMA = 188;
+ /**
+ * CAUTION: This constant requires localization for other locales and keyboard
+ * layouts.
+ */
+ static const int PERIOD = 190;
+ /**
+ * CAUTION: This constant requires localization for other locales and keyboard
+ * layouts.
+ */
+ static const int SLASH = 191;
+ /**
+ * CAUTION: This constant requires localization for other locales and keyboard
+ * layouts.
+ */
+ static const int APOSTROPHE = 192;
+ /**
+ * CAUTION: This constant requires localization for other locales and keyboard
+ * layouts.
+ */
+ static const int TILDE = 192;
+ /**
+ * CAUTION: This constant requires localization for other locales and keyboard
+ * layouts.
+ */
+ static const int SINGLE_QUOTE = 222;
+ /**
+ * CAUTION: This constant requires localization for other locales and keyboard
+ * layouts.
+ */
+ static const int OPEN_SQUARE_BRACKET = 219;
+ /**
+ * CAUTION: This constant requires localization for other locales and keyboard
+ * layouts.
+ */
+ static const int BACKSLASH = 220;
+ /**
+ * CAUTION: This constant requires localization for other locales and keyboard
+ * layouts.
+ */
+ static const int CLOSE_SQUARE_BRACKET = 221;
+ static const int WIN_KEY = 224;
+ static const int MAC_FF_META = 224;
+ static const int WIN_IME = 229;
+
+ /** A sentinel value if the keycode could not be determined. */
+ static const int UNKNOWN = -1;
+
+ /**
+ * Returns true if the keyCode produces a (US keyboard) character.
+ * Note: This does not (yet) cover characters on non-US keyboards (Russian,
+ * Hebrew, etc.).
+ */
+ static bool isCharacterKey(int keyCode) {
+ if ((keyCode >= ZERO && keyCode <= NINE) ||
+ (keyCode >= NUM_ZERO && keyCode <= NUM_MULTIPLY) ||
+ (keyCode >= A && keyCode <= Z)) {
+ return true;
+ }
+
+ // Safari sends zero key code for non-latin characters.
+ if (Device.isWebKit && keyCode == 0) {
+ return true;
+ }
+
+ return (keyCode == SPACE ||
+ keyCode == QUESTION_MARK ||
+ keyCode == NUM_PLUS ||
+ keyCode == NUM_MINUS ||
+ keyCode == NUM_PERIOD ||
+ keyCode == NUM_DIVISION ||
+ keyCode == SEMICOLON ||
+ keyCode == FF_SEMICOLON ||
+ keyCode == DASH ||
+ keyCode == EQUALS ||
+ keyCode == FF_EQUALS ||
+ keyCode == COMMA ||
+ keyCode == PERIOD ||
+ keyCode == SLASH ||
+ keyCode == APOSTROPHE ||
+ keyCode == SINGLE_QUOTE ||
+ keyCode == OPEN_SQUARE_BRACKET ||
+ keyCode == BACKSLASH ||
+ keyCode == CLOSE_SQUARE_BRACKET);
+ }
+
+ /**
+ * Experimental helper function for converting keyCodes to keyNames for the
+ * keyIdentifier attribute still used in browsers not updated with current
+ * spec. This is an imperfect conversion! It will need to be refined, but
+ * hopefully it can just completely go away once all the browsers update to
+ * follow the DOM3 spec.
+ */
+ static String _convertKeyCodeToKeyName(int keyCode) {
+ switch (keyCode) {
+ case KeyCode.ALT:
+ return _KeyName.ALT;
+ case KeyCode.BACKSPACE:
+ return _KeyName.BACKSPACE;
+ case KeyCode.CAPS_LOCK:
+ return _KeyName.CAPS_LOCK;
+ case KeyCode.CTRL:
+ return _KeyName.CONTROL;
+ case KeyCode.DELETE:
+ return _KeyName.DEL;
+ case KeyCode.DOWN:
+ return _KeyName.DOWN;
+ case KeyCode.END:
+ return _KeyName.END;
+ case KeyCode.ENTER:
+ return _KeyName.ENTER;
+ case KeyCode.ESC:
+ return _KeyName.ESC;
+ case KeyCode.F1:
+ return _KeyName.F1;
+ case KeyCode.F2:
+ return _KeyName.F2;
+ case KeyCode.F3:
+ return _KeyName.F3;
+ case KeyCode.F4:
+ return _KeyName.F4;
+ case KeyCode.F5:
+ return _KeyName.F5;
+ case KeyCode.F6:
+ return _KeyName.F6;
+ case KeyCode.F7:
+ return _KeyName.F7;
+ case KeyCode.F8:
+ return _KeyName.F8;
+ case KeyCode.F9:
+ return _KeyName.F9;
+ case KeyCode.F10:
+ return _KeyName.F10;
+ case KeyCode.F11:
+ return _KeyName.F11;
+ case KeyCode.F12:
+ return _KeyName.F12;
+ case KeyCode.HOME:
+ return _KeyName.HOME;
+ case KeyCode.INSERT:
+ return _KeyName.INSERT;
+ case KeyCode.LEFT:
+ return _KeyName.LEFT;
+ case KeyCode.META:
+ return _KeyName.META;
+ case KeyCode.NUMLOCK:
+ return _KeyName.NUM_LOCK;
+ case KeyCode.PAGE_DOWN:
+ return _KeyName.PAGE_DOWN;
+ case KeyCode.PAGE_UP:
+ return _KeyName.PAGE_UP;
+ case KeyCode.PAUSE:
+ return _KeyName.PAUSE;
+ case KeyCode.PRINT_SCREEN:
+ return _KeyName.PRINT_SCREEN;
+ case KeyCode.RIGHT:
+ return _KeyName.RIGHT;
+ case KeyCode.SCROLL_LOCK:
+ return _KeyName.SCROLL;
+ case KeyCode.SHIFT:
+ return _KeyName.SHIFT;
+ case KeyCode.SPACE:
+ return _KeyName.SPACEBAR;
+ case KeyCode.TAB:
+ return _KeyName.TAB;
+ case KeyCode.UP:
+ return _KeyName.UP;
+ case KeyCode.WIN_IME:
+ case KeyCode.WIN_KEY:
+ case KeyCode.WIN_KEY_LEFT:
+ case KeyCode.WIN_KEY_RIGHT:
+ return _KeyName.WIN;
+ default:
+ return _KeyName.UNIDENTIFIED;
+ }
+ return _KeyName.UNIDENTIFIED;
+ }
+}
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Defines the standard key locations returned by
+ * KeyboardEvent.getKeyLocation.
+ */
+abstract class KeyLocation {
+ /**
+ * The event key is not distinguished as the left or right version
+ * of the key, and did not originate from the numeric keypad (or did not
+ * originate with a virtual key corresponding to the numeric keypad).
+ */
+ static const int STANDARD = 0;
+
+ /**
+ * The event key is in the left key location.
+ */
+ static const int LEFT = 1;
+
+ /**
+ * The event key is in the right key location.
+ */
+ static const int RIGHT = 2;
+
+ /**
+ * The event key originated on the numeric keypad or with a virtual key
+ * corresponding to the numeric keypad.
+ */
+ static const int NUMPAD = 3;
+
+ /**
+ * The event key originated on a mobile device, either on a physical
+ * keypad or a virtual keyboard.
+ */
+ static const int MOBILE = 4;
+
+ /**
+ * The event key originated on a game controller or a joystick on a mobile
+ * device.
+ */
+ static const int JOYSTICK = 5;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Defines the standard keyboard identifier names for keys that are returned
+ * by KeyboardEvent.getKeyboardIdentifier when the key does not have a direct
+ * unicode mapping.
+ */
+abstract class _KeyName {
+ /** The Accept (Commit, OK) key */
+ static const String ACCEPT = "Accept";
+
+ /** The Add key */
+ static const String ADD = "Add";
+
+ /** The Again key */
+ static const String AGAIN = "Again";
+
+ /** The All Candidates key */
+ static const String ALL_CANDIDATES = "AllCandidates";
+
+ /** The Alphanumeric key */
+ static const String ALPHANUMERIC = "Alphanumeric";
+
+ /** The Alt (Menu) key */
+ static const String ALT = "Alt";
+
+ /** The Alt-Graph key */
+ static const String ALT_GRAPH = "AltGraph";
+
+ /** The Application key */
+ static const String APPS = "Apps";
+
+ /** The ATTN key */
+ static const String ATTN = "Attn";
+
+ /** The Browser Back key */
+ static const String BROWSER_BACK = "BrowserBack";
+
+ /** The Browser Favorites key */
+ static const String BROWSER_FAVORTIES = "BrowserFavorites";
+
+ /** The Browser Forward key */
+ static const String BROWSER_FORWARD = "BrowserForward";
+
+ /** The Browser Home key */
+ static const String BROWSER_NAME = "BrowserHome";
+
+ /** The Browser Refresh key */
+ static const String BROWSER_REFRESH = "BrowserRefresh";
+
+ /** The Browser Search key */
+ static const String BROWSER_SEARCH = "BrowserSearch";
+
+ /** The Browser Stop key */
+ static const String BROWSER_STOP = "BrowserStop";
+
+ /** The Camera key */
+ static const String CAMERA = "Camera";
+
+ /** The Caps Lock (Capital) key */
+ static const String CAPS_LOCK = "CapsLock";
+
+ /** The Clear key */
+ static const String CLEAR = "Clear";
+
+ /** The Code Input key */
+ static const String CODE_INPUT = "CodeInput";
+
+ /** The Compose key */
+ static const String COMPOSE = "Compose";
+
+ /** The Control (Ctrl) key */
+ static const String CONTROL = "Control";
+
+ /** The Crsel key */
+ static const String CRSEL = "Crsel";
+
+ /** The Convert key */
+ static const String CONVERT = "Convert";
+
+ /** The Copy key */
+ static const String COPY = "Copy";
+
+ /** The Cut key */
+ static const String CUT = "Cut";
+
+ /** The Decimal key */
+ static const String DECIMAL = "Decimal";
+
+ /** The Divide key */
+ static const String DIVIDE = "Divide";
+
+ /** The Down Arrow key */
+ static const String DOWN = "Down";
+
+ /** The diagonal Down-Left Arrow key */
+ static const String DOWN_LEFT = "DownLeft";
+
+ /** The diagonal Down-Right Arrow key */
+ static const String DOWN_RIGHT = "DownRight";
+
+ /** The Eject key */
+ static const String EJECT = "Eject";
+
+ /** The End key */
+ static const String END = "End";
+
+ /**
+ * The Enter key. Note: This key value must also be used for the Return
+ * (Macintosh numpad) key
+ */
+ static const String ENTER = "Enter";
+
+ /** The Erase EOF key */
+ static const String ERASE_EOF = "EraseEof";
+
+ /** The Execute key */
+ static const String EXECUTE = "Execute";
+
+ /** The Exsel key */
+ static const String EXSEL = "Exsel";
+
+ /** The Function switch key */
+ static const String FN = "Fn";
+
+ /** The F1 key */
+ static const String F1 = "F1";
+
+ /** The F2 key */
+ static const String F2 = "F2";
+
+ /** The F3 key */
+ static const String F3 = "F3";
+
+ /** The F4 key */
+ static const String F4 = "F4";
+
+ /** The F5 key */
+ static const String F5 = "F5";
+
+ /** The F6 key */
+ static const String F6 = "F6";
+
+ /** The F7 key */
+ static const String F7 = "F7";
+
+ /** The F8 key */
+ static const String F8 = "F8";
+
+ /** The F9 key */
+ static const String F9 = "F9";
+
+ /** The F10 key */
+ static const String F10 = "F10";
+
+ /** The F11 key */
+ static const String F11 = "F11";
+
+ /** The F12 key */
+ static const String F12 = "F12";
+
+ /** The F13 key */
+ static const String F13 = "F13";
+
+ /** The F14 key */
+ static const String F14 = "F14";
+
+ /** The F15 key */
+ static const String F15 = "F15";
+
+ /** The F16 key */
+ static const String F16 = "F16";
+
+ /** The F17 key */
+ static const String F17 = "F17";
+
+ /** The F18 key */
+ static const String F18 = "F18";
+
+ /** The F19 key */
+ static const String F19 = "F19";
+
+ /** The F20 key */
+ static const String F20 = "F20";
+
+ /** The F21 key */
+ static const String F21 = "F21";
+
+ /** The F22 key */
+ static const String F22 = "F22";
+
+ /** The F23 key */
+ static const String F23 = "F23";
+
+ /** The F24 key */
+ static const String F24 = "F24";
+
+ /** The Final Mode (Final) key used on some asian keyboards */
+ static const String FINAL_MODE = "FinalMode";
+
+ /** The Find key */
+ static const String FIND = "Find";
+
+ /** The Full-Width Characters key */
+ static const String FULL_WIDTH = "FullWidth";
+
+ /** The Half-Width Characters key */
+ static const String HALF_WIDTH = "HalfWidth";
+
+ /** The Hangul (Korean characters) Mode key */
+ static const String HANGUL_MODE = "HangulMode";
+
+ /** The Hanja (Korean characters) Mode key */
+ static const String HANJA_MODE = "HanjaMode";
+
+ /** The Help key */
+ static const String HELP = "Help";
+
+ /** The Hiragana (Japanese Kana characters) key */
+ static const String HIRAGANA = "Hiragana";
+
+ /** The Home key */
+ static const String HOME = "Home";
+
+ /** The Insert (Ins) key */
+ static const String INSERT = "Insert";
+
+ /** The Japanese-Hiragana key */
+ static const String JAPANESE_HIRAGANA = "JapaneseHiragana";
+
+ /** The Japanese-Katakana key */
+ static const String JAPANESE_KATAKANA = "JapaneseKatakana";
+
+ /** The Japanese-Romaji key */
+ static const String JAPANESE_ROMAJI = "JapaneseRomaji";
+
+ /** The Junja Mode key */
+ static const String JUNJA_MODE = "JunjaMode";
+
+ /** The Kana Mode (Kana Lock) key */
+ static const String KANA_MODE = "KanaMode";
+
+ /**
+ * The Kanji (Japanese name for ideographic characters of Chinese origin)
+ * Mode key
+ */
+ static const String KANJI_MODE = "KanjiMode";
+
+ /** The Katakana (Japanese Kana characters) key */
+ static const String KATAKANA = "Katakana";
+
+ /** The Start Application One key */
+ static const String LAUNCH_APPLICATION_1 = "LaunchApplication1";
+
+ /** The Start Application Two key */
+ static const String LAUNCH_APPLICATION_2 = "LaunchApplication2";
+
+ /** The Start Mail key */
+ static const String LAUNCH_MAIL = "LaunchMail";
+
+ /** The Left Arrow key */
+ static const String LEFT = "Left";
+
+ /** The Menu key */
+ static const String MENU = "Menu";
+
+ /**
+ * The Meta key. Note: This key value shall be also used for the Apple
+ * Command key
+ */
+ static const String META = "Meta";
+
+ /** The Media Next Track key */
+ static const String MEDIA_NEXT_TRACK = "MediaNextTrack";
+
+ /** The Media Play Pause key */
+ static const String MEDIA_PAUSE_PLAY = "MediaPlayPause";
+
+ /** The Media Previous Track key */
+ static const String MEDIA_PREVIOUS_TRACK = "MediaPreviousTrack";
+
+ /** The Media Stop key */
+ static const String MEDIA_STOP = "MediaStop";
+
+ /** The Mode Change key */
+ static const String MODE_CHANGE = "ModeChange";
+
+ /** The Next Candidate function key */
+ static const String NEXT_CANDIDATE = "NextCandidate";
+
+ /** The Nonconvert (Don't Convert) key */
+ static const String NON_CONVERT = "Nonconvert";
+
+ /** The Number Lock key */
+ static const String NUM_LOCK = "NumLock";
+
+ /** The Page Down (Next) key */
+ static const String PAGE_DOWN = "PageDown";
+
+ /** The Page Up key */
+ static const String PAGE_UP = "PageUp";
+
+ /** The Paste key */
+ static const String PASTE = "Paste";
+
+ /** The Pause key */
+ static const String PAUSE = "Pause";
+
+ /** The Play key */
+ static const String PLAY = "Play";
+
+ /**
+ * The Power key. Note: Some devices may not expose this key to the
+ * operating environment
+ */
+ static const String POWER = "Power";
+
+ /** The Previous Candidate function key */
+ static const String PREVIOUS_CANDIDATE = "PreviousCandidate";
+
+ /** The Print Screen (PrintScrn, SnapShot) key */
+ static const String PRINT_SCREEN = "PrintScreen";
+
+ /** The Process key */
+ static const String PROCESS = "Process";
+
+ /** The Props key */
+ static const String PROPS = "Props";
+
+ /** The Right Arrow key */
+ static const String RIGHT = "Right";
+
+ /** The Roman Characters function key */
+ static const String ROMAN_CHARACTERS = "RomanCharacters";
+
+ /** The Scroll Lock key */
+ static const String SCROLL = "Scroll";
+
+ /** The Select key */
+ static const String SELECT = "Select";
+
+ /** The Select Media key */
+ static const String SELECT_MEDIA = "SelectMedia";
+
+ /** The Separator key */
+ static const String SEPARATOR = "Separator";
+
+ /** The Shift key */
+ static const String SHIFT = "Shift";
+
+ /** The Soft1 key */
+ static const String SOFT_1 = "Soft1";
+
+ /** The Soft2 key */
+ static const String SOFT_2 = "Soft2";
+
+ /** The Soft3 key */
+ static const String SOFT_3 = "Soft3";
+
+ /** The Soft4 key */
+ static const String SOFT_4 = "Soft4";
+
+ /** The Stop key */
+ static const String STOP = "Stop";
+
+ /** The Subtract key */
+ static const String SUBTRACT = "Subtract";
+
+ /** The Symbol Lock key */
+ static const String SYMBOL_LOCK = "SymbolLock";
+
+ /** The Up Arrow key */
+ static const String UP = "Up";
+
+ /** The diagonal Up-Left Arrow key */
+ static const String UP_LEFT = "UpLeft";
+
+ /** The diagonal Up-Right Arrow key */
+ static const String UP_RIGHT = "UpRight";
+
+ /** The Undo key */
+ static const String UNDO = "Undo";
+
+ /** The Volume Down key */
+ static const String VOLUME_DOWN = "VolumeDown";
+
+ /** The Volume Mute key */
+ static const String VOLUMN_MUTE = "VolumeMute";
+
+ /** The Volume Up key */
+ static const String VOLUMN_UP = "VolumeUp";
+
+ /** The Windows Logo key */
+ static const String WIN = "Win";
+
+ /** The Zoom key */
+ static const String ZOOM = "Zoom";
+
+ /**
+ * The Backspace (Back) key. Note: This key value shall be also used for the
+ * key labeled 'delete' MacOS keyboards when not modified by the 'Fn' key
+ */
+ static const String BACKSPACE = "Backspace";
+
+ /** The Horizontal Tabulation (Tab) key */
+ static const String TAB = "Tab";
+
+ /** The Cancel key */
+ static const String CANCEL = "Cancel";
+
+ /** The Escape (Esc) key */
+ static const String ESC = "Esc";
+
+ /** The Space (Spacebar) key: */
+ static const String SPACEBAR = "Spacebar";
+
+ /**
+ * The Delete (Del) Key. Note: This key value shall be also used for the key
+ * labeled 'delete' MacOS keyboards when modified by the 'Fn' key
+ */
+ static const String DEL = "Del";
+
+ /** The Combining Grave Accent (Greek Varia, Dead Grave) key */
+ static const String DEAD_GRAVE = "DeadGrave";
+
+ /**
+ * The Combining Acute Accent (Stress Mark, Greek Oxia, Tonos, Dead Eacute)
+ * key
+ */
+ static const String DEAD_EACUTE = "DeadEacute";
+
+ /** The Combining Circumflex Accent (Hat, Dead Circumflex) key */
+ static const String DEAD_CIRCUMFLEX = "DeadCircumflex";
+
+ /** The Combining Tilde (Dead Tilde) key */
+ static const String DEAD_TILDE = "DeadTilde";
+
+ /** The Combining Macron (Long, Dead Macron) key */
+ static const String DEAD_MACRON = "DeadMacron";
+
+ /** The Combining Breve (Short, Dead Breve) key */
+ static const String DEAD_BREVE = "DeadBreve";
+
+ /** The Combining Dot Above (Derivative, Dead Above Dot) key */
+ static const String DEAD_ABOVE_DOT = "DeadAboveDot";
+
+ /**
+ * The Combining Diaeresis (Double Dot Abode, Umlaut, Greek Dialytika,
+ * Double Derivative, Dead Diaeresis) key
+ */
+ static const String DEAD_UMLAUT = "DeadUmlaut";
+
+ /** The Combining Ring Above (Dead Above Ring) key */
+ static const String DEAD_ABOVE_RING = "DeadAboveRing";
+
+ /** The Combining Double Acute Accent (Dead Doubleacute) key */
+ static const String DEAD_DOUBLEACUTE = "DeadDoubleacute";
+
+ /** The Combining Caron (Hacek, V Above, Dead Caron) key */
+ static const String DEAD_CARON = "DeadCaron";
+
+ /** The Combining Cedilla (Dead Cedilla) key */
+ static const String DEAD_CEDILLA = "DeadCedilla";
+
+ /** The Combining Ogonek (Nasal Hook, Dead Ogonek) key */
+ static const String DEAD_OGONEK = "DeadOgonek";
+
+ /**
+ * The Combining Greek Ypogegrammeni (Greek Non-Spacing Iota Below, Iota
+ * Subscript, Dead Iota) key
+ */
+ static const String DEAD_IOTA = "DeadIota";
+
+ /**
+ * The Combining Katakana-Hiragana Voiced Sound Mark (Dead Voiced Sound) key
+ */
+ static const String DEAD_VOICED_SOUND = "DeadVoicedSound";
+
+ /**
+ * The Combining Katakana-Hiragana Semi-Voiced Sound Mark (Dead Semivoiced
+ * Sound) key
+ */
+ static const String DEC_SEMIVOICED_SOUND = "DeadSemivoicedSound";
+
+ /**
+ * Key value used when an implementation is unable to identify another key
+ * value, due to either hardware, platform, or software constraints
+ */
+ static const String UNIDENTIFIED = "Unidentified";
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Internal class that does the actual calculations to determine keyCode and
+ * charCode for keydown, keypress, and keyup events for all browsers.
+ */
+class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> {
+ // This code inspired by Closure's KeyHandling library.
+ // https://github.com/google/closure-library/blob/master/closure/goog/events/keyhandler.js
+
+ /**
+ * The set of keys that have been pressed down without seeing their
+ * corresponding keyup event.
+ */
+ final List<KeyEvent> _keyDownList = <KeyEvent>[];
+
+ /** The type of KeyEvent we are tracking (keyup, keydown, keypress). */
+ final String _type;
+
+ /** The element we are watching for events to happen on. */
+ final EventTarget _target;
+
+ // The distance to shift from upper case alphabet Roman letters to lower case.
+ static final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0];
+
+ /** Custom Stream (Controller) to produce KeyEvents for the stream. */
+ _CustomKeyEventStreamImpl _stream;
+
+ static const _EVENT_TYPE = 'KeyEvent';
+
+ /**
+ * An enumeration of key identifiers currently part of the W3C draft for DOM3
+ * and their mappings to keyCodes.
+ * https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/keyset.html#KeySet-Set
+ */
+ static const Map<String, int> _keyIdentifier = const {
+ 'Up': KeyCode.UP,
+ 'Down': KeyCode.DOWN,
+ 'Left': KeyCode.LEFT,
+ 'Right': KeyCode.RIGHT,
+ 'Enter': KeyCode.ENTER,
+ 'F1': KeyCode.F1,
+ 'F2': KeyCode.F2,
+ 'F3': KeyCode.F3,
+ 'F4': KeyCode.F4,
+ 'F5': KeyCode.F5,
+ 'F6': KeyCode.F6,
+ 'F7': KeyCode.F7,
+ 'F8': KeyCode.F8,
+ 'F9': KeyCode.F9,
+ 'F10': KeyCode.F10,
+ 'F11': KeyCode.F11,
+ 'F12': KeyCode.F12,
+ 'U+007F': KeyCode.DELETE,
+ 'Home': KeyCode.HOME,
+ 'End': KeyCode.END,
+ 'PageUp': KeyCode.PAGE_UP,
+ 'PageDown': KeyCode.PAGE_DOWN,
+ 'Insert': KeyCode.INSERT
+ };
+
+ /** Return a stream for KeyEvents for the specified target. */
+ // Note: this actually functions like a factory constructor.
+ CustomStream<KeyEvent> forTarget(EventTarget e, {bool useCapture: false}) {
+ var handler =
+ new _KeyboardEventHandler.initializeAllEventListeners(_type, e);
+ return handler._stream;
+ }
+
+ /**
+ * General constructor, performs basic initialization for our improved
+ * KeyboardEvent controller.
+ */
+ _KeyboardEventHandler(this._type)
+ : _stream = new _CustomKeyEventStreamImpl('event'),
+ _target = null,
+ super(_EVENT_TYPE);
+
+ /**
+ * Hook up all event listeners under the covers so we can estimate keycodes
+ * and charcodes when they are not provided.
+ */
+ _KeyboardEventHandler.initializeAllEventListeners(this._type, this._target)
+ : super(_EVENT_TYPE) {
+ Element.keyDownEvent
+ .forTarget(_target, useCapture: true)
+ .listen(processKeyDown);
+ Element.keyPressEvent
+ .forTarget(_target, useCapture: true)
+ .listen(processKeyPress);
+ Element.keyUpEvent
+ .forTarget(_target, useCapture: true)
+ .listen(processKeyUp);
+ _stream = new _CustomKeyEventStreamImpl(_type);
+ }
+
+ /** Determine if caps lock is one of the currently depressed keys. */
+ bool get _capsLockOn =>
+ _keyDownList.any((var element) => element.keyCode == KeyCode.CAPS_LOCK);
+
+ /**
+ * Given the previously recorded keydown key codes, see if we can determine
+ * the keycode of this keypress [event]. (Generally browsers only provide
+ * charCode information for keypress events, but with a little
+ * reverse-engineering, we can also determine the keyCode.) Returns
+ * KeyCode.UNKNOWN if the keycode could not be determined.
+ */
+ int _determineKeyCodeForKeypress(KeyboardEvent event) {
+ // Note: This function is a work in progress. We'll expand this function
+ // once we get more information about other keyboards.
+ for (var prevEvent in _keyDownList) {
+ if (prevEvent._shadowCharCode == event.charCode) {
+ return prevEvent.keyCode;
+ }
+ if ((event.shiftKey || _capsLockOn) &&
+ event.charCode >= "A".codeUnits[0] &&
+ event.charCode <= "Z".codeUnits[0] &&
+ event.charCode + _ROMAN_ALPHABET_OFFSET ==
+ prevEvent._shadowCharCode) {
+ return prevEvent.keyCode;
+ }
+ }
+ return KeyCode.UNKNOWN;
+ }
+
+ /**
+ * Given the character code returned from a keyDown [event], try to ascertain
+ * and return the corresponding charCode for the character that was pressed.
+ * This information is not shown to the user, but used to help polyfill
+ * keypress events.
+ */
+ int _findCharCodeKeyDown(KeyboardEvent event) {
+ if (event.location == 3) {
+ // Numpad keys.
+ switch (event.keyCode) {
+ case KeyCode.NUM_ZERO:
+ // Even though this function returns _charCodes_, for some cases the
+ // KeyCode == the charCode we want, in which case we use the keycode
+ // constant for readability.
+ return KeyCode.ZERO;
+ case KeyCode.NUM_ONE:
+ return KeyCode.ONE;
+ case KeyCode.NUM_TWO:
+ return KeyCode.TWO;
+ case KeyCode.NUM_THREE:
+ return KeyCode.THREE;
+ case KeyCode.NUM_FOUR:
+ return KeyCode.FOUR;
+ case KeyCode.NUM_FIVE:
+ return KeyCode.FIVE;
+ case KeyCode.NUM_SIX:
+ return KeyCode.SIX;
+ case KeyCode.NUM_SEVEN:
+ return KeyCode.SEVEN;
+ case KeyCode.NUM_EIGHT:
+ return KeyCode.EIGHT;
+ case KeyCode.NUM_NINE:
+ return KeyCode.NINE;
+ case KeyCode.NUM_MULTIPLY:
+ return 42; // Char code for *
+ case KeyCode.NUM_PLUS:
+ return 43; // +
+ case KeyCode.NUM_MINUS:
+ return 45; // -
+ case KeyCode.NUM_PERIOD:
+ return 46; // .
+ case KeyCode.NUM_DIVISION:
+ return 47; // /
+ }
+ } else if (event.keyCode >= 65 && event.keyCode <= 90) {
+ // Set the "char code" for key down as the lower case letter. Again, this
+ // will not show up for the user, but will be helpful in estimating
+ // keyCode locations and other information during the keyPress event.
+ return event.keyCode + _ROMAN_ALPHABET_OFFSET;
+ }
+ switch (event.keyCode) {
+ case KeyCode.SEMICOLON:
+ return KeyCode.FF_SEMICOLON;
+ case KeyCode.EQUALS:
+ return KeyCode.FF_EQUALS;
+ case KeyCode.COMMA:
+ return 44; // Ascii value for ,
+ case KeyCode.DASH:
+ return 45; // -
+ case KeyCode.PERIOD:
+ return 46; // .
+ case KeyCode.SLASH:
+ return 47; // /
+ case KeyCode.APOSTROPHE:
+ return 96; // `
+ case KeyCode.OPEN_SQUARE_BRACKET:
+ return 91; // [
+ case KeyCode.BACKSLASH:
+ return 92; // \
+ case KeyCode.CLOSE_SQUARE_BRACKET:
+ return 93; // ]
+ case KeyCode.SINGLE_QUOTE:
+ return 39; // '
+ }
+ return event.keyCode;
+ }
+
+ /**
+ * Returns true if the key fires a keypress event in the current browser.
+ */
+ bool _firesKeyPressEvent(KeyEvent event) {
+ if (!Device.isIE && !Device.isWebKit) {
+ return true;
+ }
+
+ if (Device.userAgent.contains('Mac') && event.altKey) {
+ return KeyCode.isCharacterKey(event.keyCode);
+ }
+
+ // Alt but not AltGr which is represented as Alt+Ctrl.
+ if (event.altKey && !event.ctrlKey) {
+ return false;
+ }
+
+ // Saves Ctrl or Alt + key for IE and WebKit, which won't fire keypress.
+ if (!event.shiftKey &&
+ (_keyDownList.last.keyCode == KeyCode.CTRL ||
+ _keyDownList.last.keyCode == KeyCode.ALT ||
+ Device.userAgent.contains('Mac') &&
+ _keyDownList.last.keyCode == KeyCode.META)) {
+ return false;
+ }
+
+ // Some keys with Ctrl/Shift do not issue keypress in WebKit.
+ if (Device.isWebKit &&
+ event.ctrlKey &&
+ event.shiftKey &&
+ (event.keyCode == KeyCode.BACKSLASH ||
+ event.keyCode == KeyCode.OPEN_SQUARE_BRACKET ||
+ event.keyCode == KeyCode.CLOSE_SQUARE_BRACKET ||
+ event.keyCode == KeyCode.TILDE ||
+ event.keyCode == KeyCode.SEMICOLON ||
+ event.keyCode == KeyCode.DASH ||
+ event.keyCode == KeyCode.EQUALS ||
+ event.keyCode == KeyCode.COMMA ||
+ event.keyCode == KeyCode.PERIOD ||
+ event.keyCode == KeyCode.SLASH ||
+ event.keyCode == KeyCode.APOSTROPHE ||
+ event.keyCode == KeyCode.SINGLE_QUOTE)) {
+ return false;
+ }
+
+ switch (event.keyCode) {
+ case KeyCode.ENTER:
+ // IE9 does not fire keypress on ENTER.
+ return !Device.isIE;
+ case KeyCode.ESC:
+ return !Device.isWebKit;
+ }
+
+ return KeyCode.isCharacterKey(event.keyCode);
+ }
+
+ /**
+ * Normalize the keycodes to the IE KeyCodes (this is what Chrome, IE, and
+ * Opera all use).
+ */
+ int _normalizeKeyCodes(KeyboardEvent event) {
+ // Note: This may change once we get input about non-US keyboards.
+ if (Device.isFirefox) {
+ switch (event.keyCode) {
+ case KeyCode.FF_EQUALS:
+ return KeyCode.EQUALS;
+ case KeyCode.FF_SEMICOLON:
+ return KeyCode.SEMICOLON;
+ case KeyCode.MAC_FF_META:
+ return KeyCode.META;
+ case KeyCode.WIN_KEY_FF_LINUX:
+ return KeyCode.WIN_KEY;
+ }
+ }
+ return event.keyCode;
+ }
+
+ /** Handle keydown events. */
+ void processKeyDown(KeyboardEvent e) {
+ // Ctrl-Tab and Alt-Tab can cause the focus to be moved to another window
+ // before we've caught a key-up event. If the last-key was one of these
+ // we reset the state.
+ if (_keyDownList.length > 0 &&
+ (_keyDownList.last.keyCode == KeyCode.CTRL && !e.ctrlKey ||
+ _keyDownList.last.keyCode == KeyCode.ALT && !e.altKey ||
+ Device.userAgent.contains('Mac') &&
+ _keyDownList.last.keyCode == KeyCode.META &&
+ !e.metaKey)) {
+ _keyDownList.clear();
+ }
+
+ var event = new KeyEvent.wrap(e);
+ event._shadowKeyCode = _normalizeKeyCodes(event);
+ // Technically a "keydown" event doesn't have a charCode. This is
+ // calculated nonetheless to provide us with more information in giving
+ // as much information as possible on keypress about keycode and also
+ // charCode.
+ event._shadowCharCode = _findCharCodeKeyDown(event);
+ if (_keyDownList.length > 0 &&
+ event.keyCode != _keyDownList.last.keyCode &&
+ !_firesKeyPressEvent(event)) {
+ // Some browsers have quirks not firing keypress events where all other
+ // browsers do. This makes them more consistent.
+ processKeyPress(e);
+ }
+ _keyDownList.add(event);
+ _stream.add(event);
+ }
+
+ /** Handle keypress events. */
+ void processKeyPress(KeyboardEvent event) {
+ var e = new KeyEvent.wrap(event);
+ // IE reports the character code in the keyCode field for keypress events.
+ // There are two exceptions however, Enter and Escape.
+ if (Device.isIE) {
+ if (e.keyCode == KeyCode.ENTER || e.keyCode == KeyCode.ESC) {
+ e._shadowCharCode = 0;
+ } else {
+ e._shadowCharCode = e.keyCode;
+ }
+ } else if (Device.isOpera) {
+ // Opera reports the character code in the keyCode field.
+ e._shadowCharCode = KeyCode.isCharacterKey(e.keyCode) ? e.keyCode : 0;
+ }
+ // Now we guesstimate about what the keycode is that was actually
+ // pressed, given previous keydown information.
+ e._shadowKeyCode = _determineKeyCodeForKeypress(e);
+
+ // Correct the key value for certain browser-specific quirks.
+ if (e._shadowKeyIdentifier != null &&
+ _keyIdentifier.containsKey(e._shadowKeyIdentifier)) {
+ // This is needed for Safari Windows because it currently doesn't give a
+ // keyCode/which for non printable keys.
+ e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier];
+ }
+ e._shadowAltKey = _keyDownList.any((var element) => element.altKey);
+ _stream.add(e);
+ }
+
+ /** Handle keyup events. */
+ void processKeyUp(KeyboardEvent event) {
+ var e = new KeyEvent.wrap(event);
+ KeyboardEvent toRemove = null;
+ for (var key in _keyDownList) {
+ if (key.keyCode == e.keyCode) {
+ toRemove = key;
+ }
+ }
+ if (toRemove != null) {
+ _keyDownList.removeWhere((element) => element == toRemove);
+ } else if (_keyDownList.length > 0) {
+ // This happens when we've reached some international keyboard case we
+ // haven't accounted for or we haven't correctly eliminated all browser
+ // inconsistencies. Filing bugs on when this is reached is welcome!
+ _keyDownList.removeLast();
+ }
+ _stream.add(e);
+ }
+}
+
+/**
+ * Records KeyboardEvents that occur on a particular element, and provides a
+ * stream of outgoing KeyEvents with cross-browser consistent keyCode and
+ * charCode values despite the fact that a multitude of browsers that have
+ * varying keyboard default behavior.
+ *
+ * Example usage:
+ *
+ * KeyboardEventStream.onKeyDown(document.body).listen(
+ * keydownHandlerTest);
+ *
+ * This class is very much a work in progress, and we'd love to get information
+ * on how we can make this class work with as many international keyboards as
+ * possible. Bugs welcome!
+ */
+class KeyboardEventStream {
+ /** Named constructor to produce a stream for onKeyPress events. */
+ static CustomStream<KeyEvent> onKeyPress(EventTarget target) =>
+ new _KeyboardEventHandler('keypress').forTarget(target);
+
+ /** Named constructor to produce a stream for onKeyUp events. */
+ static CustomStream<KeyEvent> onKeyUp(EventTarget target) =>
+ new _KeyboardEventHandler('keyup').forTarget(target);
+
+ /** Named constructor to produce a stream for onKeyDown events. */
+ static CustomStream<KeyEvent> onKeyDown(EventTarget target) =>
+ new _KeyboardEventHandler('keydown').forTarget(target);
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Class which helps construct standard node validation policies.
+ *
+ * By default this will not accept anything, but the 'allow*' functions can be
+ * used to expand what types of elements or attributes are allowed.
+ *
+ * All allow functions are additive- elements will be accepted if they are
+ * accepted by any specific rule.
+ *
+ * It is important to remember that sanitization is not just intended to prevent
+ * cross-site scripting attacks, but also to prevent information from being
+ * displayed in unexpected ways. For example something displaying basic
+ * formatted text may not expect `<video>` tags to appear. In this case an
+ * empty NodeValidatorBuilder with just [allowTextElements] might be
+ * appropriate.
+ */
+class NodeValidatorBuilder implements NodeValidator {
+ final List<NodeValidator> _validators = <NodeValidator>[];
+
+ NodeValidatorBuilder() {}
+
+ /**
+ * Creates a new NodeValidatorBuilder which accepts common constructs.
+ *
+ * By default this will accept HTML5 elements and attributes with the default
+ * [UriPolicy] and templating elements.
+ *
+ * Notable syntax which is filtered:
+ *
+ * * Only known-good HTML5 elements and attributes are allowed.
+ * * All URLs must be same-origin, use [allowNavigation] and [allowImages] to
+ * specify additional URI policies.
+ * * Inline-styles are not allowed.
+ * * Custom element tags are disallowed, use [allowCustomElement].
+ * * Custom tags extensions are disallowed, use [allowTagExtension].
+ * * SVG Elements are not allowed, use [allowSvg].
+ *
+ * For scenarios where the HTML should only contain formatted text
+ * [allowTextElements] is more appropriate.
+ *
+ * Use [allowSvg] to allow SVG elements.
+ */
+ NodeValidatorBuilder.common() {
+ allowHtml5();
+ allowTemplating();
+ }
+
+ /**
+ * Allows navigation elements- Form and Anchor tags, along with common
+ * attributes.
+ *
+ * The UriPolicy can be used to restrict the locations the navigation elements
+ * are allowed to direct to. By default this will use the default [UriPolicy].
+ */
+ void allowNavigation([UriPolicy uriPolicy]) {
+ if (uriPolicy == null) {
+ uriPolicy = new UriPolicy();
+ }
+ add(new _SimpleNodeValidator.allowNavigation(uriPolicy));
+ }
+
+ /**
+ * Allows image elements.
+ *
+ * The UriPolicy can be used to restrict the locations the images may be
+ * loaded from. By default this will use the default [UriPolicy].
+ */
+ void allowImages([UriPolicy uriPolicy]) {
+ if (uriPolicy == null) {
+ uriPolicy = new UriPolicy();
+ }
+ add(new _SimpleNodeValidator.allowImages(uriPolicy));
+ }
+
+ /**
+ * Allow basic text elements.
+ *
+ * This allows a subset of HTML5 elements, specifically just these tags and
+ * no attributes.
+ *
+ * * B
+ * * BLOCKQUOTE
+ * * BR
+ * * EM
+ * * H1
+ * * H2
+ * * H3
+ * * H4
+ * * H5
+ * * H6
+ * * HR
+ * * I
+ * * LI
+ * * OL
+ * * P
+ * * SPAN
+ * * UL
+ */
+ void allowTextElements() {
+ add(new _SimpleNodeValidator.allowTextElements());
+ }
+
+ /**
+ * Allow inline styles on elements.
+ *
+ * If [tagName] is not specified then this allows inline styles on all
+ * elements. Otherwise tagName limits the styles to the specified elements.
+ */
+ void allowInlineStyles({String tagName}) {
+ if (tagName == null) {
+ tagName = '*';
+ } else {
+ tagName = tagName.toUpperCase();
+ }
+ add(new _SimpleNodeValidator(null, allowedAttributes: ['$tagName::style']));
+ }
+
+ /**
+ * Allow common safe HTML5 elements and attributes.
+ *
+ * This list is based off of the Caja whitelists at:
+ * https://code.google.com/p/google-caja/wiki/CajaWhitelists.
+ *
+ * Common things which are not allowed are script elements, style attributes
+ * and any script handlers.
+ */
+ void allowHtml5({UriPolicy uriPolicy}) {
+ add(new _Html5NodeValidator(uriPolicy: uriPolicy));
+ }
+
+ /**
+ * Allow SVG elements and attributes except for known bad ones.
+ */
+ void allowSvg() {
+ add(new _SvgNodeValidator());
+ }
+
+ /**
+ * Allow custom elements with the specified tag name and specified attributes.
+ *
+ * This will allow the elements as custom tags (such as <x-foo></x-foo>),
+ * but will not allow tag extensions. Use [allowTagExtension] to allow
+ * tag extensions.
+ */
+ void allowCustomElement(String tagName,
+ {UriPolicy uriPolicy,
+ Iterable<String> attributes,
+ Iterable<String> uriAttributes}) {
+ var tagNameUpper = tagName.toUpperCase();
+ var attrs = attributes
+ ?.map<String>((name) => '$tagNameUpper::${name.toLowerCase()}');
+ var uriAttrs = uriAttributes
+ ?.map<String>((name) => '$tagNameUpper::${name.toLowerCase()}');
+ if (uriPolicy == null) {
+ uriPolicy = new UriPolicy();
+ }
+
+ add(new _CustomElementNodeValidator(
+ uriPolicy, [tagNameUpper], attrs, uriAttrs, false, true));
+ }
+
+ /**
+ * Allow custom tag extensions with the specified type name and specified
+ * attributes.
+ *
+ * This will allow tag extensions (such as <div is="x-foo"></div>),
+ * but will not allow custom tags. Use [allowCustomElement] to allow
+ * custom tags.
+ */
+ void allowTagExtension(String tagName, String baseName,
+ {UriPolicy uriPolicy,
+ Iterable<String> attributes,
+ Iterable<String> uriAttributes}) {
+ var baseNameUpper = baseName.toUpperCase();
+ var tagNameUpper = tagName.toUpperCase();
+ var attrs = attributes
+ ?.map<String>((name) => '$baseNameUpper::${name.toLowerCase()}');
+ var uriAttrs = uriAttributes
+ ?.map<String>((name) => '$baseNameUpper::${name.toLowerCase()}');
+ if (uriPolicy == null) {
+ uriPolicy = new UriPolicy();
+ }
+
+ add(new _CustomElementNodeValidator(uriPolicy,
+ [tagNameUpper, baseNameUpper], attrs, uriAttrs, true, false));
+ }
+
+ void allowElement(String tagName,
+ {UriPolicy uriPolicy,
+ Iterable<String> attributes,
+ Iterable<String> uriAttributes}) {
+ allowCustomElement(tagName,
+ uriPolicy: uriPolicy,
+ attributes: attributes,
+ uriAttributes: uriAttributes);
+ }
+
+ /**
+ * Allow templating elements (such as <template> and template-related
+ * attributes.
+ *
+ * This still requires other validators to allow regular attributes to be
+ * bound (such as [allowHtml5]).
+ */
+ void allowTemplating() {
+ add(new _TemplatingNodeValidator());
+ }
+
+ /**
+ * Add an additional validator to the current list of validators.
+ *
+ * Elements and attributes will be accepted if they are accepted by any
+ * validators.
+ */
+ void add(NodeValidator validator) {
+ _validators.add(validator);
+ }
+
+ bool allowsElement(Element element) {
+ return _validators.any((v) => v.allowsElement(element));
+ }
+
+ bool allowsAttribute(Element element, String attributeName, String value) {
+ return _validators
+ .any((v) => v.allowsAttribute(element, attributeName, value));
+ }
+}
+
+class _SimpleNodeValidator implements NodeValidator {
+ final Set<String> allowedElements = new Set<String>();
+ final Set<String> allowedAttributes = new Set<String>();
+ final Set<String> allowedUriAttributes = new Set<String>();
+ final UriPolicy uriPolicy;
+
+ factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) {
+ return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
+ 'A',
+ 'FORM'
+ ], allowedAttributes: const [
+ 'A::accesskey',
+ 'A::coords',
+ 'A::hreflang',
+ 'A::name',
+ 'A::shape',
+ 'A::tabindex',
+ 'A::target',
+ 'A::type',
+ 'FORM::accept',
+ 'FORM::autocomplete',
+ 'FORM::enctype',
+ 'FORM::method',
+ 'FORM::name',
+ 'FORM::novalidate',
+ 'FORM::target',
+ ], allowedUriAttributes: const [
+ 'A::href',
+ 'FORM::action',
+ ]);
+ }
+
+ factory _SimpleNodeValidator.allowImages(UriPolicy uriPolicy) {
+ return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
+ 'IMG'
+ ], allowedAttributes: const [
+ 'IMG::align',
+ 'IMG::alt',
+ 'IMG::border',
+ 'IMG::height',
+ 'IMG::hspace',
+ 'IMG::ismap',
+ 'IMG::name',
+ 'IMG::usemap',
+ 'IMG::vspace',
+ 'IMG::width',
+ ], allowedUriAttributes: const [
+ 'IMG::src',
+ ]);
+ }
+
+ factory _SimpleNodeValidator.allowTextElements() {
+ return new _SimpleNodeValidator(null, allowedElements: const [
+ 'B',
+ 'BLOCKQUOTE',
+ 'BR',
+ 'EM',
+ 'H1',
+ 'H2',
+ 'H3',
+ 'H4',
+ 'H5',
+ 'H6',
+ 'HR',
+ 'I',
+ 'LI',
+ 'OL',
+ 'P',
+ 'SPAN',
+ 'UL',
+ ]);
+ }
+
+ /**
+ * Elements must be uppercased tag names. For example `'IMG'`.
+ * Attributes must be uppercased tag name followed by :: followed by
+ * lowercase attribute name. For example `'IMG:src'`.
+ */
+ _SimpleNodeValidator(this.uriPolicy,
+ {Iterable<String> allowedElements,
+ Iterable<String> allowedAttributes,
+ Iterable<String> allowedUriAttributes}) {
+ this.allowedElements.addAll(allowedElements ?? const []);
+ allowedAttributes = allowedAttributes ?? const [];
+ allowedUriAttributes = allowedUriAttributes ?? const [];
+ var legalAttributes = allowedAttributes
+ .where((x) => !_Html5NodeValidator._uriAttributes.contains(x));
+ var extraUriAttributes = allowedAttributes
+ .where((x) => _Html5NodeValidator._uriAttributes.contains(x));
+ this.allowedAttributes.addAll(legalAttributes);
+ this.allowedUriAttributes.addAll(allowedUriAttributes);
+ this.allowedUriAttributes.addAll(extraUriAttributes);
+ }
+
+ bool allowsElement(Element element) {
+ return allowedElements.contains(Element._safeTagName(element));
+ }
+
+ bool allowsAttribute(Element element, String attributeName, String value) {
+ var tagName = Element._safeTagName(element);
+ if (allowedUriAttributes.contains('$tagName::$attributeName')) {
+ return uriPolicy.allowsUri(value);
+ } else if (allowedUriAttributes.contains('*::$attributeName')) {
+ return uriPolicy.allowsUri(value);
+ } else if (allowedAttributes.contains('$tagName::$attributeName')) {
+ return true;
+ } else if (allowedAttributes.contains('*::$attributeName')) {
+ return true;
+ } else if (allowedAttributes.contains('$tagName::*')) {
+ return true;
+ } else if (allowedAttributes.contains('*::*')) {
+ return true;
+ }
+ return false;
+ }
+}
+
+class _CustomElementNodeValidator extends _SimpleNodeValidator {
+ final bool allowTypeExtension;
+ final bool allowCustomTag;
+
+ _CustomElementNodeValidator(
+ UriPolicy uriPolicy,
+ Iterable<String> allowedElements,
+ Iterable<String> allowedAttributes,
+ Iterable<String> allowedUriAttributes,
+ bool allowTypeExtension,
+ bool allowCustomTag)
+ : this.allowTypeExtension = allowTypeExtension == true,
+ this.allowCustomTag = allowCustomTag == true,
+ super(uriPolicy,
+ allowedElements: allowedElements,
+ allowedAttributes: allowedAttributes,
+ allowedUriAttributes: allowedUriAttributes);
+
+ bool allowsElement(Element element) {
+ if (allowTypeExtension) {
+ var isAttr = element.attributes['is'];
+ if (isAttr != null) {
+ return allowedElements.contains(isAttr.toUpperCase()) &&
+ allowedElements.contains(Element._safeTagName(element));
+ }
+ }
+ return allowCustomTag &&
+ allowedElements.contains(Element._safeTagName(element));
+ }
+
+ bool allowsAttribute(Element element, String attributeName, String value) {
+ if (allowsElement(element)) {
+ if (allowTypeExtension &&
+ attributeName == 'is' &&
+ allowedElements.contains(value.toUpperCase())) {
+ return true;
+ }
+ return super.allowsAttribute(element, attributeName, value);
+ }
+ return false;
+ }
+}
+
+class _TemplatingNodeValidator extends _SimpleNodeValidator {
+ static const _TEMPLATE_ATTRS = const <String>[
+ 'bind',
+ 'if',
+ 'ref',
+ 'repeat',
+ 'syntax'
+ ];
+
+ final Set<String> _templateAttrs;
+
+ _TemplatingNodeValidator()
+ : _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS),
+ super(null,
+ allowedElements: ['TEMPLATE'],
+ allowedAttributes:
+ _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')) {}
+
+ bool allowsAttribute(Element element, String attributeName, String value) {
+ if (super.allowsAttribute(element, attributeName, value)) {
+ return true;
+ }
+
+ if (attributeName == 'template' && value == "") {
+ return true;
+ }
+
+ if (element.attributes['template'] == "") {
+ return _templateAttrs.contains(attributeName);
+ }
+ return false;
+ }
+}
+
+class _SvgNodeValidator implements NodeValidator {
+ bool allowsElement(Element element) {
+ if (element is svg.ScriptElement) {
+ return false;
+ }
+ // Firefox 37 has issues with creating foreign elements inside a
+ // foreignobject tag as SvgElement. We don't want foreignobject contents
+ // anyway, so just remove the whole tree outright. And we can't rely
+ // on IE recognizing the SvgForeignObject type, so go by tagName. Bug 23144
+ if (element is svg.SvgElement &&
+ Element._safeTagName(element) == 'foreignObject') {
+ return false;
+ }
+ if (element is svg.SvgElement) {
+ return true;
+ }
+ return false;
+ }
+
+ bool allowsAttribute(Element element, String attributeName, String value) {
+ if (attributeName == 'is' || attributeName.startsWith('on')) {
+ return false;
+ }
+ return allowsElement(element);
+ }
+}
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Contains the set of standard values returned by HTMLDocument.getReadyState.
+ */
+abstract class ReadyState {
+ /**
+ * Indicates the document is still loading and parsing.
+ */
+ static const String LOADING = "loading";
+
+ /**
+ * Indicates the document is finished parsing but is still loading
+ * subresources.
+ */
+ static const String INTERACTIVE = "interactive";
+
+ /**
+ * Indicates the document and all subresources have been loaded.
+ */
+ static const String COMPLETE = "complete";
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * A list which just wraps another list, for either intercepting list calls or
+ * retyping the list (for example, from List<A> to List<B> where B extends A).
+ */
+class _WrappedList<E extends Node> extends ListBase<E>
+ implements NodeListWrapper {
+ final List<Node> _list;
+
+ _WrappedList(this._list);
+
+ // Iterable APIs
+
+ Iterator<E> get iterator => new _WrappedIterator<E>(_list.iterator);
+
+ int get length => _list.length;
+
+ // Collection APIs
+
+ void add(E element) {
+ _list.add(element);
+ }
+
+ bool remove(Object element) => _list.remove(element);
+
+ void clear() {
+ _list.clear();
+ }
+
+ // List APIs
+
+ E operator [](int index) => _list[index];
+
+ void operator []=(int index, E value) {
+ _list[index] = value;
+ }
+
+ set length(int newLength) {
+ _list.length = newLength;
+ }
+
+ void sort([int compare(E a, E b)]) {
+ // Implicit downcast on argument from Node to E-extends-Node.
+ _list.sort((Node a, Node b) => compare(a, b));
+ }
+
+ int indexOf(Object element, [int start = 0]) => _list.indexOf(element, start);
+
+ int lastIndexOf(Object element, [int start]) =>
+ _list.lastIndexOf(element, start);
+
+ void insert(int index, E element) => _list.insert(index, element);
+
+ E removeAt(int index) => _list.removeAt(index);
+
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+ _list.setRange(start, end, iterable, skipCount);
+ }
+
+ void removeRange(int start, int end) {
+ _list.removeRange(start, end);
+ }
+
+ void replaceRange(int start, int end, Iterable<E> iterable) {
+ _list.replaceRange(start, end, iterable);
+ }
+
+ void fillRange(int start, int end, [E fillValue]) {
+ _list.fillRange(start, end, fillValue);
+ }
+
+ List<Node> get rawList => _list;
+}
+
+/**
+ * Iterator wrapper for _WrappedList.
+ */
+class _WrappedIterator<E extends Node> implements Iterator<E> {
+ Iterator<Node> _iterator;
+
+ _WrappedIterator(this._iterator);
+
+ bool moveNext() {
+ return _iterator.moveNext();
+ }
+
+ E get current => _iterator.current;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class _HttpRequestUtils {
+ // Helper for factory HttpRequest.get
+ static HttpRequest get(
+ String url, onComplete(HttpRequest request), bool withCredentials) {
+ final request = new HttpRequest();
+ request.open('GET', url, async: true);
+
+ request.withCredentials = withCredentials;
+
+ request.onReadyStateChange.listen((e) {
+ if (request.readyState == HttpRequest.DONE) {
+ onComplete(request);
+ }
+ });
+
+ request.send();
+
+ return request;
+ }
+}
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Iterator for arrays with fixed size.
+class FixedSizeListIterator<T> implements Iterator<T> {
+ final List<T> _array;
+ final int _length; // Cache array length for faster access.
+ int _position;
+ T _current;
+
+ FixedSizeListIterator(List<T> array)
+ : _array = array,
+ _position = -1,
+ _length = array.length;
+
+ bool moveNext() {
+ int nextPosition = _position + 1;
+ if (nextPosition < _length) {
+ _current = _array[nextPosition];
+ _position = nextPosition;
+ return true;
+ }
+ _current = null;
+ _position = _length;
+ return false;
+ }
+
+ T get current => _current;
+}
+
+// Iterator for arrays with variable size.
+class _VariableSizeListIterator<T> implements Iterator<T> {
+ final List<T> _array;
+ int _position;
+ T _current;
+
+ _VariableSizeListIterator(List<T> array)
+ : _array = array,
+ _position = -1;
+
+ bool moveNext() {
+ int nextPosition = _position + 1;
+ if (nextPosition < _array.length) {
+ _current = _array[nextPosition];
+ _position = nextPosition;
+ return true;
+ }
+ _current = null;
+ _position = _array.length;
+ return false;
+ }
+
+ T get current => _current;
+}
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Console {
+ const Console._safe();
+ static const Console _safeConsole = const Console._safe();
+
+ bool get _isConsoleDefined => JS('bool', 'typeof console != "undefined"');
+
+ MemoryInfo get memory =>
+ _isConsoleDefined ? JS('MemoryInfo', 'window.console.memory') : null;
+
+ void assertCondition(bool condition, Object arg) => _isConsoleDefined
+ ? JS('void', 'window.console.assertCondition(#, #)', condition, arg)
+ : null;
+
+ void clear(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.clear(#)', arg) : null;
+
+ void count(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.count(#)', arg) : null;
+
+ void debug(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.debug(#)', arg) : null;
+
+ void dir(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.dir(#)', arg) : null;
+
+ void dirxml(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.dirxml(#)', arg) : null;
+
+ void error(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.error(#)', arg) : null;
+
+ void group(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.group(#)', arg) : null;
+
+ void groupCollapsed(Object arg) => _isConsoleDefined
+ ? JS('void', 'window.console.groupCollapsed(#)', arg)
+ : null;
+
+ void groupEnd() =>
+ _isConsoleDefined ? JS('void', 'window.console.groupEnd()') : null;
+
+ void info(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.info(#)', arg) : null;
+
+ void log(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.log(#)', arg) : null;
+
+ void markTimeline(Object arg) => _isConsoleDefined
+ ? JS('void', 'window.console.markTimeline(#)', arg)
+ : null;
+
+ void profile(String title) =>
+ _isConsoleDefined ? JS('void', 'window.console.profile(#)', title) : null;
+
+ void profileEnd(String title) => _isConsoleDefined
+ ? JS('void', 'window.console.profileEnd(#)', title)
+ : null;
+
+ void table(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.table(#)', arg) : null;
+
+ void time(String title) =>
+ _isConsoleDefined ? JS('void', 'window.console.time(#)', title) : null;
+
+ void timeEnd(String title) =>
+ _isConsoleDefined ? JS('void', 'window.console.timeEnd(#)', title) : null;
+
+ void timeStamp(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.timeStamp(#)', arg) : null;
+
+ void trace(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.trace(#)', arg) : null;
+
+ void warn(Object arg) =>
+ _isConsoleDefined ? JS('void', 'window.console.warn(#)', arg) : null;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Conversions for Window. These check if the window is the local
+// window, and if it's not, wraps or unwraps it with a secure wrapper.
+// We need to test for EventTarget here as well as it's a base type.
+// We omit an unwrapper for Window as no methods take a non-local
+// window as a parameter.
+
+WindowBase _convertNativeToDart_Window(win) {
+ if (win == null) return null;
+ return _DOMWindowCrossFrame._createSafe(win);
+}
+
+EventTarget _convertNativeToDart_EventTarget(e) {
+ if (e == null) {
+ return null;
+ }
+ // Assume it's a Window if it contains the postMessage property. It may be
+ // from a different frame - without a patched prototype - so we cannot
+ // rely on Dart type checking.
+ if (JS('bool', r'"postMessage" in #', e)) {
+ var window = _DOMWindowCrossFrame._createSafe(e);
+ // If it's a native window.
+ if (window is EventTarget) {
+ return window;
+ }
+ return null;
+ } else
+ return e;
+}
+
+EventTarget _convertDartToNative_EventTarget(e) {
+ if (e is _DOMWindowCrossFrame) {
+ return e._window;
+ } else {
+ return e;
+ }
+}
+
+_convertNativeToDart_XHR_Response(o) {
+ if (o is Document) {
+ return o;
+ }
+ return convertNativeToDart_SerializedScriptValue(o);
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+_callConstructor(constructor, interceptor) {
+ return (receiver) {
+ setNativeSubclassDispatchRecord(receiver, interceptor);
+
+ // Mirrors uses the constructor property to cache lookups, so we need it to
+ // be set correctly, including on IE where it is not automatically picked
+ // up from the __proto__.
+ JS('', '#.constructor = #.__proto__.constructor', receiver, receiver);
+ return JS('', '#(#)', constructor, receiver);
+ };
+}
+
+_callAttached(receiver) {
+ return receiver.attached();
+}
+
+_callDetached(receiver) {
+ return receiver.detached();
+}
+
+_callAttributeChanged(receiver, name, oldValue, newValue) {
+ return receiver.attributeChanged(name, oldValue, newValue);
+}
+
+_makeCallbackMethod(callback) {
+ return JS(
+ '',
+ '''((function(invokeCallback) {
+ return function() {
+ return invokeCallback(this);
+ };
+ })(#))''',
+ convertDartClosureToJS(callback, 1));
+}
+
+_makeCallbackMethod3(callback) {
+ return JS(
+ '',
+ '''((function(invokeCallback) {
+ return function(arg1, arg2, arg3) {
+ return invokeCallback(this, arg1, arg2, arg3);
+ };
+ })(#))''',
+ convertDartClosureToJS(callback, 4));
+}
+
+/// Checks whether the given [element] correctly extends from the native class
+/// with the given [baseClassName]. This method will throw if the base class
+/// doesn't match, except when the element extends from `template` and it's base
+/// class is `HTMLUnknownElement`. This exclusion is needed to support extension
+/// of template elements (used heavily in Polymer 1.0) on IE11 when using the
+/// webcomponents-lite.js polyfill.
+void _checkExtendsNativeClassOrTemplate(
+ Element element, String extendsTag, String baseClassName) {
+ if (!JS('bool', '(# instanceof window[#])', element, baseClassName) &&
+ !((extendsTag == 'template' &&
+ JS('bool', '(# instanceof window["HTMLUnknownElement"])',
+ element)))) {
+ throw new UnsupportedError('extendsTag does not match base native class');
+ }
+}
+
+Function _registerCustomElement(context, document, String tag, [Map options]) {
+ // Function follows the same pattern as the following JavaScript code for
+ // registering a custom element.
+ //
+ // var proto = Object.create(HTMLElement.prototype, {
+ // createdCallback: {
+ // value: function() {
+ // window.console.log('here');
+ // }
+ // }
+ // });
+ // document.registerElement('x-foo', { prototype: proto });
+ // ...
+ // var e = document.createElement('x-foo');
+
+ var extendsTagName = '';
+ Type type;
+ if (options != null) {
+ extendsTagName = options['extends'];
+ type = options['prototype'];
+ }
+
+ var interceptorClass = findInterceptorConstructorForType(type);
+ if (interceptorClass == null) {
+ throw new ArgumentError(type);
+ }
+
+ var interceptor = JS('=Object', '#.prototype', interceptorClass);
+
+ var constructor = findConstructorForNativeSubclassType(type, 'created');
+ if (constructor == null) {
+ throw new ArgumentError("$type has no constructor called 'created'");
+ }
+
+ // Workaround for 13190- use an article element to ensure that HTMLElement's
+ // interceptor is resolved correctly.
+ getNativeInterceptor(new Element.tag('article'));
+
+ String baseClassName = findDispatchTagForInterceptorClass(interceptorClass);
+ if (baseClassName == null) {
+ throw new ArgumentError(type);
+ }
+
+ if (extendsTagName == null) {
+ if (baseClassName != 'HTMLElement') {
+ throw new UnsupportedError('Class must provide extendsTag if base '
+ 'native class is not HtmlElement');
+ }
+ } else {
+ var element = document.createElement(extendsTagName);
+ _checkExtendsNativeClassOrTemplate(element, extendsTagName, baseClassName);
+ }
+
+ var baseConstructor = JS('=Object', '#[#]', context, baseClassName);
+
+ var properties = JS('=Object', '{}');
+
+ JS(
+ 'void',
+ '#.createdCallback = #',
+ properties,
+ JS('=Object', '{value: #}',
+ _makeCallbackMethod(_callConstructor(constructor, interceptor))));
+ JS('void', '#.attachedCallback = #', properties,
+ JS('=Object', '{value: #}', _makeCallbackMethod(_callAttached)));
+ JS('void', '#.detachedCallback = #', properties,
+ JS('=Object', '{value: #}', _makeCallbackMethod(_callDetached)));
+ JS('void', '#.attributeChangedCallback = #', properties,
+ JS('=Object', '{value: #}', _makeCallbackMethod3(_callAttributeChanged)));
+
+ var baseProto = JS('=Object', '#.prototype', baseConstructor);
+ var proto = JS('=Object', 'Object.create(#, #)', baseProto, properties);
+
+ setNativeSubclassDispatchRecord(proto, interceptor);
+
+ var opts = JS('=Object', '{prototype: #}', proto);
+
+ if (extendsTagName != null) {
+ JS('=Object', '#.extends = #', opts, extendsTagName);
+ }
+
+ return JS(
+ 'JavaScriptFunction', '#.registerElement(#, #)', document, tag, opts);
+}
+
+//// Called by Element.created to do validation & initialization.
+void _initializeCustomElement(Element e) {
+ // TODO(blois): Add validation that this is only in response to an upgrade.
+}
+
+/// Dart2JS implementation of ElementUpgrader
+class _JSElementUpgrader implements ElementUpgrader {
+ var _interceptor;
+ var _constructor;
+ var _nativeType;
+
+ _JSElementUpgrader(Document document, Type type, String extendsTag) {
+ var interceptorClass = findInterceptorConstructorForType(type);
+ if (interceptorClass == null) {
+ throw new ArgumentError(type);
+ }
+
+ _constructor = findConstructorForNativeSubclassType(type, 'created');
+ if (_constructor == null) {
+ throw new ArgumentError("$type has no constructor called 'created'");
+ }
+
+ // Workaround for 13190- use an article element to ensure that HTMLElement's
+ // interceptor is resolved correctly.
+ getNativeInterceptor(new Element.tag('article'));
+
+ var baseClassName = findDispatchTagForInterceptorClass(interceptorClass);
+ if (baseClassName == null) {
+ throw new ArgumentError(type);
+ }
+
+ if (extendsTag == null) {
+ if (baseClassName != 'HTMLElement') {
+ throw new UnsupportedError('Class must provide extendsTag if base '
+ 'native class is not HtmlElement');
+ }
+ _nativeType = HtmlElement;
+ } else {
+ var element = document.createElement(extendsTag);
+ _checkExtendsNativeClassOrTemplate(element, extendsTag, baseClassName);
+ _nativeType = element.runtimeType;
+ }
+
+ _interceptor = JS('=Object', '#.prototype', interceptorClass);
+ }
+
+ Element upgrade(Element element) {
+ // Only exact type matches are supported- cannot be a subclass.
+ if (element.runtimeType != _nativeType) {
+ // Some browsers may represent non-upgraded elements <x-foo> as
+ // UnknownElement and not a plain HtmlElement.
+ if (_nativeType != HtmlElement || element.runtimeType != UnknownElement) {
+ throw new ArgumentError('element is not subclass of $_nativeType');
+ }
+ }
+
+ setNativeSubclassDispatchRecord(element, _interceptor);
+ JS('', '#(#)', _constructor, element);
+ return element;
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(vsm): Unify with Dartium version.
+class _DOMWindowCrossFrame implements WindowBase {
+ // Private window. Note, this is a window in another frame, so it
+ // cannot be typed as "Window" as its prototype is not patched
+ // properly. Its fields and methods can only be accessed via JavaScript.
+ final _window;
+
+ // Fields.
+ HistoryBase get history =>
+ _HistoryCrossFrame._createSafe(JS('HistoryBase', '#.history', _window));
+ LocationBase get location => _LocationCrossFrame._createSafe(
+ JS('LocationBase', '#.location', _window));
+
+ // TODO(vsm): Add frames to navigate subframes. See 2312.
+
+ bool get closed => JS('bool', '#.closed', _window);
+
+ WindowBase get opener => _createSafe(JS('WindowBase', '#.opener', _window));
+
+ WindowBase get parent => _createSafe(JS('WindowBase', '#.parent', _window));
+
+ WindowBase get top => _createSafe(JS('WindowBase', '#.top', _window));
+
+ // Methods.
+ void close() => JS('void', '#.close()', _window);
+
+ void postMessage(var message, String targetOrigin,
+ [List messagePorts = null]) {
+ if (messagePorts == null) {
+ JS('void', '#.postMessage(#,#)', _window,
+ convertDartToNative_SerializedScriptValue(message), targetOrigin);
+ } else {
+ JS(
+ 'void',
+ '#.postMessage(#,#,#)',
+ _window,
+ convertDartToNative_SerializedScriptValue(message),
+ targetOrigin,
+ messagePorts);
+ }
+ }
+
+ // Implementation support.
+ _DOMWindowCrossFrame(this._window);
+
+ static WindowBase _createSafe(w) {
+ if (identical(w, window)) {
+ return w;
+ } else {
+ // TODO(vsm): Cache or implement equality.
+ registerGlobalObject(w);
+ return new _DOMWindowCrossFrame(w);
+ }
+ }
+
+ // TODO(efortuna): Remove this method. dartbug.com/16814
+ Events get on => throw new UnsupportedError(
+ 'You can only attach EventListeners to your own window.');
+ // TODO(efortuna): Remove this method. dartbug.com/16814
+ void _addEventListener(String type, EventListener listener,
+ [bool useCapture]) =>
+ throw new UnsupportedError(
+ 'You can only attach EventListeners to your own window.');
+ // TODO(efortuna): Remove this method. dartbug.com/16814
+ void addEventListener(String type, EventListener listener,
+ [bool useCapture]) =>
+ throw new UnsupportedError(
+ 'You can only attach EventListeners to your own window.');
+ // TODO(efortuna): Remove this method. dartbug.com/16814
+ bool dispatchEvent(Event event) => throw new UnsupportedError(
+ 'You can only attach EventListeners to your own window.');
+ // TODO(efortuna): Remove this method. dartbug.com/16814
+ void _removeEventListener(String type, EventListener listener,
+ [bool useCapture]) =>
+ throw new UnsupportedError(
+ 'You can only attach EventListeners to your own window.');
+ // TODO(efortuna): Remove this method. dartbug.com/16814
+ void removeEventListener(String type, EventListener listener,
+ [bool useCapture]) =>
+ throw new UnsupportedError(
+ 'You can only attach EventListeners to your own window.');
+}
+
+class _LocationCrossFrame implements LocationBase {
+ // Private location. Note, this is a location object in another frame, so it
+ // cannot be typed as "Location" as its prototype is not patched
+ // properly. Its fields and methods can only be accessed via JavaScript.
+ var _location;
+
+ set href(String val) => _setHref(_location, val);
+ static void _setHref(location, val) {
+ JS('void', '#.href = #', location, val);
+ }
+
+ // Implementation support.
+ _LocationCrossFrame(this._location);
+
+ static LocationBase _createSafe(location) {
+ if (identical(location, window.location)) {
+ return location;
+ } else {
+ // TODO(vsm): Cache or implement equality.
+ return new _LocationCrossFrame(location);
+ }
+ }
+}
+
+class _HistoryCrossFrame implements HistoryBase {
+ // Private history. Note, this is a history object in another frame, so it
+ // cannot be typed as "History" as its prototype is not patched
+ // properly. Its fields and methods can only be accessed via JavaScript.
+ var _history;
+
+ void back() => JS('void', '#.back()', _history);
+
+ void forward() => JS('void', '#.forward()', _history);
+
+ void go(int distance) => JS('void', '#.go(#)', _history, distance);
+
+ // Implementation support.
+ _HistoryCrossFrame(this._history);
+
+ static HistoryBase _createSafe(h) {
+ if (identical(h, window.history)) {
+ return h;
+ } else {
+ // TODO(vsm): Cache or implement equality.
+ return new _HistoryCrossFrame(h);
+ }
+ }
+}
+
+/**
+ * A custom KeyboardEvent that attempts to eliminate cross-browser
+ * inconsistencies, and also provide both keyCode and charCode information
+ * for all key events (when such information can be determined).
+ *
+ * KeyEvent tries to provide a higher level, more polished keyboard event
+ * information on top of the "raw" [KeyboardEvent].
+ *
+ * The mechanics of using KeyEvents is a little different from the underlying
+ * [KeyboardEvent]. To use KeyEvents, you need to create a stream and then add
+ * KeyEvents to the stream, rather than using the [EventTarget.dispatchEvent].
+ * Here's an example usage:
+ *
+ * // Initialize a stream for the KeyEvents:
+ * var stream = KeyEvent.keyPressEvent.forTarget(document.body);
+ * // Start listening to the stream of KeyEvents.
+ * stream.listen((keyEvent) =>
+ * window.console.log('KeyPress event detected ${keyEvent.charCode}'));
+ * ...
+ * // Add a new KeyEvent of someone pressing the 'A' key to the stream so
+ * // listeners can know a KeyEvent happened.
+ * stream.add(new KeyEvent('keypress', keyCode: 65, charCode: 97));
+ *
+ * This class is very much a work in progress, and we'd love to get information
+ * on how we can make this class work with as many international keyboards as
+ * possible. Bugs welcome!
+ */
+class KeyEvent extends _WrappedEvent implements KeyboardEvent {
+ /** The parent KeyboardEvent that this KeyEvent is wrapping and "fixing". */
+ KeyboardEvent _parent;
+
+ /** The "fixed" value of whether the alt key is being pressed. */
+ bool _shadowAltKey;
+
+ /** Calculated value of what the estimated charCode is for this event. */
+ int _shadowCharCode;
+
+ /** Calculated value of what the estimated keyCode is for this event. */
+ int _shadowKeyCode;
+
+ /** Calculated value of what the estimated keyCode is for this event. */
+ int get keyCode => _shadowKeyCode;
+
+ /** Calculated value of what the estimated charCode is for this event. */
+ int get charCode => this.type == 'keypress' ? _shadowCharCode : 0;
+
+ /** Calculated value of whether the alt key is pressed is for this event. */
+ bool get altKey => _shadowAltKey;
+
+ /** Calculated value of what the estimated keyCode is for this event. */
+ int get which => keyCode;
+
+ /** Accessor to the underlying keyCode value is the parent event. */
+ int get _realKeyCode => JS('int', '#.keyCode', _parent);
+
+ /** Accessor to the underlying charCode value is the parent event. */
+ int get _realCharCode => JS('int', '#.charCode', _parent);
+
+ /** Accessor to the underlying altKey value is the parent event. */
+ bool get _realAltKey => JS('bool', '#.altKey', _parent);
+
+ /** Shadows on top of the parent's currentTarget. */
+ EventTarget _currentTarget;
+
+ final InputDeviceCapabilities sourceCapabilities;
+
+ /**
+ * The value we want to use for this object's dispatch. Created here so it is
+ * only invoked once.
+ */
+ static final _keyboardEventDispatchRecord = _makeRecord();
+
+ /** Helper to statically create the dispatch record. */
+ static _makeRecord() {
+ var interceptor = JS_INTERCEPTOR_CONSTANT(KeyboardEvent);
+ return makeLeafDispatchRecord(interceptor);
+ }
+
+ /** Construct a KeyEvent with [parent] as the event we're emulating. */
+ KeyEvent.wrap(KeyboardEvent parent) : super(parent) {
+ _parent = parent;
+ _shadowAltKey = _realAltKey;
+ _shadowCharCode = _realCharCode;
+ _shadowKeyCode = _realKeyCode;
+ _currentTarget = _parent.currentTarget;
+ }
+
+ /** Programmatically create a new KeyEvent (and KeyboardEvent). */
+ factory KeyEvent(String type,
+ {Window view,
+ bool canBubble: true,
+ bool cancelable: true,
+ int keyCode: 0,
+ int charCode: 0,
+ int location: 1,
+ bool ctrlKey: false,
+ bool altKey: false,
+ bool shiftKey: false,
+ bool metaKey: false,
+ EventTarget currentTarget}) {
+ if (view == null) {
+ view = window;
+ }
+
+ var eventObj;
+
+ // Currently this works on everything but Safari. Safari throws an
+ // "Attempting to change access mechanism for an unconfigurable property"
+ // TypeError when trying to do the Object.defineProperty hack, so we avoid
+ // this branch if possible.
+ // Also, if we want this branch to work in FF, we also need to modify
+ // _initKeyboardEvent to also take charCode and keyCode values to
+ // initialize initKeyEvent.
+
+ eventObj = new Event.eventType('KeyboardEvent', type,
+ canBubble: canBubble, cancelable: cancelable);
+
+ // Chromium Hack
+ JS(
+ 'void',
+ "Object.defineProperty(#, 'keyCode', {"
+ " get : function() { return this.keyCodeVal; } })",
+ eventObj);
+ JS(
+ 'void',
+ "Object.defineProperty(#, 'which', {"
+ " get : function() { return this.keyCodeVal; } })",
+ eventObj);
+ JS(
+ 'void',
+ "Object.defineProperty(#, 'charCode', {"
+ " get : function() { return this.charCodeVal; } })",
+ eventObj);
+
+ var keyIdentifier = _convertToHexString(charCode, keyCode);
+ eventObj._initKeyboardEvent(type, canBubble, cancelable, view,
+ keyIdentifier, location, ctrlKey, altKey, shiftKey, metaKey);
+ JS('void', '#.keyCodeVal = #', eventObj, keyCode);
+ JS('void', '#.charCodeVal = #', eventObj, charCode);
+
+ // Tell dart2js that it smells like a KeyboardEvent!
+ setDispatchProperty(eventObj, _keyboardEventDispatchRecord);
+
+ var keyEvent = new KeyEvent.wrap(eventObj);
+ if (keyEvent._currentTarget == null) {
+ keyEvent._currentTarget = currentTarget == null ? window : currentTarget;
+ }
+ return keyEvent;
+ }
+
+ // Currently known to work on all browsers but IE.
+ static bool get canUseDispatchEvent => JS(
+ 'bool',
+ '(typeof document.body.dispatchEvent == "function")'
+ '&& document.body.dispatchEvent.length > 0');
+
+ /** The currently registered target for this event. */
+ EventTarget get currentTarget => _currentTarget;
+
+ // This is an experimental method to be sure.
+ static String _convertToHexString(int charCode, int keyCode) {
+ if (charCode != -1) {
+ var hex = charCode.toRadixString(16); // Convert to hexadecimal.
+ StringBuffer sb = new StringBuffer('U+');
+ for (int i = 0; i < 4 - hex.length; i++) sb.write('0');
+ sb.write(hex);
+ return sb.toString();
+ } else {
+ return KeyCode._convertKeyCodeToKeyName(keyCode);
+ }
+ }
+
+ // TODO(efortuna): If KeyEvent is sufficiently successful that we want to make
+ // it the default keyboard event handling, move these methods over to Element.
+ /** Accessor to provide a stream of KeyEvents on the desired target. */
+ static EventStreamProvider<KeyEvent> keyDownEvent =
+ new _KeyboardEventHandler('keydown');
+ /** Accessor to provide a stream of KeyEvents on the desired target. */
+ static EventStreamProvider<KeyEvent> keyUpEvent =
+ new _KeyboardEventHandler('keyup');
+ /** Accessor to provide a stream of KeyEvents on the desired target. */
+ static EventStreamProvider<KeyEvent> keyPressEvent =
+ new _KeyboardEventHandler('keypress');
+
+ String get code => _parent.code;
+ /** True if the ctrl key is pressed during this event. */
+ bool get ctrlKey => _parent.ctrlKey;
+ int get detail => _parent.detail;
+ bool get isComposing => _parent.isComposing;
+ String get key => _parent.key;
+ /**
+ * Accessor to the part of the keyboard that the key was pressed from (one of
+ * KeyLocation.STANDARD, KeyLocation.RIGHT, KeyLocation.LEFT,
+ * KeyLocation.NUMPAD, KeyLocation.MOBILE, KeyLocation.JOYSTICK).
+ */
+ int get location => _parent.location;
+ /** True if the Meta (or Mac command) key is pressed during this event. */
+ bool get metaKey => _parent.metaKey;
+ /** True if the shift key was pressed during this event. */
+ bool get shiftKey => _parent.shiftKey;
+ Window get view => _parent.view;
+ void _initUIEvent(
+ String type, bool canBubble, bool cancelable, Window view, int detail) {
+ throw new UnsupportedError("Cannot initialize a UI Event from a KeyEvent.");
+ }
+
+ String get _shadowKeyIdentifier => JS('String', '#.keyIdentifier', _parent);
+
+ int get _charCode => charCode;
+ int get _keyCode => keyCode;
+ int get _which => which;
+
+ String get _keyIdentifier {
+ throw new UnsupportedError("keyIdentifier is unsupported.");
+ }
+
+ void _initKeyboardEvent(
+ String type,
+ bool canBubble,
+ bool cancelable,
+ Window view,
+ String keyIdentifier,
+ int location,
+ bool ctrlKey,
+ bool altKey,
+ bool shiftKey,
+ bool metaKey) {
+ throw new UnsupportedError(
+ "Cannot initialize a KeyboardEvent from a KeyEvent.");
+ }
+
+ bool getModifierState(String keyArgument) => throw new UnimplementedError();
+
+ bool get repeat => throw new UnimplementedError();
+ bool get isComposed => throw new UnimplementedError();
+ dynamic get _get_view => throw new UnimplementedError();
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Platform {
+ /**
+ * Returns true if dart:typed_data types are supported on this
+ * browser. If false, using these types will generate a runtime
+ * error.
+ */
+ static final supportsTypedData = JS('bool', '!!(window.ArrayBuffer)');
+
+ /**
+ * Returns true if SIMD types in dart:typed_data types are supported
+ * on this browser. If false, using these types will generate a runtime
+ * error.
+ */
+ static final supportsSimd = false;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Helper class to implement custom events which wrap DOM events.
+ */
+class _WrappedEvent implements Event {
+ final Event wrapped;
+
+ /** The CSS selector involved with event delegation. */
+ String _selector;
+
+ _WrappedEvent(this.wrapped);
+
+ bool get bubbles => wrapped.bubbles;
+
+ bool get cancelable => wrapped.cancelable;
+
+ bool get composed => wrapped.composed;
+
+ EventTarget get currentTarget => wrapped.currentTarget;
+
+ bool get defaultPrevented => wrapped.defaultPrevented;
+
+ int get eventPhase => wrapped.eventPhase;
+
+ bool get isTrusted => wrapped.isTrusted;
+
+ EventTarget get target => wrapped.target;
+
+ double get timeStamp => wrapped.timeStamp;
+
+ String get type => wrapped.type;
+
+ void _initEvent(String type, [bool bubbles, bool cancelable]) {
+ throw new UnsupportedError('Cannot initialize this Event.');
+ }
+
+ void preventDefault() {
+ wrapped.preventDefault();
+ }
+
+ void stopImmediatePropagation() {
+ wrapped.stopImmediatePropagation();
+ }
+
+ void stopPropagation() {
+ wrapped.stopPropagation();
+ }
+
+ List<EventTarget> composedPath() => wrapped.composedPath();
+
+ /**
+ * A pointer to the element whose CSS selector matched within which an event
+ * was fired. If this Event was not associated with any Event delegation,
+ * accessing this value will throw an [UnsupportedError].
+ */
+ Element get matchingTarget {
+ if (_selector == null) {
+ throw new UnsupportedError('Cannot call matchingTarget if this Event did'
+ ' not arise as a result of event delegation.');
+ }
+ Element currentTarget = this.currentTarget;
+ Element target = this.target;
+ var matchedTarget;
+ do {
+ if (target.matches(_selector)) return target;
+ target = target.parent;
+ } while (target != null && target != currentTarget.parent);
+ throw new StateError('No selector matched for populating matchedTarget.');
+ }
+
+ /**
+ * This event's path, taking into account shadow DOM.
+ *
+ * ## Other resources
+ *
+ * * [Shadow DOM extensions to
+ * Event](http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-event)
+ * from W3C.
+ */
+ // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#extensions-to-event
+ List<Node> get path => wrapped.path;
+
+ dynamic get _get_currentTarget => wrapped._get_currentTarget;
+
+ dynamic get _get_target => wrapped._get_target;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void Function(T) _wrapZone<T>(void Function(T) callback) {
+ // For performance reasons avoid wrapping if we are in the root zone.
+ if (Zone.current == Zone.root) return callback;
+ if (callback == null) return null;
+ return Zone.current.bindUnaryCallbackGuarded(callback);
+}
+
+void Function(T1, T2) _wrapBinaryZone<T1, T2>(void Function(T1, T2) callback) {
+ // For performance reasons avoid wrapping if we are in the root zone.
+ if (Zone.current == Zone.root) return callback;
+ if (callback == null) return null;
+ return Zone.current.bindBinaryCallbackGuarded(callback);
+}
+
+/**
+ * Finds the first descendant element of this document that matches the
+ * specified group of selectors.
+ *
+ * Unless your webpage contains multiple documents, the top-level
+ * [querySelector]
+ * method behaves the same as this method, so you should use it instead to
+ * save typing a few characters.
+ *
+ * [selectors] should be a string using CSS selector syntax.
+ *
+ * var element1 = document.querySelector('.className');
+ * var element2 = document.querySelector('#id');
+ *
+ * For details about CSS selector syntax, see the
+ * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+ */
+Element querySelector(String selectors) => document.querySelector(selectors);
+
+/**
+ * Finds all descendant elements of this document that match the specified
+ * group of selectors.
+ *
+ * Unless your webpage contains multiple documents, the top-level
+ * [querySelectorAll]
+ * method behaves the same as this method, so you should use it instead to
+ * save typing a few characters.
+ *
+ * [selectors] should be a string using CSS selector syntax.
+ *
+ * var items = document.querySelectorAll('.itemClassName');
+ *
+ * For details about CSS selector syntax, see the
+ * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
+ */
+ElementList<T> querySelectorAll<T extends Element>(String selectors) =>
+ document.querySelectorAll(selectors);
+
+/// A utility for changing the Dart wrapper type for elements.
+abstract class ElementUpgrader {
+ /// Upgrade the specified element to be of the Dart type this was created for.
+ ///
+ /// After upgrading the element passed in is invalid and the returned value
+ /// should be used instead.
+ Element upgrade(Element element);
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Interface used to validate that only accepted elements and attributes are
+ * allowed while parsing HTML strings into DOM nodes.
+ *
+ * In general, customization of validation behavior should be done via the
+ * [NodeValidatorBuilder] class to mitigate the chances of incorrectly
+ * implementing validation rules.
+ */
+abstract class NodeValidator {
+ /**
+ * Construct a default NodeValidator which only accepts whitelisted HTML5
+ * elements and attributes.
+ *
+ * If a uriPolicy is not specified then the default uriPolicy will be used.
+ */
+ factory NodeValidator({UriPolicy uriPolicy}) =>
+ new _Html5NodeValidator(uriPolicy: uriPolicy);
+
+ factory NodeValidator.throws(NodeValidator base) =>
+ new _ThrowsNodeValidator(base);
+
+ /**
+ * Returns true if the tagName is an accepted type.
+ */
+ bool allowsElement(Element element);
+
+ /**
+ * Returns true if the attribute is allowed.
+ *
+ * The attributeName parameter will always be in lowercase.
+ *
+ * See [allowsElement] for format of tagName.
+ */
+ bool allowsAttribute(Element element, String attributeName, String value);
+}
+
+/**
+ * Performs sanitization of a node tree after construction to ensure that it
+ * does not contain any disallowed elements or attributes.
+ *
+ * In general custom implementations of this class should not be necessary and
+ * all validation customization should be done in custom NodeValidators, but
+ * custom implementations of this class can be created to perform more complex
+ * tree sanitization.
+ */
+abstract class NodeTreeSanitizer {
+ /**
+ * Constructs a default tree sanitizer which will remove all elements and
+ * attributes which are not allowed by the provided validator.
+ */
+ factory NodeTreeSanitizer(NodeValidator validator) =>
+ new _ValidatingTreeSanitizer(validator);
+
+ /**
+ * Called with the root of the tree which is to be sanitized.
+ *
+ * This method needs to walk the entire tree and either remove elements and
+ * attributes which are not recognized as safe or throw an exception which
+ * will mark the entire tree as unsafe.
+ */
+ void sanitizeTree(Node node);
+
+ /**
+ * A sanitizer for trees that we trust. It does no validation and allows
+ * any elements. It is also more efficient, since it can pass the text
+ * directly through to the underlying APIs without creating a document
+ * fragment to be sanitized.
+ */
+ static const trusted = const _TrustedHtmlTreeSanitizer();
+}
+
+/**
+ * A sanitizer for trees that we trust. It does no validation and allows
+ * any elements.
+ */
+class _TrustedHtmlTreeSanitizer implements NodeTreeSanitizer {
+ const _TrustedHtmlTreeSanitizer();
+
+ sanitizeTree(Node node) {}
+}
+
+/**
+ * Defines the policy for what types of uris are allowed for particular
+ * attribute values.
+ *
+ * This can be used to provide custom rules such as allowing all http:// URIs
+ * for image attributes but only same-origin URIs for anchor tags.
+ */
+abstract class UriPolicy {
+ /**
+ * Constructs the default UriPolicy which is to only allow Uris to the same
+ * origin as the application was launched from.
+ *
+ * This will block all ftp: mailto: URIs. It will also block accessing
+ * https://example.com if the app is running from http://example.com.
+ */
+ factory UriPolicy() => new _SameOriginUriPolicy();
+
+ /**
+ * Checks if the uri is allowed on the specified attribute.
+ *
+ * The uri provided may or may not be a relative path.
+ */
+ bool allowsUri(String uri);
+}
+
+/**
+ * Allows URIs to the same origin as the current application was loaded from
+ * (such as https://example.com:80).
+ */
+class _SameOriginUriPolicy implements UriPolicy {
+ final AnchorElement _hiddenAnchor = new AnchorElement();
+ final Location _loc = window.location;
+
+ bool allowsUri(String uri) {
+ _hiddenAnchor.href = uri;
+ // IE leaves an empty hostname for same-origin URIs.
+ return (_hiddenAnchor.hostname == _loc.hostname &&
+ _hiddenAnchor.port == _loc.port &&
+ _hiddenAnchor.protocol == _loc.protocol) ||
+ (_hiddenAnchor.hostname == '' &&
+ _hiddenAnchor.port == '' &&
+ (_hiddenAnchor.protocol == ':' || _hiddenAnchor.protocol == ''));
+ }
+}
+
+class _ThrowsNodeValidator implements NodeValidator {
+ final NodeValidator validator;
+
+ _ThrowsNodeValidator(this.validator) {}
+
+ bool allowsElement(Element element) {
+ if (!validator.allowsElement(element)) {
+ throw new ArgumentError(Element._safeTagName(element));
+ }
+ return true;
+ }
+
+ bool allowsAttribute(Element element, String attributeName, String value) {
+ if (!validator.allowsAttribute(element, attributeName, value)) {
+ throw new ArgumentError(
+ '${Element._safeTagName(element)}[$attributeName="$value"]');
+ }
+ }
+}
+
+/**
+ * Standard tree sanitizer which validates a node tree against the provided
+ * validator and removes any nodes or attributes which are not allowed.
+ */
+class _ValidatingTreeSanitizer implements NodeTreeSanitizer {
+ NodeValidator validator;
+ _ValidatingTreeSanitizer(this.validator) {}
+
+ void sanitizeTree(Node node) {
+ void walk(Node node, Node parent) {
+ sanitizeNode(node, parent);
+
+ var child = node.lastChild;
+ while (null != child) {
+ var nextChild;
+ try {
+ // Child may be removed during the walk, and we may not
+ // even be able to get its previousNode.
+ nextChild = child.previousNode;
+ } catch (e) {
+ // Child appears bad, remove it. We want to check the rest of the
+ // children of node and, but we have no way of getting to the next
+ // child, so start again from the last child.
+ _removeNode(child, node);
+ child = null;
+ nextChild = node.lastChild;
+ }
+ if (child != null) walk(child, node);
+ child = nextChild;
+ }
+ }
+
+ walk(node, null);
+ }
+
+ /// Aggressively try to remove node.
+ void _removeNode(Node node, Node parent) {
+ // If we have the parent, it's presumably already passed more sanitization
+ // or is the fragment, so ask it to remove the child. And if that fails
+ // try to set the outer html.
+ if (parent == null) {
+ node.remove();
+ } else {
+ parent._removeChild(node);
+ }
+ }
+
+ /// Sanitize the element, assuming we can't trust anything about it.
+ void _sanitizeUntrustedElement(/* Element */ element, Node parent) {
+ // If the _hasCorruptedAttributes does not successfully return false,
+ // then we consider it corrupted and remove.
+ // TODO(alanknight): This is a workaround because on Firefox
+ // embed/object
+ // tags typeof is "function", not "object". We don't recognize them, and
+ // can't call methods. This does mean that you can't explicitly allow an
+ // embed tag. The only thing that will let it through is a null
+ // sanitizer that doesn't traverse the tree at all. But sanitizing while
+ // allowing embeds seems quite unlikely. This is also the reason that we
+ // can't declare the type of element, as an embed won't pass any type
+ // check in dart2js.
+ var corrupted = true;
+ var attrs;
+ var isAttr;
+ try {
+ // If getting/indexing attributes throws, count that as corrupt.
+ attrs = element.attributes;
+ isAttr = attrs['is'];
+ var corruptedTest1 = Element._hasCorruptedAttributes(element);
+
+ // On IE, erratically, the hasCorruptedAttributes test can return false,
+ // even though it clearly is corrupted. A separate copy of the test
+ // inlining just the basic check seems to help.
+ corrupted = corruptedTest1
+ ? true
+ : Element._hasCorruptedAttributesAdditionalCheck(element);
+ } catch (e) {}
+ var elementText = 'element unprintable';
+ try {
+ elementText = element.toString();
+ } catch (e) {}
+ try {
+ var elementTagName = Element._safeTagName(element);
+ _sanitizeElement(element, parent, corrupted, elementText, elementTagName,
+ attrs, isAttr);
+ } on ArgumentError {
+ // Thrown by _ThrowsNodeValidator
+ rethrow;
+ } catch (e) {
+ // Unexpected exception sanitizing -> remove
+ _removeNode(element, parent);
+ window.console.warn('Removing corrupted element $elementText');
+ }
+ }
+
+ /// Having done basic sanity checking on the element, and computed the
+ /// important attributes we want to check, remove it if it's not valid
+ /// or not allowed, either as a whole or particular attributes.
+ void _sanitizeElement(Element element, Node parent, bool corrupted,
+ String text, String tag, Map attrs, String isAttr) {
+ if (false != corrupted) {
+ _removeNode(element, parent);
+ window.console
+ .warn('Removing element due to corrupted attributes on <$text>');
+ return;
+ }
+ if (!validator.allowsElement(element)) {
+ _removeNode(element, parent);
+ window.console.warn('Removing disallowed element <$tag> from $parent');
+ return;
+ }
+
+ if (isAttr != null) {
+ if (!validator.allowsAttribute(element, 'is', isAttr)) {
+ _removeNode(element, parent);
+ window.console.warn('Removing disallowed type extension '
+ '<$tag is="$isAttr">');
+ return;
+ }
+ }
+
+ // TODO(blois): Need to be able to get all attributes, irrespective of
+ // XMLNS.
+ var keys = attrs.keys.toList();
+ for (var i = attrs.length - 1; i >= 0; --i) {
+ var name = keys[i];
+ if (!validator.allowsAttribute(
+ element, name.toLowerCase(), attrs[name])) {
+ window.console.warn('Removing disallowed attribute '
+ '<$tag $name="${attrs[name]}">');
+ attrs.remove(name);
+ }
+ }
+
+ if (element is TemplateElement) {
+ TemplateElement template = element;
+ sanitizeTree(template.content);
+ }
+ }
+
+ /// Sanitize the node and its children recursively.
+ void sanitizeNode(Node node, Node parent) {
+ switch (node.nodeType) {
+ case Node.ELEMENT_NODE:
+ _sanitizeUntrustedElement(node, parent);
+ break;
+ case Node.COMMENT_NODE:
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ break;
+ default:
+ _removeNode(node, parent);
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/html/dartium/nativewrappers.dart b/sdk_nnbd/lib/html/dartium/nativewrappers.dart
new file mode 100644
index 0000000..b6d2dc4
--- /dev/null
+++ b/sdk_nnbd/lib/html/dartium/nativewrappers.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library nativewrappers;
+
+class NativeFieldWrapperClass1 {}
+
+class NativeFieldWrapperClass2 {}
+
+class NativeFieldWrapperClass3 {}
+
+class NativeFieldWrapperClass4 {}
diff --git a/sdk_nnbd/lib/html/html_common/conversions.dart b/sdk_nnbd/lib/html/html_common/conversions.dart
new file mode 100644
index 0000000..4c31efb
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/conversions.dart
@@ -0,0 +1,359 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Conversions for IDBKey.
+//
+// Per http://www.w3.org/TR/IndexedDB/#key-construct
+//
+// "A value is said to be a valid key if it is one of the following types: Array
+// JavaScript objects [ECMA-262], DOMString [WEBIDL], Date [ECMA-262] or float
+// [WEBIDL]. However Arrays are only valid keys if every item in the array is
+// defined and is a valid key (i.e. sparse arrays can not be valid keys) and if
+// the Array doesn't directly or indirectly contain itself. Any non-numeric
+// properties are ignored, and thus does not affect whether the Array is a valid
+// key. Additionally, if the value is of type float, it is only a valid key if
+// it is not NaN, and if the value is of type Date it is only a valid key if its
+// [[PrimitiveValue]] internal property, as defined by [ECMA-262], is not NaN."
+
+// What is required is to ensure that an Lists in the key are actually
+// JavaScript arrays, and any Dates are JavaScript Dates.
+
+// Conversions for Window. These check if the window is the local
+// window, and if it's not, wraps or unwraps it with a secure wrapper.
+// We need to test for EventTarget here as well as it's a base type.
+// We omit an unwrapper for Window as no methods take a non-local
+// window as a parameter.
+
+part of html_common;
+
+/// Converts a Dart value into a JavaScript SerializedScriptValue.
+convertDartToNative_SerializedScriptValue(value) {
+ return convertDartToNative_PrepareForStructuredClone(value);
+}
+
+/// Since the source object may be viewed via a JavaScript event listener the
+/// original may not be modified.
+convertNativeToDart_SerializedScriptValue(object) {
+ return convertNativeToDart_AcceptStructuredClone(object, mustCopy: true);
+}
+
+/**
+ * Converts a Dart value into a JavaScript SerializedScriptValue. Returns the
+ * original input or a functional 'copy'. Does not mutate the original.
+ *
+ * The main transformation is the translation of Dart Maps are converted to
+ * JavaScript Objects.
+ *
+ * The algorithm is essentially a dry-run of the structured clone algorithm
+ * described at
+ * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#structured-clone
+ * https://www.khronos.org/registry/typedarray/specs/latest/#9
+ *
+ * Since the result of this function is expected to be passed only to JavaScript
+ * operations that perform the structured clone algorithm which does not mutate
+ * its output, the result may share structure with the input [value].
+ */
+abstract class _StructuredClone {
+ // TODO(sra): Replace slots with identity hash table.
+ var values = [];
+ var copies = []; // initially 'null', 'true' during initial DFS, then a copy.
+
+ int findSlot(value) {
+ int length = values.length;
+ for (int i = 0; i < length; i++) {
+ if (identical(values[i], value)) return i;
+ }
+ values.add(value);
+ copies.add(null);
+ return length;
+ }
+
+ readSlot(int i) => copies[i];
+ writeSlot(int i, x) {
+ copies[i] = x;
+ }
+
+ cleanupSlots() {} // Will be needed if we mark objects with a property.
+ bool cloneNotRequired(object);
+ newJsMap();
+ List newJsList(length);
+ void putIntoMap(map, key, value);
+
+ // Returns the input, or a clone of the input.
+ walk(e) {
+ if (e == null) return e;
+ if (e is bool) return e;
+ if (e is num) return e;
+ if (e is String) return e;
+ if (e is DateTime) {
+ return convertDartToNative_DateTime(e);
+ }
+ if (e is RegExp) {
+ // TODO(sra).
+ throw new UnimplementedError('structured clone of RegExp');
+ }
+
+ // The browser's internal structured cloning algorithm will copy certain
+ // types of object, but it will copy only its own implementations and not
+ // just any Dart implementations of the interface.
+
+ // TODO(sra): The JavaScript objects suitable for direct cloning by the
+ // structured clone algorithm could be tagged with an private interface.
+
+ if (e is File) return e;
+ if (e is Blob) return e;
+ if (e is FileList) return e;
+
+ // TODO(sra): Firefox: How to convert _TypedImageData on the other end?
+ if (e is ImageData) return e;
+ if (cloneNotRequired(e)) return e;
+
+ if (e is Map) {
+ var slot = findSlot(e);
+ var copy = readSlot(slot);
+ if (copy != null) return copy;
+ copy = newJsMap();
+ writeSlot(slot, copy);
+ e.forEach((key, value) {
+ putIntoMap(copy, key, walk(value));
+ });
+ return copy;
+ }
+
+ if (e is List) {
+ // Since a JavaScript Array is an instance of Dart List it is tempting
+ // in dart2js to avoid making a copy of the list if there is no need
+ // to copy anything reachable from the array. However, the list may have
+ // non-native properties or methods from interceptors and such, e.g.
+ // an immutability marker. So we had to stop doing that.
+ var slot = findSlot(e);
+ var copy = JS('returns:List|Null;creates:;', '#', readSlot(slot));
+ if (copy != null) return copy;
+ copy = copyList(e, slot);
+ return copy;
+ }
+
+ throw new UnimplementedError('structured clone of other type');
+ }
+
+ List copyList(List e, int slot) {
+ int i = 0;
+ int length = e.length;
+ var copy = newJsList(length);
+ writeSlot(slot, copy);
+ for (; i < length; i++) {
+ copy[i] = walk(e[i]);
+ }
+ return copy;
+ }
+
+ convertDartToNative_PrepareForStructuredClone(value) {
+ var copy = walk(value);
+ cleanupSlots();
+ return copy;
+ }
+}
+
+/**
+ * Converts a native value into a Dart object.
+ *
+ * If [mustCopy] is [:false:], may return the original input. May mutate the
+ * original input (but will be idempotent if mutation occurs). It is assumed
+ * that this conversion happens on native serializable script values such values
+ * from native DOM calls.
+ *
+ * [object] is the result of a structured clone operation.
+ *
+ * If necessary, JavaScript Dates are converted into Dart Dates.
+ *
+ * If [mustCopy] is [:true:], the entire object is copied and the original input
+ * is not mutated. This should be the case where Dart and JavaScript code can
+ * access the value, for example, via multiple event listeners for
+ * MessageEvents. Mutating the object to make it more 'Dart-like' would corrupt
+ * the value as seen from the JavaScript listeners.
+ */
+abstract class _AcceptStructuredClone {
+ // TODO(sra): Replace slots with identity hash table.
+ var values = [];
+ var copies = []; // initially 'null', 'true' during initial DFS, then a copy.
+ bool mustCopy = false;
+
+ int findSlot(value) {
+ int length = values.length;
+ for (int i = 0; i < length; i++) {
+ if (identicalInJs(values[i], value)) return i;
+ }
+ values.add(value);
+ copies.add(null);
+ return length;
+ }
+
+ /// Are the two objects identical, but taking into account that two JsObject
+ /// wrappers may not be identical, but their underlying Js Object might be.
+ bool identicalInJs(a, b);
+ readSlot(int i) => copies[i];
+ writeSlot(int i, x) {
+ copies[i] = x;
+ }
+
+ /// Iterate over the JS properties.
+ forEachJsField(object, action(key, value));
+
+ /// Create a new Dart list of the given length. May create a native List or
+ /// a JsArray, depending if we're in Dartium or dart2js.
+ List newDartList(length);
+
+ walk(e) {
+ if (e == null) return e;
+ if (e is bool) return e;
+ if (e is num) return e;
+ if (e is String) return e;
+
+ if (isJavaScriptDate(e)) {
+ return convertNativeToDart_DateTime(e);
+ }
+
+ if (isJavaScriptRegExp(e)) {
+ // TODO(sra).
+ throw new UnimplementedError('structured clone of RegExp');
+ }
+
+ if (isJavaScriptPromise(e)) {
+ return convertNativePromiseToDartFuture(e);
+ }
+
+ if (isJavaScriptSimpleObject(e)) {
+ // TODO(sra): If mustCopy is false, swizzle the prototype for one of a Map
+ // implementation that uses the properties as storage.
+ var slot = findSlot(e);
+ var copy = readSlot(slot);
+ if (copy != null) return copy;
+ copy = {};
+
+ writeSlot(slot, copy);
+ forEachJsField(e, (key, value) => copy[key] = walk(value));
+ return copy;
+ }
+
+ if (isJavaScriptArray(e)) {
+ var l = JS<List>('returns:List;creates:;', '#', e);
+ var slot = findSlot(l);
+ var copy = JS<List>('returns:List|Null;creates:;', '#', readSlot(slot));
+ if (copy != null) return copy;
+
+ int length = l.length;
+ // Since a JavaScript Array is an instance of Dart List, we can modify it
+ // in-place unless we must copy.
+ copy = mustCopy ? newDartList(length) : l;
+ writeSlot(slot, copy);
+
+ for (int i = 0; i < length; i++) {
+ copy[i] = walk(l[i]);
+ }
+ return copy;
+ }
+
+ // Assume anything else is already a valid Dart object, either by having
+ // already been processed, or e.g. a cloneable native class.
+ return e;
+ }
+
+ convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) {
+ this.mustCopy = mustCopy;
+ var copy = walk(object);
+ return copy;
+ }
+}
+
+// Conversions for ContextAttributes.
+//
+// On Firefox, the returned ContextAttributes is a plain object.
+class ContextAttributes {
+ bool alpha;
+ bool antialias;
+ bool depth;
+ bool premultipliedAlpha;
+ bool preserveDrawingBuffer;
+ bool stencil;
+ bool failIfMajorPerformanceCaveat;
+
+ ContextAttributes(
+ this.alpha,
+ this.antialias,
+ this.depth,
+ this.failIfMajorPerformanceCaveat,
+ this.premultipliedAlpha,
+ this.preserveDrawingBuffer,
+ this.stencil);
+}
+
+convertNativeToDart_ContextAttributes(nativeContextAttributes) {
+ // On Firefox the above test fails because ContextAttributes is a plain
+ // object so we create a _TypedContextAttributes.
+
+ return new ContextAttributes(
+ JS('var', '#.alpha', nativeContextAttributes),
+ JS('var', '#.antialias', nativeContextAttributes),
+ JS('var', '#.depth', nativeContextAttributes),
+ JS('var', '#.failIfMajorPerformanceCaveat', nativeContextAttributes),
+ JS('var', '#.premultipliedAlpha', nativeContextAttributes),
+ JS('var', '#.preserveDrawingBuffer', nativeContextAttributes),
+ JS('var', '#.stencil', nativeContextAttributes));
+}
+
+// Conversions for ImageData
+//
+// On Firefox, the returned ImageData is a plain object.
+
+class _TypedImageData implements ImageData {
+ final Uint8ClampedList data;
+ final int height;
+ final int width;
+
+ _TypedImageData(this.data, this.height, this.width);
+}
+
+ImageData convertNativeToDart_ImageData(nativeImageData) {
+ // None of the native getters that return ImageData are declared as returning
+ // [ImageData] since that is incorrect for FireFox, which returns a plain
+ // Object. So we need something that tells the compiler that the ImageData
+ // class has been instantiated.
+ // TODO(sra): Remove this when all the ImageData returning APIs have been
+ // annotated as returning the union ImageData + Object.
+ JS('ImageData', '0');
+
+ if (nativeImageData is ImageData) {
+ // Fix for Issue 16069: on IE, the `data` field is a CanvasPixelArray which
+ // has Array as the constructor property. This interferes with finding the
+ // correct interceptor. Fix it by overwriting the constructor property.
+ var data = nativeImageData.data;
+ if (JS('bool', '#.constructor === Array', data)) {
+ if (JS('bool', 'typeof CanvasPixelArray !== "undefined"')) {
+ JS('void', '#.constructor = CanvasPixelArray', data);
+ // This TypedArray property is missing from CanvasPixelArray.
+ JS('void', '#.BYTES_PER_ELEMENT = 1', data);
+ }
+ }
+
+ return nativeImageData;
+ }
+
+ // On Firefox the above test fails because [nativeImageData] is a plain
+ // object. So we create a _TypedImageData.
+
+ return new _TypedImageData(
+ JS('NativeUint8ClampedList', '#.data', nativeImageData),
+ JS('var', '#.height', nativeImageData),
+ JS('var', '#.width', nativeImageData));
+}
+
+// We can get rid of this conversion if _TypedImageData implements the fields
+// with native names.
+convertDartToNative_ImageData(ImageData imageData) {
+ if (imageData is _TypedImageData) {
+ return JS('', '{data: #, height: #, width: #}', imageData.data,
+ imageData.height, imageData.width);
+ }
+ return imageData;
+}
diff --git a/sdk_nnbd/lib/html/html_common/conversions_dart2js.dart b/sdk_nnbd/lib/html/html_common/conversions_dart2js.dart
new file mode 100644
index 0000000..36153cf
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/conversions_dart2js.dart
@@ -0,0 +1,106 @@
+part of html_common;
+
+/// Converts a JavaScript object with properties into a Dart Map.
+/// Not suitable for nested objects.
+Map<String, dynamic> convertNativeToDart_Dictionary(object) {
+ if (object == null) return null;
+ var dict = <String, dynamic>{};
+ var keys = JS('JSExtendableArray', 'Object.getOwnPropertyNames(#)', object);
+ for (final key in keys) {
+ dict[key] = JS('var', '#[#]', object, key);
+ }
+ return dict;
+}
+
+/// Converts a flat Dart map into a JavaScript object with properties.
+convertDartToNative_Dictionary(Map dict, [void postCreate(Object f)]) {
+ if (dict == null) return null;
+ var object = JS('var', '{}');
+ if (postCreate != null) {
+ postCreate(object);
+ }
+ dict.forEach((key, value) {
+ JS('void', '#[#] = #', object, key, value);
+ });
+ return object;
+}
+
+/**
+ * Ensures that the input is a JavaScript Array.
+ *
+ * Creates a new JavaScript array if necessary, otherwise returns the original.
+ */
+List convertDartToNative_StringArray(List<String> input) {
+ // TODO(sra). Implement this.
+ return input;
+}
+
+DateTime convertNativeToDart_DateTime(date) {
+ var millisSinceEpoch = JS('int', '#.getTime()', date);
+ return new DateTime.fromMillisecondsSinceEpoch(millisSinceEpoch, isUtc: true);
+}
+
+convertDartToNative_DateTime(DateTime date) {
+ return JS('', 'new Date(#)', date.millisecondsSinceEpoch);
+}
+
+convertDartToNative_PrepareForStructuredClone(value) =>
+ new _StructuredCloneDart2Js()
+ .convertDartToNative_PrepareForStructuredClone(value);
+
+convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) =>
+ new _AcceptStructuredCloneDart2Js()
+ .convertNativeToDart_AcceptStructuredClone(object, mustCopy: mustCopy);
+
+class _StructuredCloneDart2Js extends _StructuredClone {
+ newJsMap() => JS('var', '{}');
+ putIntoMap(map, key, value) => JS('void', '#[#] = #', map, key, value);
+ newJsList(length) => JS('JSExtendableArray', 'new Array(#)', length);
+ cloneNotRequired(e) =>
+ (e is NativeByteBuffer || e is NativeTypedData || e is MessagePort);
+}
+
+class _AcceptStructuredCloneDart2Js extends _AcceptStructuredClone {
+ List newJsList(length) => JS('JSExtendableArray', 'new Array(#)', length);
+ List newDartList(length) => newJsList(length);
+ bool identicalInJs(a, b) => identical(a, b);
+
+ void forEachJsField(object, action(key, value)) {
+ for (final key in JS('JSExtendableArray', 'Object.keys(#)', object)) {
+ action(key, JS('var', '#[#]', object, key));
+ }
+ }
+}
+
+bool isJavaScriptDate(value) => JS('bool', '# instanceof Date', value);
+bool isJavaScriptRegExp(value) => JS('bool', '# instanceof RegExp', value);
+bool isJavaScriptArray(value) => JS('bool', '# instanceof Array', value);
+bool isJavaScriptSimpleObject(value) {
+ var proto = JS('', 'Object.getPrototypeOf(#)', value);
+ return JS('bool', '# === Object.prototype', proto) ||
+ JS('bool', '# === null', proto);
+}
+
+bool isImmutableJavaScriptArray(value) =>
+ JS('bool', r'!!(#.immutable$list)', value);
+bool isJavaScriptPromise(value) =>
+ JS('bool', r'typeof Promise != "undefined" && # instanceof Promise', value);
+
+Future convertNativePromiseToDartFuture(promise) {
+ var completer = new Completer();
+ var then = convertDartClosureToJS((result) => completer.complete(result), 1);
+ var error =
+ convertDartClosureToJS((result) => completer.completeError(result), 1);
+ var newPromise = JS('', '#.then(#)["catch"](#)', promise, then, error);
+ return completer.future;
+}
+
+const String _serializedScriptValue = 'num|String|bool|'
+ 'JSExtendableArray|=Object|'
+ 'Blob|File|NativeByteBuffer|NativeTypedData|MessagePort'
+ // TODO(sra): Add Date, RegExp.
+ ;
+const annotation_Creates_SerializedScriptValue =
+ const Creates(_serializedScriptValue);
+const annotation_Returns_SerializedScriptValue =
+ const Returns(_serializedScriptValue);
diff --git a/sdk_nnbd/lib/html/html_common/css_class_set.dart b/sdk_nnbd/lib/html/html_common/css_class_set.dart
new file mode 100644
index 0000000..2286057
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/css_class_set.dart
@@ -0,0 +1,242 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of html_common;
+
+abstract class CssClassSetImpl extends SetBase<String> implements CssClassSet {
+ static final RegExp _validTokenRE = new RegExp(r'^\S+$');
+
+ String _validateToken(String value) {
+ if (_validTokenRE.hasMatch(value)) return value;
+ throw new ArgumentError.value(value, 'value', 'Not a valid class token');
+ }
+
+ String toString() {
+ return readClasses().join(' ');
+ }
+
+ /**
+ * Adds the class [value] to the element if it is not on it, removes it if it
+ * is.
+ *
+ * If [shouldAdd] is true, then we always add that [value] to the element. If
+ * [shouldAdd] is false then we always remove [value] from the element.
+ */
+ bool toggle(String value, [bool shouldAdd]) {
+ _validateToken(value);
+ Set<String> s = readClasses();
+ bool result = false;
+ if (shouldAdd == null) shouldAdd = !s.contains(value);
+ if (shouldAdd) {
+ s.add(value);
+ result = true;
+ } else {
+ s.remove(value);
+ }
+ writeClasses(s);
+ return result;
+ }
+
+ /**
+ * Returns [:true:] if classes cannot be added or removed from this
+ * [:CssClassSet:].
+ */
+ bool get frozen => false;
+
+ // interface Iterable - BEGIN
+ Iterator<String> get iterator => readClasses().iterator;
+ // interface Iterable - END
+
+ // interface Collection - BEGIN
+ void forEach(void f(String element)) {
+ readClasses().forEach(f);
+ }
+
+ String join([String separator = ""]) => readClasses().join(separator);
+
+ Iterable<T> map<T>(T f(String e)) => readClasses().map<T>(f);
+
+ Iterable<String> where(bool f(String element)) => readClasses().where(f);
+
+ Iterable<T> expand<T>(Iterable<T> f(String element)) =>
+ readClasses().expand<T>(f);
+
+ bool every(bool f(String element)) => readClasses().every(f);
+
+ bool any(bool f(String element)) => readClasses().any(f);
+
+ bool get isEmpty => readClasses().isEmpty;
+
+ bool get isNotEmpty => readClasses().isNotEmpty;
+
+ int get length => readClasses().length;
+
+ String reduce(String combine(String value, String element)) {
+ return readClasses().reduce(combine);
+ }
+
+ T fold<T>(T initialValue, T combine(T previousValue, String element)) {
+ return readClasses().fold<T>(initialValue, combine);
+ }
+
+ // interface Collection - END
+
+ // interface Set - BEGIN
+ /**
+ * Determine if this element contains the class [value].
+ *
+ * This is the Dart equivalent of jQuery's
+ * [hasClass](http://api.jquery.com/hasClass/).
+ */
+ bool contains(Object value) {
+ if (value is! String) return false;
+ _validateToken(value);
+ return readClasses().contains(value);
+ }
+
+ /** Lookup from the Set interface. Not interesting for a String set. */
+ String lookup(Object value) => contains(value) ? value : null;
+
+ /**
+ * Add the class [value] to element.
+ *
+ * This is the Dart equivalent of jQuery's
+ * [addClass](http://api.jquery.com/addClass/).
+ */
+ bool add(String value) {
+ _validateToken(value);
+ // TODO - figure out if we need to do any validation here
+ // or if the browser natively does enough.
+ return modify((s) => s.add(value));
+ }
+
+ /**
+ * Remove the class [value] from element, and return true on successful
+ * removal.
+ *
+ * This is the Dart equivalent of jQuery's
+ * [removeClass](http://api.jquery.com/removeClass/).
+ */
+ bool remove(Object value) {
+ _validateToken(value);
+ if (value is! String) return false;
+ Set<String> s = readClasses();
+ bool result = s.remove(value);
+ writeClasses(s);
+ return result;
+ }
+
+ /**
+ * Add all classes specified in [iterable] to element.
+ *
+ * This is the Dart equivalent of jQuery's
+ * [addClass](http://api.jquery.com/addClass/).
+ */
+ void addAll(Iterable<String> iterable) {
+ // TODO - see comment above about validation.
+ modify((s) => s.addAll(iterable.map(_validateToken)));
+ }
+
+ /**
+ * Remove all classes specified in [iterable] from element.
+ *
+ * This is the Dart equivalent of jQuery's
+ * [removeClass](http://api.jquery.com/removeClass/).
+ */
+ void removeAll(Iterable<Object> iterable) {
+ modify((s) => s.removeAll(iterable));
+ }
+
+ /**
+ * Toggles all classes specified in [iterable] on element.
+ *
+ * Iterate through [iterable]'s items, and add it if it is not on it, or
+ * remove it if it is. This is the Dart equivalent of jQuery's
+ * [toggleClass](http://api.jquery.com/toggleClass/).
+ * If [shouldAdd] is true, then we always add all the classes in [iterable]
+ * element. If [shouldAdd] is false then we always remove all the classes in
+ * [iterable] from the element.
+ */
+ void toggleAll(Iterable<String> iterable, [bool shouldAdd]) {
+ iterable.forEach((e) => toggle(e, shouldAdd));
+ }
+
+ void retainAll(Iterable<Object> iterable) {
+ modify((s) => s.retainAll(iterable));
+ }
+
+ void removeWhere(bool test(String name)) {
+ modify((s) => s.removeWhere(test));
+ }
+
+ void retainWhere(bool test(String name)) {
+ modify((s) => s.retainWhere(test));
+ }
+
+ bool containsAll(Iterable<Object> collection) =>
+ readClasses().containsAll(collection);
+
+ Set<String> intersection(Set<Object> other) =>
+ readClasses().intersection(other);
+
+ Set<String> union(Set<String> other) => readClasses().union(other);
+
+ Set<String> difference(Set<Object> other) => readClasses().difference(other);
+
+ String get first => readClasses().first;
+ String get last => readClasses().last;
+ String get single => readClasses().single;
+ List<String> toList({bool growable: true}) =>
+ readClasses().toList(growable: growable);
+ Set<String> toSet() => readClasses().toSet();
+ Iterable<String> take(int n) => readClasses().take(n);
+ Iterable<String> takeWhile(bool test(String value)) =>
+ readClasses().takeWhile(test);
+ Iterable<String> skip(int n) => readClasses().skip(n);
+ Iterable<String> skipWhile(bool test(String value)) =>
+ readClasses().skipWhile(test);
+ String firstWhere(bool test(String value), {String orElse()}) =>
+ readClasses().firstWhere(test, orElse: orElse);
+ String lastWhere(bool test(String value), {String orElse()}) =>
+ readClasses().lastWhere(test, orElse: orElse);
+ String singleWhere(bool test(String value), {String orElse()}) =>
+ readClasses().singleWhere(test, orElse: orElse);
+ String elementAt(int index) => readClasses().elementAt(index);
+
+ void clear() {
+ // TODO(sra): Do this without reading the classes.
+ modify((s) => s.clear());
+ }
+ // interface Set - END
+
+ /**
+ * Helper method used to modify the set of css classes on this element.
+ *
+ * f - callback with:
+ * s - a Set of all the css class name currently on this element.
+ *
+ * After f returns, the modified set is written to the
+ * className property of this element.
+ */
+ modify(f(Set<String> s)) {
+ Set<String> s = readClasses();
+ var ret = f(s);
+ writeClasses(s);
+ return ret;
+ }
+
+ /**
+ * Read the class names from the Element class property,
+ * and put them into a set (duplicates are discarded).
+ * This is intended to be overridden by specific implementations.
+ */
+ Set<String> readClasses();
+
+ /**
+ * Join all the elements of a set into one string and write
+ * back to the element.
+ * This is intended to be overridden by specific implementations.
+ */
+ void writeClasses(Set<String> s);
+}
diff --git a/sdk_nnbd/lib/html/html_common/device.dart b/sdk_nnbd/lib/html/html_common/device.dart
new file mode 100644
index 0000000..123a5db
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/device.dart
@@ -0,0 +1,112 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of html_common;
+
+/**
+ * Utils for device detection.
+ */
+class Device {
+ static bool _isOpera;
+ static bool _isIE;
+ static bool _isFirefox;
+ static bool _isWebKit;
+ static String _cachedCssPrefix;
+ static String _cachedPropertyPrefix;
+
+ /**
+ * Gets the browser's user agent. Using this function allows tests to inject
+ * the user agent.
+ * Returns the user agent.
+ */
+ static String get userAgent => window.navigator.userAgent;
+
+ /**
+ * Determines if the current device is running Opera.
+ */
+ static bool get isOpera {
+ if (_isOpera == null) {
+ _isOpera = userAgent.contains("Opera", 0);
+ }
+ return _isOpera;
+ }
+
+ /**
+ * Determines if the current device is running Internet Explorer.
+ */
+ static bool get isIE {
+ if (_isIE == null) {
+ _isIE = !isOpera && userAgent.contains("Trident/", 0);
+ }
+ return _isIE;
+ }
+
+ /**
+ * Determines if the current device is running Firefox.
+ */
+ static bool get isFirefox {
+ if (_isFirefox == null) {
+ _isFirefox = userAgent.contains("Firefox", 0);
+ }
+ return _isFirefox;
+ }
+
+ /**
+ * Determines if the current device is running WebKit.
+ */
+ static bool get isWebKit {
+ if (_isWebKit == null) {
+ _isWebKit = !isOpera && userAgent.contains("WebKit", 0);
+ }
+ return _isWebKit;
+ }
+
+ /**
+ * Gets the CSS property prefix for the current platform.
+ */
+ static String get cssPrefix {
+ String prefix = _cachedCssPrefix;
+ if (prefix != null) return prefix;
+ if (isFirefox) {
+ prefix = '-moz-';
+ } else if (isIE) {
+ prefix = '-ms-';
+ } else if (isOpera) {
+ prefix = '-o-';
+ } else {
+ prefix = '-webkit-';
+ }
+ return _cachedCssPrefix = prefix;
+ }
+
+ /**
+ * Prefix as used for JS property names.
+ */
+ static String get propertyPrefix {
+ String prefix = _cachedPropertyPrefix;
+ if (prefix != null) return prefix;
+ if (isFirefox) {
+ prefix = 'moz';
+ } else if (isIE) {
+ prefix = 'ms';
+ } else if (isOpera) {
+ prefix = 'o';
+ } else {
+ prefix = 'webkit';
+ }
+ return _cachedPropertyPrefix = prefix;
+ }
+
+ /**
+ * Checks to see if the event class is supported by the current platform.
+ */
+ static bool isEventTypeSupported(String eventType) {
+ // Browsers throw for unsupported event names.
+ try {
+ var e = new Event.eventType(eventType, '');
+ return e is Event;
+ } catch (_) {}
+ return false;
+ }
+}
diff --git a/sdk_nnbd/lib/html/html_common/filtered_element_list.dart b/sdk_nnbd/lib/html/html_common/filtered_element_list.dart
new file mode 100644
index 0000000..fba6ad7
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/filtered_element_list.dart
@@ -0,0 +1,150 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of html_common;
+
+/**
+ * An indexable collection of a node's direct descendants in the document tree,
+ * filtered so that only elements are in the collection.
+ */
+class FilteredElementList extends ListBase<Element> implements NodeListWrapper {
+ final Node _node;
+ final List<Node> _childNodes;
+
+ /**
+ * Creates a collection of the elements that descend from a node.
+ *
+ * Example usage:
+ *
+ * var filteredElements = new FilteredElementList(query("#container"));
+ * // filteredElements is [a, b, c].
+ */
+ FilteredElementList(Node node)
+ : _childNodes = node.nodes,
+ _node = node;
+
+ // We can't memoize this, since it's possible that children will be messed
+ // with externally to this class.
+ Iterable<Element> get _iterable =>
+ _childNodes.where((n) => n is Element).map<Element>((n) => n as Element);
+ List<Element> get _filtered =>
+ new List<Element>.from(_iterable, growable: false);
+
+ void forEach(void f(Element element)) {
+ // This cannot use the iterator, because operations during iteration might
+ // modify the collection, e.g. addAll might append a node to another parent.
+ _filtered.forEach(f);
+ }
+
+ void operator []=(int index, Element value) {
+ this[index].replaceWith(value);
+ }
+
+ set length(int newLength) {
+ final len = this.length;
+ if (newLength >= len) {
+ return;
+ } else if (newLength < 0) {
+ throw new ArgumentError("Invalid list length");
+ }
+
+ removeRange(newLength, len);
+ }
+
+ void add(Element value) {
+ _childNodes.add(value);
+ }
+
+ void addAll(Iterable<Element> iterable) {
+ for (Element element in iterable) {
+ add(element);
+ }
+ }
+
+ bool contains(Object needle) {
+ if (needle is! Element) return false;
+ Element element = needle;
+ return element.parentNode == _node;
+ }
+
+ Iterable<Element> get reversed => _filtered.reversed;
+
+ void sort([int compare(Element a, Element b)]) {
+ throw new UnsupportedError('Cannot sort filtered list');
+ }
+
+ void setRange(int start, int end, Iterable<Element> iterable,
+ [int skipCount = 0]) {
+ throw new UnsupportedError('Cannot setRange on filtered list');
+ }
+
+ void fillRange(int start, int end, [Element fillValue]) {
+ throw new UnsupportedError('Cannot fillRange on filtered list');
+ }
+
+ void replaceRange(int start, int end, Iterable<Element> iterable) {
+ throw new UnsupportedError('Cannot replaceRange on filtered list');
+ }
+
+ void removeRange(int start, int end) {
+ new List.from(_iterable.skip(start).take(end - start))
+ .forEach((el) => el.remove());
+ }
+
+ void clear() {
+ // Currently, ElementList#clear clears even non-element nodes, so we follow
+ // that behavior.
+ _childNodes.clear();
+ }
+
+ Element removeLast() {
+ final result = _iterable.last;
+ if (result != null) {
+ result.remove();
+ }
+ return result;
+ }
+
+ void insert(int index, Element value) {
+ if (index == length) {
+ add(value);
+ } else {
+ var element = _iterable.elementAt(index);
+ element.parentNode.insertBefore(value, element);
+ }
+ }
+
+ void insertAll(int index, Iterable<Element> iterable) {
+ if (index == length) {
+ addAll(iterable);
+ } else {
+ var element = _iterable.elementAt(index);
+ element.parentNode.insertAllBefore(iterable, element);
+ }
+ }
+
+ Element removeAt(int index) {
+ final result = this[index];
+ result.remove();
+ return result;
+ }
+
+ bool remove(Object element) {
+ if (element is! Element) return false;
+ if (contains(element)) {
+ (element as Element).remove(); // Placate the type checker
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ int get length => _iterable.length;
+ Element operator [](int index) => _iterable.elementAt(index);
+ // This cannot use the iterator, because operations during iteration might
+ // modify the collection, e.g. addAll might append a node to another parent.
+ Iterator<Element> get iterator => _filtered.iterator;
+
+ List<Node> get rawList => _node.childNodes;
+}
diff --git a/sdk_nnbd/lib/html/html_common/html_common.dart b/sdk_nnbd/lib/html/html_common/html_common.dart
new file mode 100644
index 0000000..e689c9a
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/html_common.dart
@@ -0,0 +1,25 @@
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library html_common;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:js' as js;
+import 'dart:_internal' show WhereIterable;
+import 'dart:mirrors';
+import 'dart:nativewrappers';
+import 'dart:typed_data';
+import 'dart:web_gl' as gl;
+
+import 'dart:_js_helper';
+
+import 'dart:_metadata';
+export 'dart:_metadata';
+
+part 'css_class_set.dart';
+part 'device.dart';
+part 'filtered_element_list.dart';
+part 'lists.dart';
+part 'conversions.dart';
diff --git a/sdk_nnbd/lib/html/html_common/html_common_dart2js.dart b/sdk_nnbd/lib/html/html_common/html_common_dart2js.dart
new file mode 100644
index 0000000..f162ad8
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/html_common_dart2js.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library html_common;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:_internal' show WhereIterable;
+import 'dart:web_gl' as gl;
+import 'dart:typed_data';
+import 'dart:_native_typed_data';
+import 'dart:_js_helper' show Creates, Returns, convertDartClosureToJS;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show Interceptor, JSExtendableArray;
+
+import 'dart:_metadata';
+export 'dart:_metadata';
+
+part 'css_class_set.dart';
+part 'conversions.dart';
+part 'conversions_dart2js.dart';
+part 'device.dart';
+part 'filtered_element_list.dart';
+part 'lists.dart';
diff --git a/sdk_nnbd/lib/html/html_common/lists.dart b/sdk_nnbd/lib/html/html_common/lists.dart
new file mode 100644
index 0000000..c7abc41
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/lists.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of html_common;
+
+class Lists {
+ /**
+ * Returns the index in the array [a] of the given [element], starting
+ * the search at index [startIndex] to [endIndex] (exclusive).
+ * Returns -1 if [element] is not found.
+ */
+ static int indexOf(List a, Object element, int startIndex, int endIndex) {
+ if (startIndex >= a.length) {
+ return -1;
+ }
+ if (startIndex < 0) {
+ startIndex = 0;
+ }
+ for (int i = startIndex; i < endIndex; i++) {
+ if (a[i] == element) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the last index in the array [a] of the given [element], starting
+ * the search at index [startIndex] to 0.
+ * Returns -1 if [element] is not found.
+ */
+ static int lastIndexOf(List a, Object element, int startIndex) {
+ if (startIndex < 0) {
+ return -1;
+ }
+ if (startIndex >= a.length) {
+ startIndex = a.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (a[i] == element) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns a sub list copy of this list, from [start] to
+ * [end] ([end] not inclusive).
+ * Returns an empty list if [length] is 0.
+ * It is an error if indices are not valid for the list, or
+ * if [end] is before [start].
+ */
+ static List getRange(List a, int start, int end, List accumulator) {
+ if (start < 0) throw new RangeError.value(start);
+ if (end < start) throw new RangeError.value(end);
+ if (end > a.length) throw new RangeError.value(end);
+ for (int i = start; i < end; i++) {
+ accumulator.add(a[i]);
+ }
+ return accumulator;
+ }
+}
+
+/**
+ * For accessing underlying node lists, for dart:js interop.
+ */
+abstract class NodeListWrapper {
+ List<Node> get rawList;
+}
diff --git a/sdk_nnbd/lib/html/html_common/metadata.dart b/sdk_nnbd/lib/html/html_common/metadata.dart
new file mode 100644
index 0000000..b5542dc
--- /dev/null
+++ b/sdk_nnbd/lib/html/html_common/metadata.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library metadata;
+
+/**
+ * An annotation used to mark a feature as only being supported by a subset
+ * of the browsers that Dart supports by default.
+ *
+ * If an API is not annotated with [SupportedBrowser] then it is assumed to
+ * work on all browsers Dart supports.
+ */
+class SupportedBrowser {
+ static const String CHROME = "Chrome";
+ static const String FIREFOX = "Firefox";
+ static const String IE = "Internet Explorer";
+ static const String OPERA = "Opera";
+ static const String SAFARI = "Safari";
+
+ /// The name of the browser.
+ final String browserName;
+
+ /// The minimum version of the browser that supports the feature, or null
+ /// if supported on all versions.
+ final String minimumVersion;
+
+ const SupportedBrowser(this.browserName, [this.minimumVersion]);
+}
+
+/**
+ * An annotation used to mark an API as being experimental.
+ *
+ * An API is considered to be experimental if it is still going through the
+ * process of stabilizing and is subject to change or removal.
+ *
+ * See also:
+ *
+ * * [W3C recommendation](http://en.wikipedia.org/wiki/W3C_recommendation)
+ */
+class Experimental {
+ const Experimental();
+}
+
+/**
+ * Annotation that specifies that a member is editable through generate files.
+ *
+ * This is used for API generation.
+ *
+ * [name] should be formatted as `interface.member`.
+ */
+class DomName {
+ final String name;
+ const DomName(this.name);
+}
+
+/**
+ * Metadata that specifies that that member is editable through generated
+ * files.
+ */
+class DocsEditable {
+ const DocsEditable();
+}
+
+/**
+ * Annotation that indicates that an API is not expected to change but has
+ * not undergone enough testing to be considered stable.
+ */
+class Unstable {
+ const Unstable();
+}
diff --git a/sdk_nnbd/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk_nnbd/lib/indexed_db/dart2js/indexed_db_dart2js.dart
new file mode 100644
index 0000000..b664b7d
--- /dev/null
+++ b/sdk_nnbd/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -0,0 +1,1295 @@
+/**
+ * A client-side key-value store with support for indexes.
+ *
+ * Many browsers support IndexedDB—a web standard for
+ * an indexed database.
+ * By storing data on the client in an IndexedDB,
+ * a web app gets some advantages, such as faster performance and persistence.
+ * To find out which browsers support IndexedDB,
+ * refer to [Can I Use?](http://caniuse.com/#feat=indexeddb)
+ *
+ * In IndexedDB, each record is identified by a unique index or key,
+ * making data retrieval speedy.
+ * You can store structured data,
+ * such as images, arrays, and maps using IndexedDB.
+ * The standard does not specify size limits for individual data items
+ * or for the database itself, but browsers may impose storage limits.
+ *
+ * ## Using indexed_db
+ *
+ * The classes in this library provide an interface
+ * to the browser's IndexedDB, if it has one.
+ * To use this library in your code:
+ *
+ * import 'dart:indexed_db';
+ *
+ * A web app can determine if the browser supports
+ * IndexedDB with [IdbFactory.supported]:
+ *
+ * if (IdbFactory.supported)
+ * // Use indexeddb.
+ * else
+ * // Find an alternative.
+ *
+ * Access to the browser's IndexedDB is provided by the app's top-level
+ * [Window] object, which your code can refer to with `window.indexedDB`.
+ * So, for example,
+ * here's how to use window.indexedDB to open a database:
+ *
+ * Future open() {
+ * return window.indexedDB.open('myIndexedDB',
+ * version: 1,
+ * onUpgradeNeeded: _initializeDatabase)
+ * .then(_loadFromDB);
+ * }
+ * void _initializeDatabase(VersionChangeEvent e) {
+ * ...
+ * }
+ * Future _loadFromDB(Database db) {
+ * ...
+ * }
+ *
+ *
+ * All data in an IndexedDB is stored within an [ObjectStore].
+ * To manipulate the database use [Transaction]s.
+ *
+ * ## Other resources
+ *
+ * Other options for client-side data storage include:
+ *
+ * * [Window.localStorage]—a
+ * basic mechanism that stores data as a [Map],
+ * and where both the keys and the values are strings.
+ *
+ * * [dart:web_sql]—a database that can be queried with SQL.
+ *
+ * For a tutorial about using the indexed_db library with Dart,
+ * check out
+ * [Use IndexedDB](http://www.dartlang.org/docs/tutorials/indexeddb/).
+ *
+ * MDN provides [API
+ * documentation](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API).
+ *
+ * {@category Web}
+ */
+library dart.dom.indexed_db;
+
+import 'dart:async';
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:_native_typed_data';
+import 'dart:typed_data';
+import 'dart:_js_helper' show Creates, Returns, JSName, Native;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show Interceptor, JSExtendableArray;
+import 'dart:_js_helper' show convertDartClosureToJS;
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:svg library.
+
+class _KeyRangeFactoryProvider {
+ static KeyRange createKeyRange_only(/*Key*/ value) =>
+ _only(_class(), _translateKey(value));
+
+ static KeyRange createKeyRange_lowerBound(
+ /*Key*/ bound,
+ [bool open = false]) =>
+ _lowerBound(_class(), _translateKey(bound), open);
+
+ static KeyRange createKeyRange_upperBound(
+ /*Key*/ bound,
+ [bool open = false]) =>
+ _upperBound(_class(), _translateKey(bound), open);
+
+ static KeyRange createKeyRange_bound(/*Key*/ lower, /*Key*/ upper,
+ [bool lowerOpen = false, bool upperOpen = false]) =>
+ _bound(_class(), _translateKey(lower), _translateKey(upper), lowerOpen,
+ upperOpen);
+
+ static var _cachedClass;
+
+ static _class() {
+ if (_cachedClass != null) return _cachedClass;
+ return _cachedClass = _uncachedClass();
+ }
+
+ static _uncachedClass() =>
+ JS('var', '''window.webkitIDBKeyRange || window.mozIDBKeyRange ||
+ window.msIDBKeyRange || window.IDBKeyRange''');
+
+ static _translateKey(idbkey) => idbkey; // TODO: fixme.
+
+ static KeyRange _only(cls, value) => JS('KeyRange', '#.only(#)', cls, value);
+
+ static KeyRange _lowerBound(cls, bound, open) =>
+ JS('KeyRange', '#.lowerBound(#, #)', cls, bound, open);
+
+ static KeyRange _upperBound(cls, bound, open) =>
+ JS('KeyRange', '#.upperBound(#, #)', cls, bound, open);
+
+ static KeyRange _bound(cls, lower, upper, lowerOpen, upperOpen) => JS(
+ 'KeyRange',
+ '#.bound(#, #, #, #)',
+ cls,
+ lower,
+ upper,
+ lowerOpen,
+ upperOpen);
+}
+
+// Conversions for IDBKey.
+//
+// Per http://www.w3.org/TR/IndexedDB/#key-construct
+//
+// "A value is said to be a valid key if it is one of the following types: Array
+// JavaScript objects [ECMA-262], DOMString [WEBIDL], Date [ECMA-262] or float
+// [WEBIDL]. However Arrays are only valid keys if every item in the array is
+// defined and is a valid key (i.e. sparse arrays can not be valid keys) and if
+// the Array doesn't directly or indirectly contain itself. Any non-numeric
+// properties are ignored, and thus does not affect whether the Array is a valid
+// key. Additionally, if the value is of type float, it is only a valid key if
+// it is not NaN, and if the value is of type Date it is only a valid key if its
+// [[PrimitiveValue]] internal property, as defined by [ECMA-262], is not NaN."
+
+// What is required is to ensure that an Lists in the key are actually
+// JavaScript arrays, and any Dates are JavaScript Dates.
+
+/**
+ * Converts a native IDBKey into a Dart object.
+ *
+ * May return the original input. May mutate the original input (but will be
+ * idempotent if mutation occurs). It is assumed that this conversion happens
+ * on native IDBKeys on all paths that return IDBKeys from native DOM calls.
+ *
+ * If necessary, JavaScript Dates are converted into Dart Dates.
+ */
+_convertNativeToDart_IDBKey(nativeKey) {
+ containsDate(object) {
+ if (isJavaScriptDate(object)) return true;
+ if (object is List) {
+ for (int i = 0; i < object.length; i++) {
+ if (containsDate(object[i])) return true;
+ }
+ }
+ return false; // number, string.
+ }
+
+ if (containsDate(nativeKey)) {
+ throw new UnimplementedError('Key containing DateTime');
+ }
+ // TODO: Cache conversion somewhere?
+ return nativeKey;
+}
+
+/**
+ * Converts a Dart object into a valid IDBKey.
+ *
+ * May return the original input. Does not mutate input.
+ *
+ * If necessary, [dartKey] may be copied to ensure all lists are converted into
+ * JavaScript Arrays and Dart Dates into JavaScript Dates.
+ */
+_convertDartToNative_IDBKey(dartKey) {
+ // TODO: Implement.
+ return dartKey;
+}
+
+/// May modify original. If so, action is idempotent.
+_convertNativeToDart_IDBAny(object) {
+ return convertNativeToDart_AcceptStructuredClone(object, mustCopy: false);
+}
+
+// TODO(sra): Add DateTime.
+const String _idbKey = 'JSExtendableArray|=Object|num|String';
+const _annotation_Creates_IDBKey = const Creates(_idbKey);
+const _annotation_Returns_IDBKey = const Returns(_idbKey);
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBCursor")
+class Cursor extends Interceptor {
+ Future delete() {
+ try {
+ return _completeRequest(_delete());
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ Future update(value) {
+ try {
+ return _completeRequest(_update(value));
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ @JSName('continue')
+ void next([Object key]) {
+ if (key == null) {
+ JS('void', '#.continue()', this);
+ } else {
+ JS('void', '#.continue(#)', this, key);
+ }
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory Cursor._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String direction;
+
+ @_annotation_Creates_IDBKey
+ @_annotation_Returns_IDBKey
+ final Object key;
+
+ @_annotation_Creates_IDBKey
+ @_annotation_Returns_IDBKey
+ final Object primaryKey;
+
+ @Creates('Null')
+ @Returns('ObjectStore|Index|Null')
+ final Object source;
+
+ void advance(int count) native;
+
+ void continuePrimaryKey(Object key, Object primaryKey) native;
+
+ @JSName('delete')
+ Request _delete() native;
+
+ Request _update(/*any*/ value) {
+ var value_1 = convertDartToNative_SerializedScriptValue(value);
+ return _update_1(value_1);
+ }
+
+ @JSName('update')
+ Request _update_1(value) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBCursorWithValue")
+class CursorWithValue extends Cursor {
+ // To suppress missing implicit constructor warnings.
+ factory CursorWithValue._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ dynamic get value => _convertNativeToDart_IDBAny(this._get_value);
+ @JSName('value')
+ @annotation_Creates_SerializedScriptValue
+ @annotation_Returns_SerializedScriptValue
+ final dynamic _get_value;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * An indexed database object for storing client-side data
+ * in web apps.
+ */
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX, '15')
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@Unstable()
+@Native("IDBDatabase")
+class Database extends EventTarget {
+ ObjectStore createObjectStore(String name, {keyPath, bool autoIncrement}) {
+ var options = {};
+ if (keyPath != null) {
+ options['keyPath'] = keyPath;
+ }
+ if (autoIncrement != null) {
+ options['autoIncrement'] = autoIncrement;
+ }
+
+ return _createObjectStore(name, options);
+ }
+
+ Transaction transaction(storeName_OR_storeNames, String mode) {
+ if (mode != 'readonly' && mode != 'readwrite') {
+ throw new ArgumentError(mode);
+ }
+
+ // TODO(sra): Ensure storeName_OR_storeNames is a string or List<String>,
+ // and copy to JavaScript array if necessary.
+
+ // Try and create a transaction with a string mode. Browsers that expect a
+ // numeric mode tend to convert the string into a number. This fails
+ // silently, resulting in zero ('readonly').
+ return _transaction(storeName_OR_storeNames, mode);
+ }
+
+ Transaction transactionStore(String storeName, String mode) {
+ if (mode != 'readonly' && mode != 'readwrite') {
+ throw new ArgumentError(mode);
+ }
+ // Try and create a transaction with a string mode. Browsers that expect a
+ // numeric mode tend to convert the string into a number. This fails
+ // silently, resulting in zero ('readonly').
+ return _transaction(storeName, mode);
+ }
+
+ Transaction transactionList(List<String> storeNames, String mode) {
+ if (mode != 'readonly' && mode != 'readwrite') {
+ throw new ArgumentError(mode);
+ }
+ List storeNames_1 = convertDartToNative_StringArray(storeNames);
+ return _transaction(storeNames_1, mode);
+ }
+
+ Transaction transactionStores(DomStringList storeNames, String mode) {
+ if (mode != 'readonly' && mode != 'readwrite') {
+ throw new ArgumentError(mode);
+ }
+ return _transaction(storeNames, mode);
+ }
+
+ @JSName('transaction')
+ Transaction _transaction(stores, mode) native;
+
+ // To suppress missing implicit constructor warnings.
+ factory Database._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `abort` events to event
+ * handlers that are not necessarily instances of [Database].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> abortEvent =
+ const EventStreamProvider<Event>('abort');
+
+ /**
+ * Static factory designed to expose `close` events to event
+ * handlers that are not necessarily instances of [Database].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> closeEvent =
+ const EventStreamProvider<Event>('close');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [Database].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /**
+ * Static factory designed to expose `versionchange` events to event
+ * handlers that are not necessarily instances of [Database].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<VersionChangeEvent> versionChangeEvent =
+ const EventStreamProvider<VersionChangeEvent>('versionchange');
+
+ final String name;
+
+ @Returns('DomStringList|Null')
+ @Creates('DomStringList')
+ final List<String> objectStoreNames;
+
+ @Creates('int|String|Null')
+ @Returns('int|String|Null')
+ final int version;
+
+ void close() native;
+
+ ObjectStore _createObjectStore(String name, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return _createObjectStore_1(name, options_1);
+ }
+ return _createObjectStore_2(name);
+ }
+
+ @JSName('createObjectStore')
+ ObjectStore _createObjectStore_1(name, options) native;
+ @JSName('createObjectStore')
+ ObjectStore _createObjectStore_2(name) native;
+
+ void deleteObjectStore(String name) native;
+
+ /// Stream of `abort` events handled by this [Database].
+ Stream<Event> get onAbort => abortEvent.forTarget(this);
+
+ /// Stream of `close` events handled by this [Database].
+ Stream<Event> get onClose => closeEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [Database].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `versionchange` events handled by this [Database].
+ Stream<VersionChangeEvent> get onVersionChange =>
+ versionChangeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void ObserverCallback(ObserverChanges changes);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX, '15')
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@Unstable()
+@Native("IDBFactory")
+class IdbFactory extends Interceptor {
+ /**
+ * Checks to see if Indexed DB is supported on the current platform.
+ */
+ static bool get supported {
+ return JS(
+ 'bool',
+ '!!(window.indexedDB || '
+ 'window.webkitIndexedDB || '
+ 'window.mozIndexedDB)');
+ }
+
+ Future<Database> open(String name,
+ {int version,
+ void onUpgradeNeeded(VersionChangeEvent event),
+ void onBlocked(Event event)}) {
+ if ((version == null) != (onUpgradeNeeded == null)) {
+ return new Future.error(new ArgumentError(
+ 'version and onUpgradeNeeded must be specified together'));
+ }
+ try {
+ var request;
+ if (version != null) {
+ request = _open(name, version);
+ } else {
+ request = _open(name);
+ }
+
+ if (onUpgradeNeeded != null) {
+ request.onUpgradeNeeded.listen(onUpgradeNeeded);
+ }
+ if (onBlocked != null) {
+ request.onBlocked.listen(onBlocked);
+ }
+ return _completeRequest(request);
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ Future<IdbFactory> deleteDatabase(String name, {void onBlocked(Event e)}) {
+ try {
+ var request = _deleteDatabase(name);
+
+ if (onBlocked != null) {
+ request.onBlocked.listen(onBlocked);
+ }
+ var completer = new Completer<IdbFactory>.sync();
+ request.onSuccess.listen((e) {
+ completer.complete(this);
+ });
+ request.onError.listen(completer.completeError);
+ return completer.future;
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ /**
+ * Checks to see if getDatabaseNames is supported by the current platform.
+ * TODO(terry): Should be able to always return false?
+ */
+ bool get supportsDatabaseNames {
+ return supported &&
+ JS('bool', '!!(#.getDatabaseNames || #.webkitGetDatabaseNames)', this,
+ this);
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory IdbFactory._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int cmp(Object first, Object second) native;
+
+ @JSName('deleteDatabase')
+ OpenDBRequest _deleteDatabase(String name) native;
+
+ @JSName('open')
+ @Returns('Request')
+ @Creates('Request')
+ @Creates('Database')
+ OpenDBRequest _open(String name, [int version]) native;
+}
+
+/**
+ * Ties a request to a completer, so the completer is completed when it succeeds
+ * and errors out when the request errors.
+ */
+Future<T> _completeRequest<T>(Request request) {
+ var completer = new Completer<T>.sync();
+ // TODO: make sure that completer.complete is synchronous as transactions
+ // may be committed if the result is not processed immediately.
+ request.onSuccess.listen((e) {
+ T result = request.result;
+ completer.complete(result);
+ });
+ request.onError.listen(completer.completeError);
+ return completer.future;
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBIndex")
+class Index extends Interceptor {
+ Future<int> count([key_OR_range]) {
+ try {
+ var request = _count(key_OR_range);
+ return _completeRequest(request);
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ Future get(key) {
+ try {
+ var request = _get(key);
+
+ return _completeRequest(request);
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ Future getKey(key) {
+ try {
+ var request = _getKey(key);
+
+ return _completeRequest(request);
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ /**
+ * Creates a stream of cursors over the records in this object store.
+ *
+ * See also:
+ *
+ * * [ObjectStore.openCursor]
+ */
+ Stream<CursorWithValue> openCursor(
+ {key, KeyRange range, String direction, bool autoAdvance}) {
+ var key_OR_range = null;
+ if (key != null) {
+ if (range != null) {
+ throw new ArgumentError('Cannot specify both key and range.');
+ }
+ key_OR_range = key;
+ } else {
+ key_OR_range = range;
+ }
+ var request;
+ if (direction == null) {
+ // FIXME: Passing in "next" should be unnecessary.
+ request = _openCursor(key_OR_range, "next");
+ } else {
+ request = _openCursor(key_OR_range, direction);
+ }
+ return ObjectStore._cursorStreamFromResult(request, autoAdvance);
+ }
+
+ /**
+ * Creates a stream of cursors over the records in this object store.
+ *
+ * See also:
+ *
+ * * [ObjectStore.openCursor]
+ */
+ Stream<Cursor> openKeyCursor(
+ {key, KeyRange range, String direction, bool autoAdvance}) {
+ var key_OR_range = null;
+ if (key != null) {
+ if (range != null) {
+ throw new ArgumentError('Cannot specify both key and range.');
+ }
+ key_OR_range = key;
+ } else {
+ key_OR_range = range;
+ }
+ var request;
+ if (direction == null) {
+ // FIXME: Passing in "next" should be unnecessary.
+ request = _openKeyCursor(key_OR_range, "next");
+ } else {
+ request = _openKeyCursor(key_OR_range, direction);
+ }
+ return ObjectStore._cursorStreamFromResult(request, autoAdvance);
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory Index._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @annotation_Creates_SerializedScriptValue
+ final Object keyPath;
+
+ final bool multiEntry;
+
+ String name;
+
+ final ObjectStore objectStore;
+
+ final bool unique;
+
+ @JSName('count')
+ Request _count(Object key) native;
+
+ @JSName('get')
+ @Returns('Request')
+ @Creates('Request')
+ @annotation_Creates_SerializedScriptValue
+ Request _get(Object key) native;
+
+ Request getAll(Object query, [int count]) native;
+
+ Request getAllKeys(Object query, [int count]) native;
+
+ @JSName('getKey')
+ @Returns('Request')
+ @Creates('Request')
+ @annotation_Creates_SerializedScriptValue
+ @Creates('ObjectStore')
+ Request _getKey(Object key) native;
+
+ @JSName('openCursor')
+ @Returns('Request')
+ @Creates('Request')
+ @Creates('Cursor')
+ Request _openCursor(Object range, [String direction]) native;
+
+ @JSName('openKeyCursor')
+ @Returns('Request')
+ @Creates('Request')
+ @Creates('Cursor')
+ Request _openKeyCursor(Object range, [String direction]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBKeyRange")
+class KeyRange extends Interceptor {
+ factory KeyRange.only(/*Key*/ value) =>
+ _KeyRangeFactoryProvider.createKeyRange_only(value);
+
+ factory KeyRange.lowerBound(/*Key*/ bound, [bool open = false]) =>
+ _KeyRangeFactoryProvider.createKeyRange_lowerBound(bound, open);
+
+ factory KeyRange.upperBound(/*Key*/ bound, [bool open = false]) =>
+ _KeyRangeFactoryProvider.createKeyRange_upperBound(bound, open);
+
+ factory KeyRange.bound(/*Key*/ lower, /*Key*/ upper,
+ [bool lowerOpen = false, bool upperOpen = false]) =>
+ _KeyRangeFactoryProvider.createKeyRange_bound(
+ lower, upper, lowerOpen, upperOpen);
+
+ // To suppress missing implicit constructor warnings.
+ factory KeyRange._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @annotation_Creates_SerializedScriptValue
+ final Object lower;
+
+ final bool lowerOpen;
+
+ @annotation_Creates_SerializedScriptValue
+ final Object upper;
+
+ final bool upperOpen;
+
+ @JSName('bound')
+ static KeyRange bound_(Object lower, Object upper,
+ [bool lowerOpen, bool upperOpen]) native;
+
+ bool includes(Object key) native;
+
+ @JSName('lowerBound')
+ static KeyRange lowerBound_(Object bound, [bool open]) native;
+
+ @JSName('only')
+ static KeyRange only_(Object value) native;
+
+ @JSName('upperBound')
+ static KeyRange upperBound_(Object bound, [bool open]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBObjectStore")
+class ObjectStore extends Interceptor {
+ Future add(value, [key]) {
+ try {
+ var request;
+ if (key != null) {
+ request = _add(value, key);
+ } else {
+ request = _add(value);
+ }
+ return _completeRequest(request);
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ Future clear() {
+ try {
+ return _completeRequest(_clear());
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ Future delete(key_OR_keyRange) {
+ try {
+ return _completeRequest(_delete(key_OR_keyRange));
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ Future<int> count([key_OR_range]) {
+ try {
+ var request = _count(key_OR_range);
+ return _completeRequest(request);
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ Future put(value, [key]) {
+ try {
+ var request;
+ if (key != null) {
+ request = _put(value, key);
+ } else {
+ request = _put(value);
+ }
+ return _completeRequest(request);
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ Future getObject(key) {
+ try {
+ var request = _get(key);
+
+ return _completeRequest(request);
+ } catch (e, stacktrace) {
+ return new Future.error(e, stacktrace);
+ }
+ }
+
+ /**
+ * Creates a stream of cursors over the records in this object store.
+ *
+ * **The stream must be manually advanced by calling [Cursor.next] after
+ * each item or by specifying autoAdvance to be true.**
+ *
+ * var cursors = objectStore.openCursor().listen(
+ * (cursor) {
+ * // ...some processing with the cursor
+ * cursor.next(); // advance onto the next cursor.
+ * },
+ * onDone: () {
+ * // called when there are no more cursors.
+ * print('all done!');
+ * });
+ *
+ * Asynchronous operations which are not related to the current transaction
+ * will cause the transaction to automatically be committed-- all processing
+ * must be done synchronously unless they are additional async requests to
+ * the current transaction.
+ */
+ Stream<CursorWithValue> openCursor(
+ {key, KeyRange range, String direction, bool autoAdvance}) {
+ var key_OR_range = null;
+ if (key != null) {
+ if (range != null) {
+ throw new ArgumentError('Cannot specify both key and range.');
+ }
+ key_OR_range = key;
+ } else {
+ key_OR_range = range;
+ }
+
+ // TODO: try/catch this and return a stream with an immediate error.
+ var request;
+ if (direction == null) {
+ request = _openCursor(key_OR_range);
+ } else {
+ request = _openCursor(key_OR_range, direction);
+ }
+ return _cursorStreamFromResult(request, autoAdvance);
+ }
+
+ Index createIndex(String name, keyPath, {bool unique, bool multiEntry}) {
+ var options = {};
+ if (unique != null) {
+ options['unique'] = unique;
+ }
+ if (multiEntry != null) {
+ options['multiEntry'] = multiEntry;
+ }
+
+ return _createIndex(name, keyPath, options);
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory ObjectStore._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool autoIncrement;
+
+ @Returns('DomStringList|Null')
+ @Creates('DomStringList')
+ final List<String> indexNames;
+
+ @annotation_Creates_SerializedScriptValue
+ final Object keyPath;
+
+ String name;
+
+ final Transaction transaction;
+
+ @Returns('Request')
+ @Creates('Request')
+ @_annotation_Creates_IDBKey
+ Request _add(/*any*/ value, [/*any*/ key]) {
+ if (key != null) {
+ var value_1 = convertDartToNative_SerializedScriptValue(value);
+ var key_2 = convertDartToNative_SerializedScriptValue(key);
+ return _add_1(value_1, key_2);
+ }
+ var value_1 = convertDartToNative_SerializedScriptValue(value);
+ return _add_2(value_1);
+ }
+
+ @JSName('add')
+ @Returns('Request')
+ @Creates('Request')
+ @_annotation_Creates_IDBKey
+ Request _add_1(value, key) native;
+ @JSName('add')
+ @Returns('Request')
+ @Creates('Request')
+ @_annotation_Creates_IDBKey
+ Request _add_2(value) native;
+
+ @JSName('clear')
+ Request _clear() native;
+
+ @JSName('count')
+ Request _count(Object key) native;
+
+ Index _createIndex(String name, Object keyPath, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return _createIndex_1(name, keyPath, options_1);
+ }
+ return _createIndex_2(name, keyPath);
+ }
+
+ @JSName('createIndex')
+ Index _createIndex_1(name, keyPath, options) native;
+ @JSName('createIndex')
+ Index _createIndex_2(name, keyPath) native;
+
+ @JSName('delete')
+ Request _delete(Object key) native;
+
+ void deleteIndex(String name) native;
+
+ @JSName('get')
+ @Returns('Request')
+ @Creates('Request')
+ @annotation_Creates_SerializedScriptValue
+ Request _get(Object key) native;
+
+ Request getAll(Object query, [int count]) native;
+
+ Request getAllKeys(Object query, [int count]) native;
+
+ Request getKey(Object key) native;
+
+ Index index(String name) native;
+
+ @JSName('openCursor')
+ @Returns('Request')
+ @Creates('Request')
+ @Creates('Cursor')
+ Request _openCursor(Object range, [String direction]) native;
+
+ Request openKeyCursor(Object range, [String direction]) native;
+
+ @Returns('Request')
+ @Creates('Request')
+ @_annotation_Creates_IDBKey
+ Request _put(/*any*/ value, [/*any*/ key]) {
+ if (key != null) {
+ var value_1 = convertDartToNative_SerializedScriptValue(value);
+ var key_2 = convertDartToNative_SerializedScriptValue(key);
+ return _put_1(value_1, key_2);
+ }
+ var value_1 = convertDartToNative_SerializedScriptValue(value);
+ return _put_2(value_1);
+ }
+
+ @JSName('put')
+ @Returns('Request')
+ @Creates('Request')
+ @_annotation_Creates_IDBKey
+ Request _put_1(value, key) native;
+ @JSName('put')
+ @Returns('Request')
+ @Creates('Request')
+ @_annotation_Creates_IDBKey
+ Request _put_2(value) native;
+
+ /**
+ * Helper for iterating over cursors in a request.
+ */
+ static Stream<T> _cursorStreamFromResult<T extends Cursor>(
+ Request request, bool autoAdvance) {
+ // TODO: need to guarantee that the controller provides the values
+ // immediately as waiting until the next tick will cause the transaction to
+ // close.
+ var controller = new StreamController<T>(sync: true);
+
+ //TODO: Report stacktrace once issue 4061 is resolved.
+ request.onError.listen(controller.addError);
+
+ request.onSuccess.listen((e) {
+ T cursor = request.result as dynamic;
+ if (cursor == null) {
+ controller.close();
+ } else {
+ controller.add(cursor);
+ if (autoAdvance == true && controller.hasListener) {
+ cursor.next();
+ }
+ }
+ });
+ return controller.stream;
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IDBObservation")
+class Observation extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Observation._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Object key;
+
+ final String type;
+
+ final Object value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IDBObserver")
+class Observer extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Observer._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory Observer(ObserverCallback callback) {
+ var callback_1 = convertDartClosureToJS(callback, 1);
+ return Observer._create_1(callback_1);
+ }
+ static Observer _create_1(callback) =>
+ JS('Observer', 'new IDBObserver(#)', callback);
+
+ void observe(Database db, Transaction tx, Map options) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ _observe_1(db, tx, options_1);
+ return;
+ }
+
+ @JSName('observe')
+ void _observe_1(Database db, Transaction tx, options) native;
+
+ void unobserve(Database db) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IDBObserverChanges")
+class ObserverChanges extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ObserverChanges._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Database database;
+
+ final Object records;
+
+ final Transaction transaction;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBOpenDBRequest,IDBVersionChangeRequest")
+class OpenDBRequest extends Request {
+ // To suppress missing implicit constructor warnings.
+ factory OpenDBRequest._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `blocked` events to event
+ * handlers that are not necessarily instances of [OpenDBRequest].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> blockedEvent =
+ const EventStreamProvider<Event>('blocked');
+
+ /**
+ * Static factory designed to expose `upgradeneeded` events to event
+ * handlers that are not necessarily instances of [OpenDBRequest].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<VersionChangeEvent> upgradeNeededEvent =
+ const EventStreamProvider<VersionChangeEvent>('upgradeneeded');
+
+ /// Stream of `blocked` events handled by this [OpenDBRequest].
+ Stream<Event> get onBlocked => blockedEvent.forTarget(this);
+
+ /// Stream of `upgradeneeded` events handled by this [OpenDBRequest].
+ Stream<VersionChangeEvent> get onUpgradeNeeded =>
+ upgradeNeededEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBRequest")
+class Request extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory Request._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [Request].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ /**
+ * Static factory designed to expose `success` events to event
+ * handlers that are not necessarily instances of [Request].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> successEvent =
+ const EventStreamProvider<Event>('success');
+
+ final DomException error;
+
+ final String readyState;
+
+ dynamic get result => _convertNativeToDart_IDBAny(this._get_result);
+ @JSName('result')
+ @Creates('Null')
+ final dynamic _get_result;
+
+ @Creates('Null')
+ final Object source;
+
+ final Transaction transaction;
+
+ /// Stream of `error` events handled by this [Request].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+
+ /// Stream of `success` events handled by this [Request].
+ Stream<Event> get onSuccess => successEvent.forTarget(this);
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBTransaction")
+class Transaction extends EventTarget {
+ /**
+ * Provides a Future which will be completed once the transaction has
+ * completed.
+ *
+ * The future will error if an error occurrs on the transaction or if the
+ * transaction is aborted.
+ */
+ Future<Database> get completed {
+ var completer = new Completer<Database>();
+
+ this.onComplete.first.then((_) {
+ completer.complete(db);
+ });
+
+ this.onError.first.then((e) {
+ completer.completeError(e);
+ });
+
+ this.onAbort.first.then((e) {
+ // Avoid completing twice if an error occurs.
+ if (!completer.isCompleted) {
+ completer.completeError(e);
+ }
+ });
+
+ return completer.future;
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory Transaction._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `abort` events to event
+ * handlers that are not necessarily instances of [Transaction].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> abortEvent =
+ const EventStreamProvider<Event>('abort');
+
+ /**
+ * Static factory designed to expose `complete` events to event
+ * handlers that are not necessarily instances of [Transaction].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> completeEvent =
+ const EventStreamProvider<Event>('complete');
+
+ /**
+ * Static factory designed to expose `error` events to event
+ * handlers that are not necessarily instances of [Transaction].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ final Database db;
+
+ final DomException error;
+
+ final String mode;
+
+ @Returns('DomStringList|Null')
+ @Creates('DomStringList')
+ final List<String> objectStoreNames;
+
+ void abort() native;
+
+ ObjectStore objectStore(String name) native;
+
+ /// Stream of `abort` events handled by this [Transaction].
+ Stream<Event> get onAbort => abortEvent.forTarget(this);
+
+ /// Stream of `complete` events handled by this [Transaction].
+ Stream<Event> get onComplete => completeEvent.forTarget(this);
+
+ /// Stream of `error` events handled by this [Transaction].
+ Stream<Event> get onError => errorEvent.forTarget(this);
+}
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("IDBVersionChangeEvent")
+class VersionChangeEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory VersionChangeEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory VersionChangeEvent(String type, [Map eventInitDict]) {
+ if (eventInitDict != null) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return VersionChangeEvent._create_1(type, eventInitDict_1);
+ }
+ return VersionChangeEvent._create_2(type);
+ }
+ static VersionChangeEvent _create_1(type, eventInitDict) => JS(
+ 'VersionChangeEvent',
+ 'new IDBVersionChangeEvent(#,#)',
+ type,
+ eventInitDict);
+ static VersionChangeEvent _create_2(type) =>
+ JS('VersionChangeEvent', 'new IDBVersionChangeEvent(#)', type);
+
+ final String dataLoss;
+
+ final String dataLossMessage;
+
+ @Creates('int|String|Null')
+ @Returns('int|String|Null')
+ final int newVersion;
+
+ @Creates('int|String|Null')
+ @Returns('int|String|Null')
+ final int oldVersion;
+
+ @JSName('target')
+ final OpenDBRequest target;
+}
diff --git a/sdk_nnbd/lib/internal/async_cast.dart b/sdk_nnbd/lib/internal/async_cast.dart
new file mode 100644
index 0000000..e041ff3
--- /dev/null
+++ b/sdk_nnbd/lib/internal/async_cast.dart
@@ -0,0 +1,121 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+// Casting wrappers for asynchronous classes.
+
+class CastStream<S, T> extends Stream<T> {
+ final Stream<S> _source;
+ CastStream(this._source);
+ bool get isBroadcast => _source.isBroadcast;
+
+ StreamSubscription<T> listen(void onData(T data),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ return new CastStreamSubscription<S, T>(
+ _source.listen(null, onDone: onDone, cancelOnError: cancelOnError))
+ ..onData(onData)
+ ..onError(onError);
+ }
+
+ Stream<R> cast<R>() => new CastStream<S, R>(_source);
+}
+
+class CastStreamSubscription<S, T> implements StreamSubscription<T> {
+ final StreamSubscription<S> _source;
+
+ /// Zone where listen was called.
+ final Zone _zone = Zone.current;
+
+ /// User's data handler. May be null.
+ void Function(T) _handleData;
+
+ /// Copy of _source's handleError so we can report errors in onData.
+ /// May be null.
+ Function _handleError;
+
+ CastStreamSubscription(this._source) {
+ _source.onData(_onData);
+ }
+
+ Future cancel() => _source.cancel();
+
+ void onData(void handleData(T data)) {
+ _handleData = handleData == null
+ ? null
+ : _zone.registerUnaryCallback<dynamic, T>(handleData);
+ }
+
+ void onError(Function handleError) {
+ _source.onError(handleError);
+ if (handleError == null) {
+ _handleError = null;
+ } else if (handleError is Function(Null, Null)) {
+ _handleError = _zone
+ .registerBinaryCallback<dynamic, Object, StackTrace>(handleError);
+ } else {
+ _handleError = _zone.registerUnaryCallback<dynamic, Object>(handleError);
+ }
+ }
+
+ void onDone(void handleDone()) {
+ _source.onDone(handleDone);
+ }
+
+ void _onData(S data) {
+ if (_handleData == null) return;
+ T targetData;
+ try {
+ targetData = data as T;
+ } catch (error, stack) {
+ if (_handleError == null) {
+ _zone.handleUncaughtError(error, stack);
+ } else if (_handleError is Function(Null, Null)) {
+ _zone.runBinaryGuarded(_handleError, error, stack);
+ } else {
+ _zone.runUnaryGuarded(_handleError, error);
+ }
+ return;
+ }
+ _zone.runUnaryGuarded(_handleData, targetData);
+ }
+
+ void pause([Future resumeSignal]) {
+ _source.pause(resumeSignal);
+ }
+
+ void resume() {
+ _source.resume();
+ }
+
+ bool get isPaused => _source.isPaused;
+
+ Future<E> asFuture<E>([E futureValue]) => _source.asFuture<E>(futureValue);
+}
+
+class CastStreamTransformer<SS, ST, TS, TT>
+ extends StreamTransformerBase<TS, TT> {
+ final StreamTransformer<SS, ST> _source;
+ CastStreamTransformer(this._source);
+
+ StreamTransformer<RS, RT> cast<RS, RT>() =>
+ new CastStreamTransformer<SS, ST, RS, RT>(_source);
+ Stream<TT> bind(Stream<TS> stream) =>
+ _source.bind(stream.cast<SS>()).cast<TT>();
+}
+
+class CastConverter<SS, ST, TS, TT> extends Converter<TS, TT> {
+ final Converter<SS, ST> _source;
+ CastConverter(this._source);
+
+ TT convert(TS input) => _source.convert(input as SS) as TT;
+
+ // cast is inherited from Converter.
+
+ Stream<TT> bind(Stream<TS> stream) =>
+ _source.bind(stream.cast<SS>()).cast<TT>();
+
+ Converter<RS, RT> cast<RS, RT>() =>
+ new CastConverter<SS, ST, RS, RT>(_source);
+}
diff --git a/sdk_nnbd/lib/internal/cast.dart b/sdk_nnbd/lib/internal/cast.dart
new file mode 100644
index 0000000..b3620f5
--- /dev/null
+++ b/sdk_nnbd/lib/internal/cast.dart
@@ -0,0 +1,361 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+// Casting wrappers for collection classes.
+
+abstract class _CastIterableBase<S, T> extends Iterable<T> {
+ Iterable<S> get _source;
+
+ Iterator<T> get iterator => new CastIterator<S, T>(_source.iterator);
+
+ // The following members use the default implementation on the
+ // throwing iterator. These are all operations that have no more efficient
+ // implementation than visiting every element in order,
+ // or that has no more efficient way to get the correct type (toList, toSet).
+ //
+ // * map
+ // * where
+ // * expand
+ // * forEach
+ // * reduce
+ // * fold
+ // * every
+ // * any
+ // * join
+ // * toList
+ // * toSet
+ // * skipWhile
+ // * takeWhile
+ // * firstWhere
+ // * singleWhere
+
+ int get length => _source.length;
+ bool get isEmpty => _source.isEmpty;
+ bool get isNotEmpty => _source.isNotEmpty;
+
+ Iterable<T> skip(int count) => new CastIterable<S, T>(_source.skip(count));
+ Iterable<T> take(int count) => new CastIterable<S, T>(_source.take(count));
+
+ T elementAt(int index) => _source.elementAt(index) as T;
+ T get first => _source.first as T;
+ T get last => _source.last as T;
+ T get single => _source.single as T;
+
+ bool contains(Object other) => _source.contains(other);
+
+ // Might be implemented by testing backwards from the end,
+ // so use the _source's implementation.
+ T lastWhere(bool test(T element), {T orElse()}) =>
+ _source.lastWhere((S element) => test(element as T),
+ orElse: (orElse == null) ? null : () => orElse() as S) as T;
+
+ String toString() => _source.toString();
+}
+
+class CastIterator<S, T> implements Iterator<T> {
+ Iterator<S> _source;
+ CastIterator(this._source);
+ bool moveNext() => _source.moveNext();
+ T get current => _source.current as T;
+}
+
+class CastIterable<S, T> extends _CastIterableBase<S, T> {
+ final Iterable<S> _source;
+
+ CastIterable._(this._source);
+
+ factory CastIterable(Iterable<S> source) {
+ if (source is EfficientLengthIterable<S>) {
+ return new _EfficientLengthCastIterable<S, T>(source);
+ }
+ return new CastIterable<S, T>._(source);
+ }
+
+ Iterable<R> cast<R>() => new CastIterable<S, R>(_source);
+}
+
+class _EfficientLengthCastIterable<S, T> extends CastIterable<S, T>
+ implements EfficientLengthIterable<T> {
+ _EfficientLengthCastIterable(EfficientLengthIterable<S> source)
+ : super._(source);
+}
+
+abstract class _CastListBase<S, T> extends _CastIterableBase<S, T>
+ with ListMixin<T> {
+ List<S> get _source;
+
+ // Using the default implementation from ListMixin:
+ // * reversed
+ // * shuffle
+ // * indexOf
+ // * lastIndexOf
+ // * clear
+ // * sublist
+ // * asMap
+
+ T operator [](int index) => _source[index] as T;
+
+ void operator []=(int index, T value) {
+ _source[index] = value as S;
+ }
+
+ void set length(int length) {
+ _source.length = length;
+ }
+
+ void add(T value) {
+ _source.add(value as S);
+ }
+
+ void addAll(Iterable<T> values) {
+ _source.addAll(new CastIterable<T, S>(values));
+ }
+
+ void sort([int compare(T v1, T v2)]) {
+ _source.sort(
+ compare == null ? null : (S v1, S v2) => compare(v1 as T, v2 as T));
+ }
+
+ void shuffle([Random random]) {
+ _source.shuffle(random);
+ }
+
+ void insert(int index, T element) {
+ _source.insert(index, element as S);
+ }
+
+ void insertAll(int index, Iterable<T> elements) {
+ _source.insertAll(index, new CastIterable<T, S>(elements));
+ }
+
+ void setAll(int index, Iterable<T> elements) {
+ _source.setAll(index, new CastIterable<T, S>(elements));
+ }
+
+ bool remove(Object value) => _source.remove(value);
+
+ T removeAt(int index) => _source.removeAt(index) as T;
+
+ T removeLast() => _source.removeLast() as T;
+
+ void removeWhere(bool test(T element)) {
+ _source.removeWhere((S element) => test(element as T));
+ }
+
+ void retainWhere(bool test(T element)) {
+ _source.retainWhere((S element) => test(element as T));
+ }
+
+ Iterable<T> getRange(int start, int end) =>
+ new CastIterable<S, T>(_source.getRange(start, end));
+
+ void setRange(int start, int end, Iterable<T> iterable, [int skipCount = 0]) {
+ _source.setRange(start, end, new CastIterable<T, S>(iterable), skipCount);
+ }
+
+ void removeRange(int start, int end) {
+ _source.removeRange(start, end);
+ }
+
+ void fillRange(int start, int end, [T fillValue]) {
+ _source.fillRange(start, end, fillValue as S);
+ }
+
+ void replaceRange(int start, int end, Iterable<T> replacement) {
+ _source.replaceRange(start, end, new CastIterable<T, S>(replacement));
+ }
+}
+
+class CastList<S, T> extends _CastListBase<S, T> {
+ final List<S> _source;
+ CastList(this._source);
+
+ List<R> cast<R>() => new CastList<S, R>(_source);
+}
+
+class CastSet<S, T> extends _CastIterableBase<S, T> implements Set<T> {
+ final Set<S> _source;
+
+ /// Creates a new empty set of the same *kind* as [_source],
+ /// but with `<R>` as type argument.
+ /// Used by [toSet] and [union].
+ final Set<R> Function<R>() _emptySet;
+
+ CastSet(this._source, this._emptySet);
+
+ static Set<R> _defaultEmptySet<R>() => new Set<R>();
+
+ Set<R> cast<R>() => new CastSet<S, R>(_source, _emptySet);
+ bool add(T value) => _source.add(value as S);
+
+ void addAll(Iterable<T> elements) {
+ _source.addAll(new CastIterable<T, S>(elements));
+ }
+
+ bool remove(Object object) => _source.remove(object);
+
+ void removeAll(Iterable<Object> objects) {
+ _source.removeAll(objects);
+ }
+
+ void retainAll(Iterable<Object> objects) {
+ _source.retainAll(objects);
+ }
+
+ void removeWhere(bool test(T element)) {
+ _source.removeWhere((S element) => test(element as T));
+ }
+
+ void retainWhere(bool test(T element)) {
+ _source.retainWhere((S element) => test(element as T));
+ }
+
+ bool containsAll(Iterable<Object> objects) => _source.containsAll(objects);
+
+ Set<T> intersection(Set<Object> other) {
+ if (_emptySet != null) return _conditionalAdd(other, true);
+ return new CastSet<S, T>(_source.intersection(other), null);
+ }
+
+ Set<T> difference(Set<Object> other) {
+ if (_emptySet != null) return _conditionalAdd(other, false);
+ return new CastSet<S, T>(_source.difference(other), null);
+ }
+
+ Set<T> _conditionalAdd(Set<Object> other, bool otherContains) {
+ Set<T> result = (_emptySet == null) ? new Set<T>() : _emptySet<T>();
+ for (var element in _source) {
+ T castElement = element as T;
+ if (otherContains == other.contains(castElement)) result.add(castElement);
+ }
+ return result;
+ }
+
+ Set<T> union(Set<T> other) => _clone()..addAll(other);
+
+ void clear() {
+ _source.clear();
+ }
+
+ Set<T> _clone() {
+ Set<T> result = (_emptySet == null) ? new Set<T>() : _emptySet<T>();
+ result.addAll(this);
+ return result;
+ }
+
+ Set<T> toSet() => _clone();
+
+ T lookup(Object key) => _source.lookup(key) as T;
+}
+
+class CastMap<SK, SV, K, V> extends MapBase<K, V> {
+ final Map<SK, SV> _source;
+
+ CastMap(this._source);
+
+ Map<RK, RV> cast<RK, RV>() => new CastMap<SK, SV, RK, RV>(_source);
+
+ bool containsValue(Object value) => _source.containsValue(value);
+
+ bool containsKey(Object key) => _source.containsKey(key);
+
+ V operator [](Object key) => _source[key] as V;
+
+ void operator []=(K key, V value) {
+ _source[key as SK] = value as SV;
+ }
+
+ V putIfAbsent(K key, V ifAbsent()) => _source.putIfAbsent(
+ key as SK, (ifAbsent == null) ? null : () => ifAbsent() as SV) as V;
+
+ void addAll(Map<K, V> other) {
+ _source.addAll(new CastMap<K, V, SK, SV>(other));
+ }
+
+ V remove(Object key) => _source.remove(key) as V;
+
+ void clear() {
+ _source.clear();
+ }
+
+ void forEach(void f(K key, V value)) {
+ _source.forEach((SK key, SV value) {
+ f(key as K, value as V);
+ });
+ }
+
+ Iterable<K> get keys => new CastIterable<SK, K>(_source.keys);
+
+ Iterable<V> get values => new CastIterable<SV, V>(_source.values);
+
+ int get length => _source.length;
+
+ bool get isEmpty => _source.isEmpty;
+
+ bool get isNotEmpty => _source.isNotEmpty;
+
+ V update(K key, V update(V value), {V ifAbsent()}) {
+ return _source.update(key as SK, (SV value) => update(value as V) as SV,
+ ifAbsent: (ifAbsent == null) ? null : () => ifAbsent() as SV) as V;
+ }
+
+ void updateAll(V update(K key, V value)) {
+ _source.updateAll((SK key, SV value) => update(key as K, value as V) as SV);
+ }
+
+ Iterable<MapEntry<K, V>> get entries {
+ return _source.entries.map<MapEntry<K, V>>(
+ (MapEntry<SK, SV> e) => new MapEntry<K, V>(e.key as K, e.value as V));
+ }
+
+ void addEntries(Iterable<MapEntry<K, V>> entries) {
+ for (var entry in entries) {
+ _source[entry.key as SK] = entry.value as SV;
+ }
+ }
+
+ void removeWhere(bool test(K key, V value)) {
+ _source.removeWhere((SK key, SV value) => test(key as K, value as V));
+ }
+}
+
+class CastQueue<S, T> extends _CastIterableBase<S, T> implements Queue<T> {
+ final Queue<S> _source;
+ CastQueue(this._source);
+ Queue<R> cast<R>() => new CastQueue<S, R>(_source);
+
+ T removeFirst() => _source.removeFirst() as T;
+ T removeLast() => _source.removeLast() as T;
+
+ void add(T value) {
+ _source.add(value as S);
+ }
+
+ void addFirst(T value) {
+ _source.addFirst(value as S);
+ }
+
+ void addLast(T value) {
+ _source.addLast(value as S);
+ }
+
+ bool remove(Object other) => _source.remove(other);
+ void addAll(Iterable<T> elements) {
+ _source.addAll(new CastIterable<T, S>(elements));
+ }
+
+ void removeWhere(bool test(T element)) {
+ _source.removeWhere((S element) => test(element as T));
+ }
+
+ void retainWhere(bool test(T element)) {
+ _source.retainWhere((S element) => test(element as T));
+ }
+
+ void clear() {
+ _source.clear();
+ }
+}
diff --git a/sdk_nnbd/lib/internal/internal.dart b/sdk_nnbd/lib/internal/internal.dart
new file mode 100644
index 0000000..11ee996
--- /dev/null
+++ b/sdk_nnbd/lib/internal/internal.dart
@@ -0,0 +1,382 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._internal;
+
+import 'dart:collection';
+
+import 'dart:async'
+ show
+ Future,
+ Stream,
+ StreamSubscription,
+ StreamTransformer,
+ StreamTransformerBase,
+ Zone;
+import 'dart:convert' show Converter;
+import 'dart:core' hide Symbol;
+import 'dart:core' as core;
+import 'dart:math' show Random;
+
+part 'async_cast.dart';
+part 'cast.dart';
+part 'iterable.dart';
+part 'list.dart';
+part 'print.dart';
+part 'sort.dart';
+part 'symbol.dart';
+part 'linked_list.dart';
+
+// Powers of 10 up to 10^22 are representable as doubles.
+// Powers of 10 above that are only approximate due to lack of precission.
+// Used by double-parsing.
+const POWERS_OF_TEN = const [
+ 1.0, // 0
+ 10.0,
+ 100.0,
+ 1000.0,
+ 10000.0,
+ 100000.0, // 5
+ 1000000.0,
+ 10000000.0,
+ 100000000.0,
+ 1000000000.0,
+ 10000000000.0, // 10
+ 100000000000.0,
+ 1000000000000.0,
+ 10000000000000.0,
+ 100000000000000.0,
+ 1000000000000000.0, // 15
+ 10000000000000000.0,
+ 100000000000000000.0,
+ 1000000000000000000.0,
+ 10000000000000000000.0,
+ 100000000000000000000.0, // 20
+ 1000000000000000000000.0,
+ 10000000000000000000000.0,
+];
+
+/**
+ * An [Iterable] of the UTF-16 code units of a [String] in index order.
+ */
+class CodeUnits extends UnmodifiableListBase<int> {
+ /** The string that this is the code units of. */
+ final String _string;
+
+ CodeUnits(this._string);
+
+ int get length => _string.length;
+ int operator [](int i) => _string.codeUnitAt(i);
+
+ static String stringOf(CodeUnits u) => u._string;
+}
+
+/// Marks a function or library as having an external implementation ("native"
+/// in the Dart VM).
+///
+/// On a function, this provides a backend-specific String that can be used to
+/// identify the function's implementation.
+///
+/// On a library, it provides a Uri that can be used to locate the native
+/// library's implementation.
+class ExternalName {
+ final String name;
+ const ExternalName(this.name);
+}
+
+// Shared hex-parsing utilities.
+
+/// Parses a single hex-digit as code unit.
+///
+/// Returns a negative value if the character is not a valid hex-digit.
+int hexDigitValue(int char) {
+ assert(char >= 0 && char <= 0xFFFF);
+ const int digit0 = 0x30;
+ const int a = 0x61;
+ const int f = 0x66;
+ int digit = char ^ digit0;
+ if (digit <= 9) return digit;
+ int letter = (char | 0x20);
+ if (a <= letter && letter <= f) return letter - (a - 10);
+ return -1;
+}
+
+/// Parses two hex digits in a string.
+///
+/// Returns a negative value if either digit isn't valid.
+int parseHexByte(String source, int index) {
+ assert(index + 2 <= source.length);
+ int digit1 = hexDigitValue(source.codeUnitAt(index));
+ int digit2 = hexDigitValue(source.codeUnitAt(index + 1));
+ return digit1 * 16 + digit2 - (digit2 & 256);
+}
+
+/// Given an [instance] of some generic type [T], and [extract], a first-class
+/// generic function that takes the same number of type parameters as [T],
+/// invokes the function with the same type arguments that were passed to T
+/// when [instance] was constructed.
+///
+/// Example:
+///
+/// ```dart
+/// class Two<A, B> {}
+///
+/// print(extractTypeArguments<List>(<int>[], <T>() => new Set<T>()));
+/// // Prints: Instance of 'Set<int>'.
+///
+/// print(extractTypeArguments<Map>(<String, bool>{},
+/// <T, S>() => new Two<T, S>));
+/// // Prints: Instance of 'Two<String, bool>'.
+/// ```
+///
+/// The type argument T is important to choose which specific type parameter
+/// list in [instance]'s type hierarchy is being extracted. Consider:
+///
+/// ```dart
+/// class A<T> {}
+/// class B<T> {}
+///
+/// class C implements A<int>, B<String> {}
+///
+/// main() {
+/// var c = new C();
+/// print(extractTypeArguments<A>(c, <T>() => <T>[]));
+/// // Prints: Instance of 'List<int>'.
+///
+/// print(extractTypeArguments<B>(c, <T>() => <T>[]));
+/// // Prints: Instance of 'List<String>'.
+/// }
+/// ```
+///
+/// A caller must not:
+///
+/// * Pass `null` for [instance].
+/// * Use a non-class type (i.e. a function type) for [T].
+/// * Use a non-generic type for [T].
+/// * Pass an instance of a generic type and a function that don't both take
+/// the same number of type arguments:
+///
+/// ```dart
+/// extractTypeArguments<List>(<int>[], <T, S>() => null);
+/// ```
+///
+/// See this issue for more context:
+/// https://github.com/dart-lang/sdk/issues/31371
+external Object extractTypeArguments<T>(T instance, Function extract);
+
+/// Annotation class marking the version where SDK API was added.
+///
+/// A `Since` annotation can be applied to a library declaration,
+/// any public declaration in a library, or in a class, or to
+/// an optional parameter.
+///
+/// It signifies that the export, member or parameter was *added* in
+/// that version.
+///
+/// When applied to a library declaration, it also a applies to
+/// all members declared or exported by that library.
+/// If applied to a class, it also applies to all members and constructors
+/// of that class.
+/// If applied to a class method, or parameter of such,
+/// any method implementing that interface method is also annotated.
+/// I multiple `Since` annotations apply to the same declaration or
+/// parameter, the latest version takes precendence.
+///
+/// Any use of a marked API may trigger a warning if the using code
+/// does not require an SDK version guaranteeing that the API is available,
+/// unless the API feature is also provided by something else.
+/// It is only a problem if an annotated feature is used, and the annotated
+/// API is the *only* thing providing the functionality.
+/// For example, using `Future` exported by `dart:core` is not a problem
+/// if the same library also imports `dart:async`, and using an optional
+/// parameter on an interface is not a problem if the same type also
+/// implements another interface providing the same parameter.
+///
+/// The version must be a semantic version (like `1.4.2` or `0.9.4-rec.4`),
+/// or the first two numbers of a semantic version (like `1.0` or `2.2`),
+/// representing a stable release, and equivalent to the semantic version
+/// you get by appending a `.0`.
+@Since("2.2")
+class Since {
+ final String version;
+ const Since(this.version);
+}
+
+/**
+ * HTTP status codes. Exported in dart:io and dart:html.
+ */
+abstract class HttpStatus {
+ static const int continue_ = 100;
+ static const int switchingProtocols = 101;
+ @Since("2.1")
+ static const int processing = 102;
+ static const int ok = 200;
+ static const int created = 201;
+ static const int accepted = 202;
+ static const int nonAuthoritativeInformation = 203;
+ static const int noContent = 204;
+ static const int resetContent = 205;
+ static const int partialContent = 206;
+ @Since("2.1")
+ static const int multiStatus = 207;
+ @Since("2.1")
+ static const int alreadyReported = 208;
+ @Since("2.1")
+ static const int imUsed = 226;
+ static const int multipleChoices = 300;
+ static const int movedPermanently = 301;
+ static const int found = 302;
+ static const int movedTemporarily = 302; // Common alias for found.
+ static const int seeOther = 303;
+ static const int notModified = 304;
+ static const int useProxy = 305;
+ static const int temporaryRedirect = 307;
+ @Since("2.1")
+ static const int permanentRedirect = 308;
+ static const int badRequest = 400;
+ static const int unauthorized = 401;
+ static const int paymentRequired = 402;
+ static const int forbidden = 403;
+ static const int notFound = 404;
+ static const int methodNotAllowed = 405;
+ static const int notAcceptable = 406;
+ static const int proxyAuthenticationRequired = 407;
+ static const int requestTimeout = 408;
+ static const int conflict = 409;
+ static const int gone = 410;
+ static const int lengthRequired = 411;
+ static const int preconditionFailed = 412;
+ static const int requestEntityTooLarge = 413;
+ static const int requestUriTooLong = 414;
+ static const int unsupportedMediaType = 415;
+ static const int requestedRangeNotSatisfiable = 416;
+ static const int expectationFailed = 417;
+ @Since("2.1")
+ static const int misdirectedRequest = 421;
+ @Since("2.1")
+ static const int unprocessableEntity = 422;
+ @Since("2.1")
+ static const int locked = 423;
+ @Since("2.1")
+ static const int failedDependency = 424;
+ static const int upgradeRequired = 426;
+ @Since("2.1")
+ static const int preconditionRequired = 428;
+ @Since("2.1")
+ static const int tooManyRequests = 429;
+ @Since("2.1")
+ static const int requestHeaderFieldsTooLarge = 431;
+ @Since("2.1")
+ static const int connectionClosedWithoutResponse = 444;
+ @Since("2.1")
+ static const int unavailableForLegalReasons = 451;
+ @Since("2.1")
+ static const int clientClosedRequest = 499;
+ static const int internalServerError = 500;
+ static const int notImplemented = 501;
+ static const int badGateway = 502;
+ static const int serviceUnavailable = 503;
+ static const int gatewayTimeout = 504;
+ static const int httpVersionNotSupported = 505;
+ @Since("2.1")
+ static const int variantAlsoNegotiates = 506;
+ @Since("2.1")
+ static const int insufficientStorage = 507;
+ @Since("2.1")
+ static const int loopDetected = 508;
+ @Since("2.1")
+ static const int notExtended = 510;
+ @Since("2.1")
+ static const int networkAuthenticationRequired = 511;
+ // Client generated status code.
+ static const int networkConnectTimeoutError = 599;
+
+ @Deprecated("Use continue_ instead")
+ static const int CONTINUE = continue_;
+ @Deprecated("Use switchingProtocols instead")
+ static const int SWITCHING_PROTOCOLS = switchingProtocols;
+ @Deprecated("Use ok instead")
+ static const int OK = ok;
+ @Deprecated("Use created instead")
+ static const int CREATED = created;
+ @Deprecated("Use accepted instead")
+ static const int ACCEPTED = accepted;
+ @Deprecated("Use nonAuthoritativeInformation instead")
+ static const int NON_AUTHORITATIVE_INFORMATION = nonAuthoritativeInformation;
+ @Deprecated("Use noContent instead")
+ static const int NO_CONTENT = noContent;
+ @Deprecated("Use resetContent instead")
+ static const int RESET_CONTENT = resetContent;
+ @Deprecated("Use partialContent instead")
+ static const int PARTIAL_CONTENT = partialContent;
+ @Deprecated("Use multipleChoices instead")
+ static const int MULTIPLE_CHOICES = multipleChoices;
+ @Deprecated("Use movedPermanently instead")
+ static const int MOVED_PERMANENTLY = movedPermanently;
+ @Deprecated("Use found instead")
+ static const int FOUND = found;
+ @Deprecated("Use movedTemporarily instead")
+ static const int MOVED_TEMPORARILY = movedTemporarily;
+ @Deprecated("Use seeOther instead")
+ static const int SEE_OTHER = seeOther;
+ @Deprecated("Use notModified instead")
+ static const int NOT_MODIFIED = notModified;
+ @Deprecated("Use useProxy instead")
+ static const int USE_PROXY = useProxy;
+ @Deprecated("Use temporaryRedirect instead")
+ static const int TEMPORARY_REDIRECT = temporaryRedirect;
+ @Deprecated("Use badRequest instead")
+ static const int BAD_REQUEST = badRequest;
+ @Deprecated("Use unauthorized instead")
+ static const int UNAUTHORIZED = unauthorized;
+ @Deprecated("Use paymentRequired instead")
+ static const int PAYMENT_REQUIRED = paymentRequired;
+ @Deprecated("Use forbidden instead")
+ static const int FORBIDDEN = forbidden;
+ @Deprecated("Use notFound instead")
+ static const int NOT_FOUND = notFound;
+ @Deprecated("Use methodNotAllowed instead")
+ static const int METHOD_NOT_ALLOWED = methodNotAllowed;
+ @Deprecated("Use notAcceptable instead")
+ static const int NOT_ACCEPTABLE = notAcceptable;
+ @Deprecated("Use proxyAuthenticationRequired instead")
+ static const int PROXY_AUTHENTICATION_REQUIRED = proxyAuthenticationRequired;
+ @Deprecated("Use requestTimeout instead")
+ static const int REQUEST_TIMEOUT = requestTimeout;
+ @Deprecated("Use conflict instead")
+ static const int CONFLICT = conflict;
+ @Deprecated("Use gone instead")
+ static const int GONE = gone;
+ @Deprecated("Use lengthRequired instead")
+ static const int LENGTH_REQUIRED = lengthRequired;
+ @Deprecated("Use preconditionFailed instead")
+ static const int PRECONDITION_FAILED = preconditionFailed;
+ @Deprecated("Use requestEntityTooLarge instead")
+ static const int REQUEST_ENTITY_TOO_LARGE = requestEntityTooLarge;
+ @Deprecated("Use requestUriTooLong instead")
+ static const int REQUEST_URI_TOO_LONG = requestUriTooLong;
+ @Deprecated("Use unsupportedMediaType instead")
+ static const int UNSUPPORTED_MEDIA_TYPE = unsupportedMediaType;
+ @Deprecated("Use requestedRangeNotSatisfiable instead")
+ static const int REQUESTED_RANGE_NOT_SATISFIABLE =
+ requestedRangeNotSatisfiable;
+ @Deprecated("Use expectationFailed instead")
+ static const int EXPECTATION_FAILED = expectationFailed;
+ @Deprecated("Use upgradeRequired instead")
+ static const int UPGRADE_REQUIRED = upgradeRequired;
+ @Deprecated("Use internalServerError instead")
+ static const int INTERNAL_SERVER_ERROR = internalServerError;
+ @Deprecated("Use notImplemented instead")
+ static const int NOT_IMPLEMENTED = notImplemented;
+ @Deprecated("Use badGateway instead")
+ static const int BAD_GATEWAY = badGateway;
+ @Deprecated("Use serviceUnavailable instead")
+ static const int SERVICE_UNAVAILABLE = serviceUnavailable;
+ @Deprecated("Use gatewayTimeout instead")
+ static const int GATEWAY_TIMEOUT = gatewayTimeout;
+ @Deprecated("Use httpVersionNotSupported instead")
+ static const int HTTP_VERSION_NOT_SUPPORTED = httpVersionNotSupported;
+ @Deprecated("Use networkConnectTimeoutError instead")
+ static const int NETWORK_CONNECT_TIMEOUT_ERROR = networkConnectTimeoutError;
+}
diff --git a/sdk_nnbd/lib/internal/internal_sources.gni b/sdk_nnbd/lib/internal/internal_sources.gni
new file mode 100644
index 0000000..7c8af46
--- /dev/null
+++ b/sdk_nnbd/lib/internal/internal_sources.gni
@@ -0,0 +1,18 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# This file contains all sources for the dart:_internal library.
+internal_sdk_sources = [
+ "internal.dart",
+
+ # The above file needs to be first as it lists the parts below.
+ "async_cast.dart",
+ "cast.dart",
+ "iterable.dart",
+ "list.dart",
+ "linked_list.dart",
+ "print.dart",
+ "sort.dart",
+ "symbol.dart",
+]
diff --git a/sdk_nnbd/lib/internal/iterable.dart b/sdk_nnbd/lib/internal/iterable.dart
new file mode 100644
index 0000000..b3e8e4e
--- /dev/null
+++ b/sdk_nnbd/lib/internal/iterable.dart
@@ -0,0 +1,897 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+/**
+ * Marker interface for [Iterable] subclasses that have an efficient
+ * [length] implementation.
+ */
+abstract class EfficientLengthIterable<T> extends Iterable<T> {
+ const EfficientLengthIterable();
+ /**
+ * Returns the number of elements in the iterable.
+ *
+ * This is an efficient operation that doesn't require iterating through
+ * the elements.
+ */
+ int get length;
+}
+
+/**
+ * An [Iterable] for classes that have efficient [length] and [elementAt].
+ *
+ * All other methods are implemented in terms of [length] and [elementAt],
+ * including [iterator].
+ */
+abstract class ListIterable<E> extends EfficientLengthIterable<E> {
+ int get length;
+ E elementAt(int i);
+
+ const ListIterable();
+
+ Iterator<E> get iterator => new ListIterator<E>(this);
+
+ void forEach(void action(E element)) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ action(elementAt(i));
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ }
+
+ bool get isEmpty => length == 0;
+
+ E get first {
+ if (length == 0) throw IterableElementError.noElement();
+ return elementAt(0);
+ }
+
+ E get last {
+ if (length == 0) throw IterableElementError.noElement();
+ return elementAt(length - 1);
+ }
+
+ E get single {
+ if (length == 0) throw IterableElementError.noElement();
+ if (length > 1) throw IterableElementError.tooMany();
+ return elementAt(0);
+ }
+
+ bool contains(Object element) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ if (elementAt(i) == element) return true;
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return false;
+ }
+
+ bool every(bool test(E element)) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ if (!test(elementAt(i))) return false;
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return true;
+ }
+
+ bool any(bool test(E element)) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ if (test(elementAt(i))) return true;
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return false;
+ }
+
+ E firstWhere(bool test(E element), {E orElse()}) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ E element = elementAt(i);
+ if (test(element)) return element;
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E lastWhere(bool test(E element), {E orElse()}) {
+ int length = this.length;
+ for (int i = length - 1; i >= 0; i--) {
+ E element = elementAt(i);
+ if (test(element)) return element;
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E singleWhere(bool test(E element), {E orElse()}) {
+ int length = this.length;
+ E match = null;
+ bool matchFound = false;
+ for (int i = 0; i < length; i++) {
+ E element = elementAt(i);
+ if (test(element)) {
+ if (matchFound) {
+ throw IterableElementError.tooMany();
+ }
+ matchFound = true;
+ match = element;
+ }
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ if (matchFound) return match;
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ String join([String separator = ""]) {
+ int length = this.length;
+ if (!separator.isEmpty) {
+ if (length == 0) return "";
+ String first = "${elementAt(0)}";
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ StringBuffer buffer = new StringBuffer(first);
+ for (int i = 1; i < length; i++) {
+ buffer.write(separator);
+ buffer.write(elementAt(i));
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return buffer.toString();
+ } else {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < length; i++) {
+ buffer.write(elementAt(i));
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return buffer.toString();
+ }
+ }
+
+ Iterable<E> where(bool test(E element)) => super.where(test);
+
+ Iterable<T> map<T>(T f(E element)) => new MappedListIterable<E, T>(this, f);
+
+ E reduce(E combine(E value, E element)) {
+ int length = this.length;
+ if (length == 0) throw IterableElementError.noElement();
+ E value = elementAt(0);
+ for (int i = 1; i < length; i++) {
+ value = combine(value, elementAt(i));
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return value;
+ }
+
+ T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+ var value = initialValue;
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ value = combine(value, elementAt(i));
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return value;
+ }
+
+ Iterable<E> skip(int count) => new SubListIterable<E>(this, count, null);
+
+ Iterable<E> skipWhile(bool test(E element)) => super.skipWhile(test);
+
+ Iterable<E> take(int count) => new SubListIterable<E>(this, 0, count);
+
+ Iterable<E> takeWhile(bool test(E element)) => super.takeWhile(test);
+
+ List<E> toList({bool growable: true}) {
+ List<E> result;
+ if (growable) {
+ result = <E>[]..length = length;
+ } else {
+ result = new List<E>(length);
+ }
+ for (int i = 0; i < length; i++) {
+ result[i] = elementAt(i);
+ }
+ return result;
+ }
+
+ Set<E> toSet() {
+ Set<E> result = new Set<E>();
+ for (int i = 0; i < length; i++) {
+ result.add(elementAt(i));
+ }
+ return result;
+ }
+}
+
+class SubListIterable<E> extends ListIterable<E> {
+ final Iterable<E> _iterable; // Has efficient length and elementAt.
+ final int _start;
+ /** If null, represents the length of the iterable. */
+ final int _endOrLength;
+
+ SubListIterable(this._iterable, this._start, this._endOrLength) {
+ RangeError.checkNotNegative(_start, "start");
+ if (_endOrLength != null) {
+ RangeError.checkNotNegative(_endOrLength, "end");
+ if (_start > _endOrLength) {
+ throw new RangeError.range(_start, 0, _endOrLength, "start");
+ }
+ }
+ }
+
+ int get _endIndex {
+ int length = _iterable.length;
+ if (_endOrLength == null || _endOrLength > length) return length;
+ return _endOrLength;
+ }
+
+ int get _startIndex {
+ int length = _iterable.length;
+ if (_start > length) return length;
+ return _start;
+ }
+
+ int get length {
+ int length = _iterable.length;
+ if (_start >= length) return 0;
+ if (_endOrLength == null || _endOrLength >= length) {
+ return length - _start;
+ }
+ return _endOrLength - _start;
+ }
+
+ E elementAt(int index) {
+ int realIndex = _startIndex + index;
+ if (index < 0 || realIndex >= _endIndex) {
+ throw new RangeError.index(index, this, "index");
+ }
+ return _iterable.elementAt(realIndex);
+ }
+
+ Iterable<E> skip(int count) {
+ RangeError.checkNotNegative(count, "count");
+ int newStart = _start + count;
+ if (_endOrLength != null && newStart >= _endOrLength) {
+ return new EmptyIterable<E>();
+ }
+ return new SubListIterable<E>(_iterable, newStart, _endOrLength);
+ }
+
+ Iterable<E> take(int count) {
+ RangeError.checkNotNegative(count, "count");
+ if (_endOrLength == null) {
+ return new SubListIterable<E>(_iterable, _start, _start + count);
+ } else {
+ int newEnd = _start + count;
+ if (_endOrLength < newEnd) return this;
+ return new SubListIterable<E>(_iterable, _start, newEnd);
+ }
+ }
+
+ List<E> toList({bool growable: true}) {
+ int start = _start;
+ int end = _iterable.length;
+ if (_endOrLength != null && _endOrLength < end) end = _endOrLength;
+ int length = end - start;
+ if (length < 0) length = 0;
+ List<E> result =
+ growable ? (new List<E>()..length = length) : new List<E>(length);
+ for (int i = 0; i < length; i++) {
+ result[i] = _iterable.elementAt(start + i);
+ if (_iterable.length < end) throw new ConcurrentModificationError(this);
+ }
+ return result;
+ }
+}
+
+/**
+ * An [Iterator] that iterates a list-like [Iterable].
+ *
+ * All iterations is done in terms of [Iterable.length] and
+ * [Iterable.elementAt]. These operations are fast for list-like
+ * iterables.
+ */
+class ListIterator<E> implements Iterator<E> {
+ final Iterable<E> _iterable;
+ final int _length;
+ int _index;
+ E _current;
+
+ ListIterator(Iterable<E> iterable)
+ : _iterable = iterable,
+ _length = iterable.length,
+ _index = 0;
+
+ E get current => _current;
+
+ @pragma("vm:prefer-inline")
+ bool moveNext() {
+ int length = _iterable.length;
+ if (_length != length) {
+ throw new ConcurrentModificationError(_iterable);
+ }
+ if (_index >= length) {
+ _current = null;
+ return false;
+ }
+ _current = _iterable.elementAt(_index);
+ _index++;
+ return true;
+ }
+}
+
+typedef T _Transformation<S, T>(S value);
+
+class MappedIterable<S, T> extends Iterable<T> {
+ final Iterable<S> _iterable;
+ final _Transformation<S, T> _f;
+
+ factory MappedIterable(Iterable<S> iterable, T function(S value)) {
+ if (iterable is EfficientLengthIterable) {
+ return new EfficientLengthMappedIterable<S, T>(iterable, function);
+ }
+ return new MappedIterable<S, T>._(iterable, function);
+ }
+
+ MappedIterable._(this._iterable, this._f);
+
+ Iterator<T> get iterator => new MappedIterator<S, T>(_iterable.iterator, _f);
+
+ // Length related functions are independent of the mapping.
+ int get length => _iterable.length;
+ bool get isEmpty => _iterable.isEmpty;
+
+ // Index based lookup can be done before transforming.
+ T get first => _f(_iterable.first);
+ T get last => _f(_iterable.last);
+ T get single => _f(_iterable.single);
+ T elementAt(int index) => _f(_iterable.elementAt(index));
+}
+
+class EfficientLengthMappedIterable<S, T> extends MappedIterable<S, T>
+ implements EfficientLengthIterable<T> {
+ EfficientLengthMappedIterable(Iterable<S> iterable, T function(S value))
+ : super._(iterable, function);
+}
+
+class MappedIterator<S, T> extends Iterator<T> {
+ T _current;
+ final Iterator<S> _iterator;
+ final _Transformation<S, T> _f;
+
+ MappedIterator(this._iterator, this._f);
+
+ bool moveNext() {
+ if (_iterator.moveNext()) {
+ _current = _f(_iterator.current);
+ return true;
+ }
+ _current = null;
+ return false;
+ }
+
+ T get current => _current;
+}
+
+/**
+ * Specialized alternative to [MappedIterable] for mapped [List]s.
+ *
+ * Expects efficient `length` and `elementAt` on the source iterable.
+ */
+class MappedListIterable<S, T> extends ListIterable<T> {
+ final Iterable<S> _source;
+ final _Transformation<S, T> _f;
+
+ MappedListIterable(this._source, this._f);
+
+ int get length => _source.length;
+ T elementAt(int index) => _f(_source.elementAt(index));
+}
+
+typedef bool _ElementPredicate<E>(E element);
+
+class WhereIterable<E> extends Iterable<E> {
+ final Iterable<E> _iterable;
+ final _ElementPredicate<E> _f;
+
+ WhereIterable(this._iterable, this._f);
+
+ Iterator<E> get iterator => new WhereIterator<E>(_iterable.iterator, _f);
+
+ // Specialization of [Iterable.map] to non-EfficientLengthIterable.
+ Iterable<T> map<T>(T f(E element)) => new MappedIterable<E, T>._(this, f);
+}
+
+class WhereIterator<E> extends Iterator<E> {
+ final Iterator<E> _iterator;
+ final _ElementPredicate<E> _f;
+
+ WhereIterator(this._iterator, this._f);
+
+ bool moveNext() {
+ while (_iterator.moveNext()) {
+ if (_f(_iterator.current)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ E get current => _iterator.current;
+}
+
+typedef Iterable<T> _ExpandFunction<S, T>(S sourceElement);
+
+class ExpandIterable<S, T> extends Iterable<T> {
+ final Iterable<S> _iterable;
+ final _ExpandFunction<S, T> _f;
+
+ ExpandIterable(this._iterable, this._f);
+
+ Iterator<T> get iterator => new ExpandIterator<S, T>(_iterable.iterator, _f);
+}
+
+class ExpandIterator<S, T> implements Iterator<T> {
+ final Iterator<S> _iterator;
+ final _ExpandFunction<S, T> _f;
+ // Initialize _currentExpansion to an empty iterable. A null value
+ // marks the end of iteration, and we don't want to call _f before
+ // the first moveNext call.
+ Iterator<T> _currentExpansion = const EmptyIterator();
+ T _current;
+
+ ExpandIterator(this._iterator, this._f);
+
+ T get current => _current;
+
+ bool moveNext() {
+ if (_currentExpansion == null) return false;
+ while (!_currentExpansion.moveNext()) {
+ _current = null;
+ if (_iterator.moveNext()) {
+ // If _f throws, this ends iteration. Otherwise _currentExpansion and
+ // _current will be set again below.
+ _currentExpansion = null;
+ _currentExpansion = _f(_iterator.current).iterator;
+ } else {
+ return false;
+ }
+ }
+ _current = _currentExpansion.current;
+ return true;
+ }
+}
+
+class TakeIterable<E> extends Iterable<E> {
+ final Iterable<E> _iterable;
+ final int _takeCount;
+
+ factory TakeIterable(Iterable<E> iterable, int takeCount) {
+ ArgumentError.checkNotNull(takeCount, "takeCount");
+ RangeError.checkNotNegative(takeCount, "takeCount");
+ if (iterable is EfficientLengthIterable) {
+ return new EfficientLengthTakeIterable<E>(iterable, takeCount);
+ }
+ return new TakeIterable<E>._(iterable, takeCount);
+ }
+
+ TakeIterable._(this._iterable, this._takeCount);
+
+ Iterator<E> get iterator {
+ return new TakeIterator<E>(_iterable.iterator, _takeCount);
+ }
+}
+
+class EfficientLengthTakeIterable<E> extends TakeIterable<E>
+ implements EfficientLengthIterable<E> {
+ EfficientLengthTakeIterable(Iterable<E> iterable, int takeCount)
+ : super._(iterable, takeCount);
+
+ int get length {
+ int iterableLength = _iterable.length;
+ if (iterableLength > _takeCount) return _takeCount;
+ return iterableLength;
+ }
+}
+
+class TakeIterator<E> extends Iterator<E> {
+ final Iterator<E> _iterator;
+ int _remaining;
+
+ TakeIterator(this._iterator, this._remaining) {
+ assert(_remaining >= 0);
+ }
+
+ bool moveNext() {
+ _remaining--;
+ if (_remaining >= 0) {
+ return _iterator.moveNext();
+ }
+ _remaining = -1;
+ return false;
+ }
+
+ E get current {
+ if (_remaining < 0) return null;
+ return _iterator.current;
+ }
+}
+
+class TakeWhileIterable<E> extends Iterable<E> {
+ final Iterable<E> _iterable;
+ final _ElementPredicate<E> _f;
+
+ TakeWhileIterable(this._iterable, this._f);
+
+ Iterator<E> get iterator {
+ return new TakeWhileIterator<E>(_iterable.iterator, _f);
+ }
+}
+
+class TakeWhileIterator<E> extends Iterator<E> {
+ final Iterator<E> _iterator;
+ final _ElementPredicate<E> _f;
+ bool _isFinished = false;
+
+ TakeWhileIterator(this._iterator, this._f);
+
+ bool moveNext() {
+ if (_isFinished) return false;
+ if (!_iterator.moveNext() || !_f(_iterator.current)) {
+ _isFinished = true;
+ return false;
+ }
+ return true;
+ }
+
+ E get current {
+ if (_isFinished) return null;
+ return _iterator.current;
+ }
+}
+
+class SkipIterable<E> extends Iterable<E> {
+ final Iterable<E> _iterable;
+ final int _skipCount;
+
+ factory SkipIterable(Iterable<E> iterable, int count) {
+ if (iterable is EfficientLengthIterable) {
+ return new EfficientLengthSkipIterable<E>(iterable, count);
+ }
+ return new SkipIterable<E>._(iterable, _checkCount(count));
+ }
+
+ SkipIterable._(this._iterable, this._skipCount);
+
+ Iterable<E> skip(int count) {
+ return new SkipIterable<E>._(_iterable, _skipCount + _checkCount(count));
+ }
+
+ Iterator<E> get iterator {
+ return new SkipIterator<E>(_iterable.iterator, _skipCount);
+ }
+}
+
+class EfficientLengthSkipIterable<E> extends SkipIterable<E>
+ implements EfficientLengthIterable<E> {
+ factory EfficientLengthSkipIterable(Iterable<E> iterable, int count) {
+ return new EfficientLengthSkipIterable<E>._(iterable, _checkCount(count));
+ }
+
+ EfficientLengthSkipIterable._(Iterable<E> iterable, int count)
+ : super._(iterable, count);
+
+ int get length {
+ int length = _iterable.length - _skipCount;
+ if (length >= 0) return length;
+ return 0;
+ }
+
+ Iterable<E> skip(int count) {
+ return new EfficientLengthSkipIterable<E>._(
+ _iterable, _skipCount + _checkCount(count));
+ }
+}
+
+int _checkCount(int count) {
+ ArgumentError.checkNotNull(count, "count");
+ RangeError.checkNotNegative(count, "count");
+ return count;
+}
+
+class SkipIterator<E> extends Iterator<E> {
+ final Iterator<E> _iterator;
+ int _skipCount;
+
+ SkipIterator(this._iterator, this._skipCount) {
+ assert(_skipCount >= 0);
+ }
+
+ bool moveNext() {
+ for (int i = 0; i < _skipCount; i++) _iterator.moveNext();
+ _skipCount = 0;
+ return _iterator.moveNext();
+ }
+
+ E get current => _iterator.current;
+}
+
+class SkipWhileIterable<E> extends Iterable<E> {
+ final Iterable<E> _iterable;
+ final _ElementPredicate<E> _f;
+
+ SkipWhileIterable(this._iterable, this._f);
+
+ Iterator<E> get iterator {
+ return new SkipWhileIterator<E>(_iterable.iterator, _f);
+ }
+}
+
+class SkipWhileIterator<E> extends Iterator<E> {
+ final Iterator<E> _iterator;
+ final _ElementPredicate<E> _f;
+ bool _hasSkipped = false;
+
+ SkipWhileIterator(this._iterator, this._f);
+
+ bool moveNext() {
+ if (!_hasSkipped) {
+ _hasSkipped = true;
+ while (_iterator.moveNext()) {
+ if (!_f(_iterator.current)) return true;
+ }
+ }
+ return _iterator.moveNext();
+ }
+
+ E get current => _iterator.current;
+}
+
+/**
+ * The always empty [Iterable].
+ */
+class EmptyIterable<E> extends EfficientLengthIterable<E> {
+ const EmptyIterable();
+
+ Iterator<E> get iterator => const EmptyIterator();
+
+ void forEach(void action(E element)) {}
+
+ bool get isEmpty => true;
+
+ int get length => 0;
+
+ E get first {
+ throw IterableElementError.noElement();
+ }
+
+ E get last {
+ throw IterableElementError.noElement();
+ }
+
+ E get single {
+ throw IterableElementError.noElement();
+ }
+
+ E elementAt(int index) {
+ throw new RangeError.range(index, 0, 0, "index");
+ }
+
+ bool contains(Object element) => false;
+
+ bool every(bool test(E element)) => true;
+
+ bool any(bool test(E element)) => false;
+
+ E firstWhere(bool test(E element), {E orElse()}) {
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E lastWhere(bool test(E element), {E orElse()}) {
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ E singleWhere(bool test(E element), {E orElse()}) {
+ if (orElse != null) return orElse();
+ throw IterableElementError.noElement();
+ }
+
+ String join([String separator = ""]) => "";
+
+ Iterable<E> where(bool test(E element)) => this;
+
+ Iterable<T> map<T>(T f(E element)) => new EmptyIterable<T>();
+
+ E reduce(E combine(E value, E element)) {
+ throw IterableElementError.noElement();
+ }
+
+ T fold<T>(T initialValue, T combine(T previousValue, E element)) {
+ return initialValue;
+ }
+
+ Iterable<E> skip(int count) {
+ RangeError.checkNotNegative(count, "count");
+ return this;
+ }
+
+ Iterable<E> skipWhile(bool test(E element)) => this;
+
+ Iterable<E> take(int count) {
+ RangeError.checkNotNegative(count, "count");
+ return this;
+ }
+
+ Iterable<E> takeWhile(bool test(E element)) => this;
+
+ List<E> toList({bool growable: true}) => growable ? <E>[] : new List<E>(0);
+
+ Set<E> toSet() => new Set<E>();
+}
+
+/** The always empty iterator. */
+class EmptyIterator<E> implements Iterator<E> {
+ const EmptyIterator();
+ bool moveNext() => false;
+ E get current => null;
+}
+
+class FollowedByIterable<E> extends Iterable<E> {
+ final Iterable<E> _first;
+ final Iterable<E> _second;
+ FollowedByIterable(this._first, this._second);
+
+ factory FollowedByIterable.firstEfficient(
+ EfficientLengthIterable<E> first, Iterable<E> second) {
+ if (second is EfficientLengthIterable<E>) {
+ return new EfficientLengthFollowedByIterable<E>(first, second);
+ }
+ return new FollowedByIterable<E>(first, second);
+ }
+
+ Iterator<E> get iterator => new FollowedByIterator(_first, _second);
+
+ int get length => _first.length + _second.length;
+ bool get isEmpty => _first.isEmpty && _second.isEmpty;
+ bool get isNotEmpty => _first.isNotEmpty || _second.isNotEmpty;
+
+ // May be more efficient if either iterable is a Set.
+ bool contains(Object value) =>
+ _first.contains(value) || _second.contains(value);
+
+ E get first {
+ var iterator = _first.iterator;
+ if (iterator.moveNext()) return iterator.current;
+ return _second.first;
+ }
+
+ E get last {
+ var iterator = _second.iterator;
+ if (iterator.moveNext()) {
+ E last = iterator.current;
+ while (iterator.moveNext()) last = iterator.current;
+ return last;
+ }
+ return _first.last;
+ }
+
+ // If linear sequences of `followedBy` becomes an issue, we can flatten
+ // into a list of iterables instead of a tree or spine.
+}
+
+class EfficientLengthFollowedByIterable<E> extends FollowedByIterable<E>
+ implements EfficientLengthIterable<E> {
+ EfficientLengthFollowedByIterable(
+ EfficientLengthIterable<E> first, EfficientLengthIterable<E> second)
+ : super(first, second);
+
+ Iterable<E> skip(int count) {
+ int firstLength = _first.length;
+ if (count >= firstLength) return _second.skip(count - firstLength);
+ return new EfficientLengthFollowedByIterable<E>(
+ _first.skip(count), _second);
+ }
+
+ Iterable<E> take(int count) {
+ int firstLength = _first.length;
+ if (count <= firstLength) return _first.take(count);
+ return new EfficientLengthFollowedByIterable<E>(
+ _first, _second.take(count - firstLength));
+ }
+
+ E elementAt(int index) {
+ int firstLength = _first.length;
+ if (index < firstLength) return _first.elementAt(index);
+ return _second.elementAt(index - firstLength);
+ }
+
+ E get first {
+ if (_first.isNotEmpty) return _first.first;
+ return _second.first;
+ }
+
+ E get last {
+ if (_second.isNotEmpty) return _second.last;
+ return _first.last;
+ }
+}
+
+class FollowedByIterator<E> implements Iterator<E> {
+ Iterator<E> _currentIterator;
+ Iterable<E> _nextIterable;
+
+ FollowedByIterator(Iterable<E> first, this._nextIterable)
+ : _currentIterator = first.iterator;
+
+ bool moveNext() {
+ if (_currentIterator.moveNext()) return true;
+ if (_nextIterable != null) {
+ _currentIterator = _nextIterable.iterator;
+ _nextIterable = null;
+ return _currentIterator.moveNext();
+ }
+ return false;
+ }
+
+ E get current => _currentIterator.current;
+}
+
+class WhereTypeIterable<T> extends Iterable<T> {
+ final Iterable<Object> _source;
+ WhereTypeIterable(this._source);
+ Iterator<T> get iterator => new WhereTypeIterator<T>(_source.iterator);
+}
+
+class WhereTypeIterator<T> implements Iterator<T> {
+ final Iterator<Object> _source;
+ WhereTypeIterator(this._source);
+ bool moveNext() {
+ while (_source.moveNext()) {
+ if (_source.current is T) return true;
+ }
+ return false;
+ }
+
+ T get current => _source.current;
+}
+
+/**
+ * Creates errors throw by [Iterable] when the element count is wrong.
+ */
+abstract class IterableElementError {
+ /** Error thrown thrown by, e.g., [Iterable.first] when there is no result. */
+ static StateError noElement() => new StateError("No element");
+ /** Error thrown by, e.g., [Iterable.single] if there are too many results. */
+ static StateError tooMany() => new StateError("Too many elements");
+ /** Error thrown by, e.g., [List.setRange] if there are too few elements. */
+ static StateError tooFew() => new StateError("Too few elements");
+}
diff --git a/sdk_nnbd/lib/internal/linked_list.dart b/sdk_nnbd/lib/internal/linked_list.dart
new file mode 100644
index 0000000..31a6c01
--- /dev/null
+++ b/sdk_nnbd/lib/internal/linked_list.dart
@@ -0,0 +1,126 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+/// A rudimentary linked list.
+class LinkedList<T extends LinkedListEntry<T>> extends IterableBase<T> {
+ T first;
+ T last;
+ int length = 0;
+
+ bool get isEmpty => length == 0;
+
+ /**
+ * Adds [newLast] to the end of this linked list.
+ */
+ void add(T newLast) {
+ assert(newLast._next == null && newLast._previous == null);
+ if (last != null) {
+ assert(last._next == null);
+ last._next = newLast;
+ } else {
+ first = newLast;
+ }
+ newLast._previous = last;
+ last = newLast;
+ last._list = this;
+ length++;
+ }
+
+ /**
+ * Adds [newFirst] to the beginning of this linked list.
+ */
+ void addFirst(T newFirst) {
+ if (first != null) {
+ assert(first._previous == null);
+ first._previous = newFirst;
+ } else {
+ last = newFirst;
+ }
+ newFirst._next = first;
+ first = newFirst;
+ first._list = this;
+ length++;
+ }
+
+ /**
+ * Removes the given [node] from this list.
+ *
+ * If the entry is not in this linked list nothing happens.
+ *
+ * Also see [LinkedListEntry.unlink].
+ */
+ void remove(T node) {
+ if (node._list != this) return;
+ length--;
+ if (node._previous == null) {
+ assert(identical(node, first));
+ first = node._next;
+ } else {
+ node._previous._next = node._next;
+ }
+ if (node._next == null) {
+ assert(identical(node, last));
+ last = node._previous;
+ } else {
+ node._next._previous = node._previous;
+ }
+ node._next = node._previous = null;
+ node._list = null;
+ }
+
+ Iterator<T> get iterator => new _LinkedListIterator<T>(this);
+}
+
+class LinkedListEntry<T extends LinkedListEntry<T>> {
+ T _next;
+ T _previous;
+ LinkedList<T> _list;
+
+ /**
+ * Unlinks the element from its linked list.
+ *
+ * If the entry is not in a linked list, does nothing. Otherwise, this
+ * is equivalent to calling [LinkedList.remove] on the list this entry
+ * is currently in.
+ */
+ void unlink() {
+ if (_list == null) return;
+ _list.remove(this);
+ }
+}
+
+class _LinkedListIterator<T extends LinkedListEntry<T>> implements Iterator<T> {
+ /// The current element of the iterator.
+ // This field is writeable, but should only read by users of this class.
+ T current;
+
+ /// The list the iterator iterates over.
+ ///
+ /// Set to [null] if the provided list was empty (indicating that there were
+ /// no entries to iterate over).
+ ///
+ /// Set to [null] as soon as [moveNext] was invoked (indicating that the
+ /// iterator has to work with [current] from now on.
+ LinkedList<T> _list;
+
+ _LinkedListIterator(this._list) {
+ if (_list.length == 0) _list = null;
+ }
+
+ bool moveNext() {
+ // current is null if the iterator hasn't started iterating, or if the
+ // iteration is finished. In the first case, the [_list] field is not null.
+ if (current == null) {
+ if (_list == null) return false;
+ assert(_list.length > 0);
+ current = _list.first;
+ _list = null;
+ return true;
+ }
+ current = current._next;
+ return current != null;
+ }
+}
diff --git a/sdk_nnbd/lib/internal/list.dart b/sdk_nnbd/lib/internal/list.dart
new file mode 100644
index 0000000..e0ddd70
--- /dev/null
+++ b/sdk_nnbd/lib/internal/list.dart
@@ -0,0 +1,341 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+/**
+ * Mixin that throws on the length changing operations of [List].
+ *
+ * Intended to mix-in on top of [ListMixin] for fixed-length lists.
+ */
+abstract class FixedLengthListMixin<E> {
+ /** This operation is not supported by a fixed length list. */
+ set length(int newLength) {
+ throw new UnsupportedError(
+ "Cannot change the length of a fixed-length list");
+ }
+
+ /** This operation is not supported by a fixed length list. */
+ void add(E value) {
+ throw new UnsupportedError("Cannot add to a fixed-length list");
+ }
+
+ /** This operation is not supported by a fixed length list. */
+ void insert(int index, E value) {
+ throw new UnsupportedError("Cannot add to a fixed-length list");
+ }
+
+ /** This operation is not supported by a fixed length list. */
+ void insertAll(int at, Iterable<E> iterable) {
+ throw new UnsupportedError("Cannot add to a fixed-length list");
+ }
+
+ /** This operation is not supported by a fixed length list. */
+ void addAll(Iterable<E> iterable) {
+ throw new UnsupportedError("Cannot add to a fixed-length list");
+ }
+
+ /** This operation is not supported by a fixed length list. */
+ bool remove(Object element) {
+ throw new UnsupportedError("Cannot remove from a fixed-length list");
+ }
+
+ /** This operation is not supported by a fixed length list. */
+ void removeWhere(bool test(E element)) {
+ throw new UnsupportedError("Cannot remove from a fixed-length list");
+ }
+
+ /** This operation is not supported by a fixed length list. */
+ void retainWhere(bool test(E element)) {
+ throw new UnsupportedError("Cannot remove from a fixed-length list");
+ }
+
+ /** This operation is not supported by a fixed length list. */
+ void clear() {
+ throw new UnsupportedError("Cannot clear a fixed-length list");
+ }
+
+ /** This operation is not supported by a fixed length list. */
+ E removeAt(int index) {
+ throw new UnsupportedError("Cannot remove from a fixed-length list");
+ }
+
+ /** This operation is not supported by a fixed length list. */
+ E removeLast() {
+ throw new UnsupportedError("Cannot remove from a fixed-length list");
+ }
+
+ /** This operation is not supported by a fixed length list. */
+ void removeRange(int start, int end) {
+ throw new UnsupportedError("Cannot remove from a fixed-length list");
+ }
+
+ /** This operation is not supported by a fixed length list. */
+ void replaceRange(int start, int end, Iterable<E> iterable) {
+ throw new UnsupportedError("Cannot remove from a fixed-length list");
+ }
+}
+
+/**
+ * Mixin for an unmodifiable [List] class.
+ *
+ * This overrides all mutating methods with methods that throw.
+ * This mixin is intended to be mixed in on top of [ListMixin] on
+ * unmodifiable lists.
+ */
+abstract class UnmodifiableListMixin<E> implements List<E> {
+ /** This operation is not supported by an unmodifiable list. */
+ void operator []=(int index, E value) {
+ throw new UnsupportedError("Cannot modify an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ set length(int newLength) {
+ throw new UnsupportedError(
+ "Cannot change the length of an unmodifiable list");
+ }
+
+ set first(E element) {
+ throw new UnsupportedError("Cannot modify an unmodifiable list");
+ }
+
+ set last(E element) {
+ throw new UnsupportedError("Cannot modify an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void setAll(int at, Iterable<E> iterable) {
+ throw new UnsupportedError("Cannot modify an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void add(E value) {
+ throw new UnsupportedError("Cannot add to an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void insert(int index, E element) {
+ throw new UnsupportedError("Cannot add to an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void insertAll(int at, Iterable<E> iterable) {
+ throw new UnsupportedError("Cannot add to an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void addAll(Iterable<E> iterable) {
+ throw new UnsupportedError("Cannot add to an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ bool remove(Object element) {
+ throw new UnsupportedError("Cannot remove from an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void removeWhere(bool test(E element)) {
+ throw new UnsupportedError("Cannot remove from an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void retainWhere(bool test(E element)) {
+ throw new UnsupportedError("Cannot remove from an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void sort([Comparator<E> compare]) {
+ throw new UnsupportedError("Cannot modify an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void shuffle([Random random]) {
+ throw new UnsupportedError("Cannot modify an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void clear() {
+ throw new UnsupportedError("Cannot clear an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ E removeAt(int index) {
+ throw new UnsupportedError("Cannot remove from an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ E removeLast() {
+ throw new UnsupportedError("Cannot remove from an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+ throw new UnsupportedError("Cannot modify an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void removeRange(int start, int end) {
+ throw new UnsupportedError("Cannot remove from an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void replaceRange(int start, int end, Iterable<E> iterable) {
+ throw new UnsupportedError("Cannot remove from an unmodifiable list");
+ }
+
+ /** This operation is not supported by an unmodifiable list. */
+ void fillRange(int start, int end, [E fillValue]) {
+ throw new UnsupportedError("Cannot modify an unmodifiable list");
+ }
+}
+
+/**
+ * Abstract implementation of a fixed-length list.
+ *
+ * All operations are defined in terms of `length`, `operator[]` and
+ * `operator[]=`, which need to be implemented.
+ */
+abstract class FixedLengthListBase<E> = ListBase<E>
+ with FixedLengthListMixin<E>;
+
+/**
+ * Abstract implementation of an unmodifiable list.
+ *
+ * All operations are defined in terms of `length` and `operator[]`,
+ * which need to be implemented.
+ */
+abstract class UnmodifiableListBase<E> = ListBase<E>
+ with UnmodifiableListMixin<E>;
+
+class _ListIndicesIterable extends ListIterable<int> {
+ List _backedList;
+
+ _ListIndicesIterable(this._backedList);
+
+ int get length => _backedList.length;
+ int elementAt(int index) {
+ RangeError.checkValidIndex(index, this);
+ return index;
+ }
+}
+
+class ListMapView<E> extends UnmodifiableMapBase<int, E> {
+ List<E> _values;
+
+ ListMapView(this._values);
+
+ E operator [](Object key) => containsKey(key) ? _values[key] : null;
+ int get length => _values.length;
+
+ Iterable<E> get values => new SubListIterable<E>(_values, 0, null);
+ Iterable<int> get keys => new _ListIndicesIterable(_values);
+
+ bool get isEmpty => _values.isEmpty;
+ bool get isNotEmpty => _values.isNotEmpty;
+ bool containsValue(Object value) => _values.contains(value);
+ bool containsKey(Object key) => key is int && key >= 0 && key < length;
+
+ void forEach(void f(int key, E value)) {
+ int length = _values.length;
+ for (int i = 0; i < length; i++) {
+ f(i, _values[i]);
+ if (length != _values.length) {
+ throw new ConcurrentModificationError(_values);
+ }
+ }
+ }
+}
+
+class ReversedListIterable<E> extends ListIterable<E> {
+ Iterable<E> _source;
+ ReversedListIterable(this._source);
+
+ int get length => _source.length;
+
+ E elementAt(int index) => _source.elementAt(_source.length - 1 - index);
+}
+
+/**
+ * Creates errors thrown by unmodifiable lists when they are attempted modified.
+ *
+ * This class creates [UnsupportedError]s with specialized messages.
+ */
+abstract class UnmodifiableListError {
+ /** Error thrown when trying to add elements to an unmodifiable list. */
+ static UnsupportedError add() =>
+ new UnsupportedError("Cannot add to unmodifiable List");
+
+ /** Error thrown when trying to add elements to an unmodifiable list. */
+ static UnsupportedError change() =>
+ new UnsupportedError("Cannot change the content of an unmodifiable List");
+
+ /** Error thrown when trying to change the length of an unmodifiable list. */
+ static UnsupportedError length() =>
+ new UnsupportedError("Cannot change length of unmodifiable List");
+
+ /** Error thrown when trying to remove elements from an unmodifiable list. */
+ static UnsupportedError remove() =>
+ new UnsupportedError("Cannot remove from unmodifiable List");
+}
+
+/**
+ * Creates errors thrown by non-growable lists when they are attempted modified.
+ *
+ * This class creates [UnsupportedError]s with specialized messages.
+ */
+abstract class NonGrowableListError {
+ /** Error thrown when trying to add elements to an non-growable list. */
+ static UnsupportedError add() =>
+ new UnsupportedError("Cannot add to non-growable List");
+
+ /** Error thrown when trying to change the length of an non-growable list. */
+ static UnsupportedError length() =>
+ new UnsupportedError("Cannot change length of non-growable List");
+
+ /** Error thrown when trying to remove elements from an non-growable list. */
+ static UnsupportedError remove() =>
+ new UnsupportedError("Cannot remove from non-growable List");
+}
+
+/**
+ * Converts a growable list to a fixed length list with the same elements.
+ *
+ * For internal use only.
+ * Only works on growable lists as created by `[]` or `new List()`.
+ * May throw on any other list.
+ *
+ * The operation is efficient. It doesn't copy the elements, but converts
+ * the existing list directly to a fixed length list.
+ * That means that it is a destructive conversion.
+ * The original list should not be used afterwards.
+ *
+ * The returned list may be the same list as the original,
+ * or it may be a different list (according to [identical]).
+ * The original list may have changed type to be a fixed list,
+ * or become empty or been otherwise modified.
+ * It will still be a valid object, so references to it will not, e.g., crash
+ * the runtime if accessed, but no promises are made wrt. its contents.
+ *
+ * This unspecified behavior is the reason the function is not exposed to
+ * users. We allow the underlying implementation to make the most efficient
+ * conversion, at the cost of leaving the original list in an unspecified
+ * state.
+ */
+external List<T> makeListFixedLength<T>(List<T> growableList);
+
+/**
+ * Converts a fixed-length list to an unmodifiable list.
+ *
+ * For internal use only.
+ * Only works for core fixed-length lists as created by `new List(length)`,
+ * or as returned by [makeListFixedLength].
+ *
+ * The operation is efficient. It doesn't copy the elements, but converts
+ * the existing list directly to a fixed length list.
+ * That means that it is a destructive conversion.
+ * The original list should not be used afterwards.
+ *
+ * The unmodifiable list type is similar to the one used by const lists.
+ */
+external List<T> makeFixedListUnmodifiable<T>(List<T> fixedLengthList);
diff --git a/sdk_nnbd/lib/internal/patch.dart b/sdk_nnbd/lib/internal/patch.dart
new file mode 100644
index 0000000..3fc9733
--- /dev/null
+++ b/sdk_nnbd/lib/internal/patch.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of "dart:_internal";
+
+class _Patch {
+ const _Patch();
+}
+
+const _Patch patch = const _Patch();
diff --git a/sdk_nnbd/lib/internal/print.dart b/sdk_nnbd/lib/internal/print.dart
new file mode 100644
index 0000000..417003b
--- /dev/null
+++ b/sdk_nnbd/lib/internal/print.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+/**
+ * This function is set by the first allocation of a Zone.
+ *
+ * Once the function is set the core `print` function calls this closure instead
+ * of [printToConsole].
+ *
+ * This decouples the core library from the async library.
+ */
+void Function(String) printToZone = null;
+
+external void printToConsole(String line);
diff --git a/sdk_nnbd/lib/internal/sort.dart b/sdk_nnbd/lib/internal/sort.dart
new file mode 100644
index 0000000..d6cca2e
--- /dev/null
+++ b/sdk_nnbd/lib/internal/sort.dart
@@ -0,0 +1,385 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+/**
+ * Dual-Pivot Quicksort algorithm.
+ *
+ * This class implements the dual-pivot quicksort algorithm as presented in
+ * Vladimir Yaroslavskiy's paper.
+ *
+ * Some improvements have been copied from Android's implementation.
+ */
+class Sort {
+ // When a list has less then [:_INSERTION_SORT_THRESHOLD:] elements it will
+ // be sorted by an insertion sort.
+ static const int _INSERTION_SORT_THRESHOLD = 32;
+
+ /**
+ * Sorts all elements of the given list [:a:] according to the given
+ * [:compare:] function.
+ *
+ * The [:compare:] function takes two arguments [:x:] and [:y:] and returns
+ * -1 if [:x < y:],
+ * 0 if [:x == y:], and
+ * 1 if [:x > y:].
+ *
+ * The function's behavior must be consistent. It must not return different
+ * results for the same values.
+ */
+ static void sort<E>(List<E> a, int compare(E a, E b)) {
+ _doSort(a, 0, a.length - 1, compare);
+ }
+
+ /**
+ * Sorts all elements in the range [:from:] (inclusive) to [:to:] (exclusive)
+ * of the given list [:a:].
+ *
+ * If the given range is invalid an "OutOfRange" error is raised.
+ * TODO(floitsch): do we want an error?
+ *
+ * See [:sort:] for requirements of the [:compare:] function.
+ */
+ static void sortRange<E>(List<E> a, int from, int to, int compare(E a, E b)) {
+ if ((from < 0) || (to > a.length) || (to < from)) {
+ throw "OutOfRange";
+ }
+ _doSort(a, from, to - 1, compare);
+ }
+
+ /**
+ * Sorts the list in the interval [:left:] to [:right:] (both inclusive).
+ */
+ static void _doSort<E>(
+ List<E> a, int left, int right, int compare(E a, E b)) {
+ if ((right - left) <= _INSERTION_SORT_THRESHOLD) {
+ _insertionSort(a, left, right, compare);
+ } else {
+ _dualPivotQuicksort(a, left, right, compare);
+ }
+ }
+
+ static void _insertionSort<E>(
+ List<E> a, int left, int right, int compare(E a, E b)) {
+ for (int i = left + 1; i <= right; i++) {
+ var el = a[i];
+ int j = i;
+ while ((j > left) && (compare(a[j - 1], el) > 0)) {
+ a[j] = a[j - 1];
+ j--;
+ }
+ a[j] = el;
+ }
+ }
+
+ static void _dualPivotQuicksort<E>(
+ List<E> a, int left, int right, int compare(E a, E b)) {
+ assert(right - left > _INSERTION_SORT_THRESHOLD);
+
+ // Compute the two pivots by looking at 5 elements.
+ int sixth = (right - left + 1) ~/ 6;
+ int index1 = left + sixth;
+ int index5 = right - sixth;
+ int index3 = (left + right) ~/ 2; // The midpoint.
+ int index2 = index3 - sixth;
+ int index4 = index3 + sixth;
+
+ var el1 = a[index1];
+ var el2 = a[index2];
+ var el3 = a[index3];
+ var el4 = a[index4];
+ var el5 = a[index5];
+
+ // Sort the selected 5 elements using a sorting network.
+ if (compare(el1, el2) > 0) {
+ var t = el1;
+ el1 = el2;
+ el2 = t;
+ }
+ if (compare(el4, el5) > 0) {
+ var t = el4;
+ el4 = el5;
+ el5 = t;
+ }
+ if (compare(el1, el3) > 0) {
+ var t = el1;
+ el1 = el3;
+ el3 = t;
+ }
+ if (compare(el2, el3) > 0) {
+ var t = el2;
+ el2 = el3;
+ el3 = t;
+ }
+ if (compare(el1, el4) > 0) {
+ var t = el1;
+ el1 = el4;
+ el4 = t;
+ }
+ if (compare(el3, el4) > 0) {
+ var t = el3;
+ el3 = el4;
+ el4 = t;
+ }
+ if (compare(el2, el5) > 0) {
+ var t = el2;
+ el2 = el5;
+ el5 = t;
+ }
+ if (compare(el2, el3) > 0) {
+ var t = el2;
+ el2 = el3;
+ el3 = t;
+ }
+ if (compare(el4, el5) > 0) {
+ var t = el4;
+ el4 = el5;
+ el5 = t;
+ }
+
+ var pivot1 = el2;
+ var pivot2 = el4;
+
+ // el2 and el4 have been saved in the pivot variables. They will be written
+ // back, once the partitioning is finished.
+ a[index1] = el1;
+ a[index3] = el3;
+ a[index5] = el5;
+
+ a[index2] = a[left];
+ a[index4] = a[right];
+
+ int less = left + 1; // First element in the middle partition.
+ int great = right - 1; // Last element in the middle partition.
+
+ bool pivots_are_equal = (compare(pivot1, pivot2) == 0);
+ if (pivots_are_equal) {
+ var pivot = pivot1;
+ // Degenerated case where the partitioning becomes a Dutch national flag
+ // problem.
+ //
+ // [ | < pivot | == pivot | unpartitioned | > pivot | ]
+ // ^ ^ ^ ^ ^
+ // left less k great right
+ //
+ // a[left] and a[right] are undefined and are filled after the
+ // partitioning.
+ //
+ // Invariants:
+ // 1) for x in ]left, less[ : x < pivot.
+ // 2) for x in [less, k[ : x == pivot.
+ // 3) for x in ]great, right[ : x > pivot.
+ for (int k = less; k <= great; k++) {
+ var ak = a[k];
+ int comp = compare(ak, pivot);
+ if (comp == 0) continue;
+ if (comp < 0) {
+ if (k != less) {
+ a[k] = a[less];
+ a[less] = ak;
+ }
+ less++;
+ } else {
+ // comp > 0.
+ //
+ // Find the first element <= pivot in the range [k - 1, great] and
+ // put [:ak:] there. We know that such an element must exist:
+ // When k == less, then el3 (which is equal to pivot) lies in the
+ // interval. Otherwise a[k - 1] == pivot and the search stops at k-1.
+ // Note that in the latter case invariant 2 will be violated for a
+ // short amount of time. The invariant will be restored when the
+ // pivots are put into their final positions.
+ while (true) {
+ comp = compare(a[great], pivot);
+ if (comp > 0) {
+ great--;
+ // This is the only location in the while-loop where a new
+ // iteration is started.
+ continue;
+ } else if (comp < 0) {
+ // Triple exchange.
+ a[k] = a[less];
+ a[less++] = a[great];
+ a[great--] = ak;
+ break;
+ } else {
+ // comp == 0;
+ a[k] = a[great];
+ a[great--] = ak;
+ // Note: if great < k then we will exit the outer loop and fix
+ // invariant 2 (which we just violated).
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ // We partition the list into three parts:
+ // 1. < pivot1
+ // 2. >= pivot1 && <= pivot2
+ // 3. > pivot2
+ //
+ // During the loop we have:
+ // [ | < pivot1 | >= pivot1 && <= pivot2 | unpartitioned | > pivot2 | ]
+ // ^ ^ ^ ^ ^
+ // left less k great right
+ //
+ // a[left] and a[right] are undefined and are filled after the
+ // partitioning.
+ //
+ // Invariants:
+ // 1. for x in ]left, less[ : x < pivot1
+ // 2. for x in [less, k[ : pivot1 <= x && x <= pivot2
+ // 3. for x in ]great, right[ : x > pivot2
+ for (int k = less; k <= great; k++) {
+ var ak = a[k];
+ int comp_pivot1 = compare(ak, pivot1);
+ if (comp_pivot1 < 0) {
+ if (k != less) {
+ a[k] = a[less];
+ a[less] = ak;
+ }
+ less++;
+ } else {
+ int comp_pivot2 = compare(ak, pivot2);
+ if (comp_pivot2 > 0) {
+ while (true) {
+ int comp = compare(a[great], pivot2);
+ if (comp > 0) {
+ great--;
+ if (great < k) break;
+ // This is the only location inside the loop where a new
+ // iteration is started.
+ continue;
+ } else {
+ // a[great] <= pivot2.
+ comp = compare(a[great], pivot1);
+ if (comp < 0) {
+ // Triple exchange.
+ a[k] = a[less];
+ a[less++] = a[great];
+ a[great--] = ak;
+ } else {
+ // a[great] >= pivot1.
+ a[k] = a[great];
+ a[great--] = ak;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Move pivots into their final positions.
+ // We shrunk the list from both sides (a[left] and a[right] have
+ // meaningless values in them) and now we move elements from the first
+ // and third partition into these locations so that we can store the
+ // pivots.
+ a[left] = a[less - 1];
+ a[less - 1] = pivot1;
+ a[right] = a[great + 1];
+ a[great + 1] = pivot2;
+
+ // The list is now partitioned into three partitions:
+ // [ < pivot1 | >= pivot1 && <= pivot2 | > pivot2 ]
+ // ^ ^ ^ ^
+ // left less great right
+
+ // Recursive descent. (Don't include the pivot values.)
+ _doSort(a, left, less - 2, compare);
+ _doSort(a, great + 2, right, compare);
+
+ if (pivots_are_equal) {
+ // All elements in the second partition are equal to the pivot. No
+ // need to sort them.
+ return;
+ }
+
+ // In theory it should be enough to call _doSort recursively on the second
+ // partition.
+ // The Android source however removes the pivot elements from the recursive
+ // call if the second partition is too large (more than 2/3 of the list).
+ if (less < index1 && great > index5) {
+ while (compare(a[less], pivot1) == 0) {
+ less++;
+ }
+ while (compare(a[great], pivot2) == 0) {
+ great--;
+ }
+
+ // Copy paste of the previous 3-way partitioning with adaptions.
+ //
+ // We partition the list into three parts:
+ // 1. == pivot1
+ // 2. > pivot1 && < pivot2
+ // 3. == pivot2
+ //
+ // During the loop we have:
+ // [ == pivot1 | > pivot1 && < pivot2 | unpartitioned | == pivot2 ]
+ // ^ ^ ^
+ // less k great
+ //
+ // Invariants:
+ // 1. for x in [ *, less[ : x == pivot1
+ // 2. for x in [less, k[ : pivot1 < x && x < pivot2
+ // 3. for x in ]great, * ] : x == pivot2
+ for (int k = less; k <= great; k++) {
+ var ak = a[k];
+ int comp_pivot1 = compare(ak, pivot1);
+ if (comp_pivot1 == 0) {
+ if (k != less) {
+ a[k] = a[less];
+ a[less] = ak;
+ }
+ less++;
+ } else {
+ int comp_pivot2 = compare(ak, pivot2);
+ if (comp_pivot2 == 0) {
+ while (true) {
+ int comp = compare(a[great], pivot2);
+ if (comp == 0) {
+ great--;
+ if (great < k) break;
+ // This is the only location inside the loop where a new
+ // iteration is started.
+ continue;
+ } else {
+ // a[great] < pivot2.
+ comp = compare(a[great], pivot1);
+ if (comp < 0) {
+ // Triple exchange.
+ a[k] = a[less];
+ a[less++] = a[great];
+ a[great--] = ak;
+ } else {
+ // a[great] == pivot1.
+ a[k] = a[great];
+ a[great--] = ak;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ // The second partition has now been cleared of pivot elements and looks
+ // as follows:
+ // [ * | > pivot1 && < pivot2 | * ]
+ // ^ ^
+ // less great
+ // Sort the second partition using recursive descent.
+ _doSort(a, less, great, compare);
+ } else {
+ // The second partition looks as follows:
+ // [ * | >= pivot1 && <= pivot2 | * ]
+ // ^ ^
+ // less great
+ // Simply sort it by recursive descent.
+ _doSort(a, less, great, compare);
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/internal/symbol.dart b/sdk_nnbd/lib/internal/symbol.dart
new file mode 100644
index 0000000..54d235c
--- /dev/null
+++ b/sdk_nnbd/lib/internal/symbol.dart
@@ -0,0 +1,142 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+/**
+ * Implementation of [core.Symbol]. This class uses the same name as
+ * a core class so a user can't tell the difference.
+ *
+ * The purpose of this class is to hide [_name] from user code, but
+ * make it accessible to Dart platform code via the static method
+ * [getName].
+ */
+class Symbol implements core.Symbol {
+ final String _name;
+
+ /**
+ * Source of RegExp matching Dart reserved words.
+ *
+ * Reserved words are not allowed as identifiers.
+ */
+ static const String reservedWordRE =
+ r'(?:assert|break|c(?:a(?:se|tch)|lass|on(?:st|tinue))|d(?:efault|o)|'
+ r'e(?:lse|num|xtends)|f(?:alse|inal(?:ly)?|or)|i[fns]|n(?:ew|ull)|'
+ r'ret(?:hrow|urn)|s(?:uper|witch)|t(?:h(?:is|row)|r(?:ue|y))|'
+ r'v(?:ar|oid)|w(?:hile|ith))';
+ /**
+ * Source of RegExp matching any public identifier.
+ *
+ * A public identifier is a valid identifier (not a reserved word)
+ * that doesn't start with '_'.
+ */
+ static const String publicIdentifierRE =
+ r'(?!' '$reservedWordRE' r'\b(?!\$))[a-zA-Z$][\w$]*';
+ /**
+ * Source of RegExp matching any identifier.
+ *
+ * It matches identifiers but not reserved words. The identifiers
+ * may start with '_'.
+ */
+ static const String identifierRE =
+ r'(?!' '$reservedWordRE' r'\b(?!\$))[a-zA-Z$_][\w$]*';
+ /**
+ * Source of RegExp matching a declarable operator names.
+ *
+ * The operators that can be declared using `operator` declarations are
+ * also the only ones allowed as symbols. The name of the operators is
+ * the same as the operator itself except for unary minus, where the name
+ * is "unary-".
+ */
+ static const String operatorRE =
+ r'(?:[\-+*/%&|^]|\[\]=?|==|~/?|<[<=]?|>[>=]?|unary-)';
+
+ // Grammar if symbols:
+ // symbol ::= qualifiedName | <empty>
+ // qualifiedName ::= publicIdentifier '.' qualifiedName | name
+ // name ::= publicIdentifier
+ // | publicIdentifier '='
+ // | operator
+ // where publicIdentifier is any valid identifier (not a reserved word)
+ // that isn't private (doesn't start with '_').
+ //
+ // Railroad diagram of the accepted grammar:
+ //
+ // /----------------\
+ // | |
+ // | /-[.]-/ /-[=]-\
+ // \ / / \
+ // -------[id]------------------------->
+ // \ /
+ // \------[operator]---/
+ // \ /
+ // \------------/
+ //
+
+ /**
+ * RegExp that validates a non-empty non-private symbol.
+ *
+ * The empty symbol is handled before this regexp is used, and is not
+ * accepted.
+ */
+ static final RegExp publicSymbolPattern = new RegExp(
+ '^(?:$operatorRE\$|$publicIdentifierRE(?:=?\$|[.](?!\$)))+?\$');
+
+ // The grammar of symbols that may be private is the same as for public
+ // symbols, except that "publicIdentifier" is replaced by "identifier",
+ // which matches any identifier.
+
+ /**
+ * RegExp that validates a non-empty symbol.
+ *
+ * Private symbols are accepted.
+ *
+ * The empty symbol is handled before this regexp is used, and is not
+ * accepted.
+ */
+ static final RegExp symbolPattern =
+ new RegExp('^(?:$operatorRE\$|$identifierRE(?:=?\$|[.](?!\$)))+?\$');
+
+ external const Symbol(String name);
+
+ /**
+ * Platform-private method used by the mirror system to create
+ * otherwise invalid names.
+ */
+ const Symbol.unvalidated(this._name);
+
+ // This is called by dart2js.
+ Symbol.validated(String name) : this._name = validatePublicSymbol(name);
+
+ bool operator ==(other) => other is Symbol && _name == other._name;
+
+ external int get hashCode;
+
+ external toString();
+
+ /// Platform-private accessor which cannot be called from user libraries.
+ static String getName(Symbol symbol) => symbol._name;
+
+ static String validatePublicSymbol(String name) {
+ if (name.isEmpty || publicSymbolPattern.hasMatch(name)) return name;
+ if (name.startsWith('_')) {
+ // There may be other private parts in a qualified name than the first
+ // one, but this is a common case that deserves a specific error
+ // message.
+ throw new ArgumentError('"$name" is a private identifier');
+ }
+ throw new ArgumentError('"$name" is not a valid (qualified) symbol name');
+ }
+
+ /**
+ * Checks whether name is a valid symbol name.
+ *
+ * This test allows both private and non-private symbols.
+ */
+ static bool isValidSymbol(String name) {
+ return (name.isEmpty || symbolPattern.hasMatch(name));
+ }
+
+ external static String computeUnmangledName(Symbol symbol);
+}
diff --git a/sdk_nnbd/lib/io/bytes_builder.dart b/sdk_nnbd/lib/io/bytes_builder.dart
new file mode 100644
index 0000000..9113d44
--- /dev/null
+++ b/sdk_nnbd/lib/io/bytes_builder.dart
@@ -0,0 +1,233 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * Builds a list of bytes, allowing bytes and lists of bytes to be added at the
+ * end.
+ *
+ * Used to efficiently collect bytes and lists of bytes.
+ */
+abstract class BytesBuilder {
+ /**
+ * Construct a new empty [BytesBuilder].
+ *
+ * If [copy] is true, the data is always copied when added to the list. If
+ * it [copy] is false, the data is only copied if needed. That means that if
+ * the lists are changed after added to the [BytesBuilder], it may effect the
+ * output. Default is `true`.
+ */
+ factory BytesBuilder({bool copy: true}) {
+ if (copy) {
+ return new _CopyingBytesBuilder();
+ } else {
+ return new _BytesBuilder();
+ }
+ }
+
+ /**
+ * Appends [bytes] to the current contents of the builder.
+ *
+ * Each value of [bytes] will be bit-representation truncated to the range
+ * 0 .. 255.
+ */
+ void add(List<int> bytes);
+
+ /**
+ * Append [byte] to the current contents of the builder.
+ *
+ * The [byte] will be bit-representation truncated to the range 0 .. 255.
+ */
+ void addByte(int byte);
+
+ /**
+ * Returns the contents of `this` and clears `this`.
+ *
+ * The list returned is a view of the internal buffer, limited to the
+ * [length].
+ */
+ Uint8List takeBytes();
+
+ /**
+ * Returns a copy of the current contents of the builder.
+ *
+ * Leaves the contents of the builder intact.
+ */
+ Uint8List toBytes();
+
+ /**
+ * The number of bytes in the builder.
+ */
+ int get length;
+
+ /**
+ * Returns `true` if the buffer is empty.
+ */
+ bool get isEmpty;
+
+ /**
+ * Returns `true` if the buffer is not empty.
+ */
+ bool get isNotEmpty;
+
+ /**
+ * Clear the contents of the builder.
+ */
+ void clear();
+}
+
+class _CopyingBytesBuilder implements BytesBuilder {
+ // Start with 1024 bytes.
+ static const int _initSize = 1024;
+
+ // Safe for reuse because a fixed-length empty list is immutable.
+ static final _emptyList = new Uint8List(0);
+
+ int _length = 0;
+ Uint8List _buffer;
+
+ _CopyingBytesBuilder([int initialCapacity = 0])
+ : _buffer = (initialCapacity <= 0)
+ ? _emptyList
+ : new Uint8List(_pow2roundup(initialCapacity));
+
+ void add(List<int> bytes) {
+ int bytesLength = bytes.length;
+ if (bytesLength == 0) return;
+ int required = _length + bytesLength;
+ if (_buffer.length < required) {
+ _grow(required);
+ }
+ assert(_buffer.length >= required);
+ if (bytes is Uint8List) {
+ _buffer.setRange(_length, required, bytes);
+ } else {
+ for (int i = 0; i < bytesLength; i++) {
+ _buffer[_length + i] = bytes[i];
+ }
+ }
+ _length = required;
+ }
+
+ void addByte(int byte) {
+ if (_buffer.length == _length) {
+ // The grow algorithm always at least doubles.
+ // If we added one to _length it would quadruple unnecessarily.
+ _grow(_length);
+ }
+ assert(_buffer.length > _length);
+ _buffer[_length] = byte;
+ _length++;
+ }
+
+ void _grow(int required) {
+ // We will create a list in the range of 2-4 times larger than
+ // required.
+ int newSize = required * 2;
+ if (newSize < _initSize) {
+ newSize = _initSize;
+ } else {
+ newSize = _pow2roundup(newSize);
+ }
+ var newBuffer = new Uint8List(newSize);
+ newBuffer.setRange(0, _buffer.length, _buffer);
+ _buffer = newBuffer;
+ }
+
+ Uint8List takeBytes() {
+ if (_length == 0) return _emptyList;
+ var buffer = new Uint8List.view(_buffer.buffer, 0, _length);
+ clear();
+ return buffer;
+ }
+
+ Uint8List toBytes() {
+ if (_length == 0) return _emptyList;
+ return new Uint8List.fromList(
+ new Uint8List.view(_buffer.buffer, 0, _length));
+ }
+
+ int get length => _length;
+
+ bool get isEmpty => _length == 0;
+
+ bool get isNotEmpty => _length != 0;
+
+ void clear() {
+ _length = 0;
+ _buffer = _emptyList;
+ }
+
+ static int _pow2roundup(int x) {
+ assert(x > 0);
+ --x;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ return x + 1;
+ }
+}
+
+class _BytesBuilder implements BytesBuilder {
+ int _length = 0;
+ final List<Uint8List> _chunks = [];
+
+ void add(List<int> bytes) {
+ Uint8List typedBytes;
+ if (bytes is Uint8List) {
+ typedBytes = bytes;
+ } else {
+ typedBytes = new Uint8List.fromList(bytes);
+ }
+ _chunks.add(typedBytes);
+ _length += typedBytes.length;
+ }
+
+ void addByte(int byte) {
+ _chunks.add(new Uint8List(1)..[0] = byte);
+ _length++;
+ }
+
+ Uint8List takeBytes() {
+ if (_length == 0) return _CopyingBytesBuilder._emptyList;
+ if (_chunks.length == 1) {
+ var buffer = _chunks[0];
+ clear();
+ return buffer;
+ }
+ var buffer = new Uint8List(_length);
+ int offset = 0;
+ for (var chunk in _chunks) {
+ buffer.setRange(offset, offset + chunk.length, chunk);
+ offset += chunk.length;
+ }
+ clear();
+ return buffer;
+ }
+
+ Uint8List toBytes() {
+ if (_length == 0) return _CopyingBytesBuilder._emptyList;
+ var buffer = new Uint8List(_length);
+ int offset = 0;
+ for (var chunk in _chunks) {
+ buffer.setRange(offset, offset + chunk.length, chunk);
+ offset += chunk.length;
+ }
+ return buffer;
+ }
+
+ int get length => _length;
+
+ bool get isEmpty => _length == 0;
+
+ bool get isNotEmpty => _length != 0;
+
+ void clear() {
+ _length = 0;
+ _chunks.clear();
+ }
+}
diff --git a/sdk_nnbd/lib/io/common.dart b/sdk_nnbd/lib/io/common.dart
new file mode 100644
index 0000000..77b7587
--- /dev/null
+++ b/sdk_nnbd/lib/io/common.dart
@@ -0,0 +1,117 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+// Constants used when working with native ports.
+// These must match the constants in runtime/bin/dartutils.h class CObject.
+const int _successResponse = 0;
+const int _illegalArgumentResponse = 1;
+const int _osErrorResponse = 2;
+const int _fileClosedResponse = 3;
+
+const int _errorResponseErrorType = 0;
+const int _osErrorResponseErrorCode = 1;
+const int _osErrorResponseMessage = 2;
+
+// Functions used to receive exceptions from native ports.
+bool _isErrorResponse(response) =>
+ response is List && response[0] != _successResponse;
+
+/**
+ * Returns an Exception or an Error
+ */
+_exceptionFromResponse(response, String message, String path) {
+ assert(_isErrorResponse(response));
+ switch (response[_errorResponseErrorType]) {
+ case _illegalArgumentResponse:
+ return new ArgumentError("$message: $path");
+ case _osErrorResponse:
+ var err = new OSError(response[_osErrorResponseMessage],
+ response[_osErrorResponseErrorCode]);
+ return new FileSystemException(message, path, err);
+ case _fileClosedResponse:
+ return new FileSystemException("File closed", path);
+ default:
+ return new Exception("Unknown error");
+ }
+}
+
+/**
+ * Base class for all IO related exceptions.
+ */
+abstract class IOException implements Exception {
+ String toString() => "IOException";
+}
+
+/**
+ * An [OSError] object holds information about an error from the
+ * operating system.
+ */
+@pragma("vm:entry-point")
+class OSError {
+ /** Constant used to indicate that no OS error code is available. */
+ static const int noErrorCode = -1;
+
+ /// Error message supplied by the operating system. This may be `null` or
+ /// empty if no message is associated with the error.
+ final String message;
+
+ /// Error code supplied by the operating system.
+ ///
+ /// Will have the value [OSError.noErrorCode] if there is no error code
+ /// associated with the error.
+ final int errorCode;
+
+ /** Creates an OSError object from a message and an errorCode. */
+ @pragma("vm:entry-point")
+ const OSError([this.message = "", this.errorCode = noErrorCode]);
+
+ /** Converts an OSError object to a string representation. */
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.write("OS Error");
+ if (message.isNotEmpty) {
+ sb..write(": ")..write(message);
+ if (errorCode != noErrorCode) {
+ sb..write(", errno = ")..write(errorCode.toString());
+ }
+ } else if (errorCode != noErrorCode) {
+ sb..write(": errno = ")..write(errorCode.toString());
+ }
+ return sb.toString();
+ }
+}
+
+// Object for holding a buffer and an offset.
+class _BufferAndStart {
+ List<int> buffer;
+ int start;
+ _BufferAndStart(this.buffer, this.start);
+}
+
+// Ensure that the input List can be serialized through a native port.
+// Only Int8List and Uint8List Lists are serialized directly.
+// All other lists are first copied into a Uint8List. This has the added
+// benefit that it is faster to access from the C code as well.
+_BufferAndStart _ensureFastAndSerializableByteData(
+ List<int> buffer, int start, int end) {
+ if (buffer is Uint8List || buffer is Int8List) {
+ return new _BufferAndStart(buffer, start);
+ }
+ int length = end - start;
+ var newBuffer = new Uint8List(length);
+ int j = start;
+ for (int i = 0; i < length; i++) {
+ int value = buffer[j];
+ if (value == null) throw ArgumentError("List element is null at index $j");
+ newBuffer[i] = value;
+ j++;
+ }
+ return new _BufferAndStart(newBuffer, 0);
+}
+
+class _IOCrypto {
+ external static Uint8List getRandomBytes(int count);
+}
diff --git a/sdk_nnbd/lib/io/data_transformer.dart b/sdk_nnbd/lib/io/data_transformer.dart
new file mode 100644
index 0000000..33c615d
--- /dev/null
+++ b/sdk_nnbd/lib/io/data_transformer.dart
@@ -0,0 +1,673 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * Exposes ZLib options for input parameters.
+ *
+ * See http://www.zlib.net/manual.html for more documentation.
+ */
+abstract class ZLibOption {
+ /// Minimal value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits]
+ /// and [ZLibDecoder.windowBits].
+ static const int minWindowBits = 8;
+ @Deprecated("Use minWindowBits instead")
+ static const int MIN_WINDOW_BITS = 8;
+
+ /// Maximal value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits]
+ /// and [ZLibDecoder.windowBits].
+ static const int maxWindowBits = 15;
+ @Deprecated("Use maxWindowBits instead")
+ static const int MAX_WINDOW_BITS = 15;
+
+ /// Default value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits]
+ /// and [ZLibDecoder.windowBits].
+ static const int defaultWindowBits = 15;
+ @Deprecated("Use defaultWindowBits instead")
+ static const int DEFAULT_WINDOW_BITS = 15;
+
+ /// Minimal value for [ZLibCodec.level] and [ZLibEncoder.level].
+ static const int minLevel = -1;
+ @Deprecated("Use minLevel instead")
+ static const int MIN_LEVEL = -1;
+
+ /// Maximal value for [ZLibCodec.level] and [ZLibEncoder.level]
+ static const int maxLevel = 9;
+ @Deprecated("Use maxLevel instead")
+ static const int MAX_LEVEL = 9;
+
+ /// Default value for [ZLibCodec.level] and [ZLibEncoder.level].
+ static const int defaultLevel = 6;
+ @Deprecated("Use defaultLevel instead")
+ static const int DEFAULT_LEVEL = 6;
+
+ /// Minimal value for [ZLibCodec.memLevel] and [ZLibEncoder.memLevel].
+ static const int minMemLevel = 1;
+ @Deprecated("Use minMemLevel instead")
+ static const int MIN_MEM_LEVEL = 1;
+
+ /// Maximal value for [ZLibCodec.memLevel] and [ZLibEncoder.memLevel].
+ static const int maxMemLevel = 9;
+ @Deprecated("Use maxMemLevel instead")
+ static const int MAX_MEM_LEVEL = 9;
+
+ /// Default value for [ZLibCodec.memLevel] and [ZLibEncoder.memLevel].
+ static const int defaultMemLevel = 8;
+ @Deprecated("Use defaultMemLevel instead")
+ static const int DEFAULT_MEM_LEVEL = 8;
+
+ /// Recommended strategy for data produced by a filter (or predictor)
+ static const int strategyFiltered = 1;
+ @Deprecated("Use strategyFiltered instead")
+ static const int STRATEGY_FILTERED = 1;
+
+ /// Use this strategy to force Huffman encoding only (no string match)
+ static const int strategyHuffmanOnly = 2;
+ @Deprecated("Use strategyHuffmanOnly instead")
+ static const int STRATEGY_HUFFMAN_ONLY = 2;
+
+ /// Use this strategy to limit match distances to one (run-length encoding)
+ static const int strategyRle = 3;
+ @Deprecated("Use strategyRle instead")
+ static const int STRATEGY_RLE = 3;
+
+ /// This strategy prevents the use of dynamic Huffman codes, allowing for a
+ /// simpler decoder
+ static const int strategyFixed = 4;
+ @Deprecated("Use strategyFixed instead")
+ static const int STRATEGY_FIXED = 4;
+
+ /// Recommended strategy for normal data
+ static const int strategyDefault = 0;
+ @Deprecated("Use strategyDefault instead")
+ static const int STRATEGY_DEFAULT = 0;
+}
+
+/**
+ * An instance of the default implementation of the [ZLibCodec].
+ */
+const ZLibCodec zlib = const ZLibCodec._default();
+@Deprecated("Use zlib instead")
+const ZLibCodec ZLIB = zlib;
+
+/**
+ * The [ZLibCodec] encodes raw bytes to ZLib compressed bytes and decodes ZLib
+ * compressed bytes to raw bytes.
+ */
+class ZLibCodec extends Codec<List<int>, List<int>> {
+ /**
+ * When true, `GZip` frames will be added to the compressed data.
+ */
+ final bool gzip;
+
+ /**
+ * The compression-[level] can be set in the range of `-1..9`, with `6` being
+ * the default compression level. Levels above `6` will have higher
+ * compression rates at the cost of more CPU and memory usage. Levels below
+ * `6` will use less CPU and memory at the cost of lower compression rates.
+ */
+ final int level;
+
+ /**
+ * Specifies how much memory should be allocated for the internal compression
+ * state. `1` uses minimum memory but is slow and reduces compression ratio;
+ * `9` uses maximum memory for optimal speed. The default value is `8`.
+ *
+ * The memory requirements for deflate are (in bytes):
+ *
+ * (1 << (windowBits + 2)) + (1 << (memLevel + 9))
+ * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values)
+ */
+ final int memLevel;
+
+ /**
+ * Tunes the compression algorithm. Use the value strategyDefault for normal
+ * data, strategyFiltered for data produced by a filter (or predictor),
+ * strategyHuffmanOnly to force Huffman encoding only (no string match), or
+ * strategyRle to limit match distances to one (run-length encoding).
+ */
+ final int strategy;
+
+ /**
+ * Base two logarithm of the window size (the size of the history buffer). It
+ * should be in the range 8..15. Larger values result in better compression at
+ * the expense of memory usage. The default value is 15
+ */
+ final int windowBits;
+
+ /**
+ * When true, deflate generates raw data with no zlib header or trailer, and
+ * will not compute an adler32 check value
+ */
+ final bool raw;
+
+ /**
+ * Initial compression dictionary.
+ *
+ * It should consist of strings (byte sequences) that are likely to be
+ * encountered later in the data to be compressed, with the most commonly used
+ * strings preferably put towards the end of the dictionary. Using a
+ * dictionary is most useful when the data to be compressed is short and can
+ * be predicted with good accuracy; the data can then be compressed better
+ * than with the default empty dictionary.
+ */
+ final List<int> dictionary;
+
+ ZLibCodec(
+ {this.level: ZLibOption.defaultLevel,
+ this.windowBits: ZLibOption.defaultWindowBits,
+ this.memLevel: ZLibOption.defaultMemLevel,
+ this.strategy: ZLibOption.strategyDefault,
+ this.dictionary,
+ this.raw: false,
+ this.gzip: false}) {
+ _validateZLibeLevel(level);
+ _validateZLibMemLevel(memLevel);
+ _validateZLibStrategy(strategy);
+ _validateZLibWindowBits(windowBits);
+ }
+
+ const ZLibCodec._default()
+ : level = ZLibOption.defaultLevel,
+ windowBits = ZLibOption.defaultWindowBits,
+ memLevel = ZLibOption.defaultMemLevel,
+ strategy = ZLibOption.strategyDefault,
+ raw = false,
+ gzip = false,
+ dictionary = null;
+
+ /**
+ * Get a [ZLibEncoder] for encoding to `ZLib` compressed data.
+ */
+ ZLibEncoder get encoder => new ZLibEncoder(
+ gzip: false,
+ level: level,
+ windowBits: windowBits,
+ memLevel: memLevel,
+ strategy: strategy,
+ dictionary: dictionary,
+ raw: raw);
+
+ /**
+ * Get a [ZLibDecoder] for decoding `ZLib` compressed data.
+ */
+ ZLibDecoder get decoder =>
+ new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw);
+}
+
+/**
+ * An instance of the default implementation of the [GZipCodec].
+ */
+const GZipCodec gzip = const GZipCodec._default();
+@Deprecated("Use gzip instead")
+const GZipCodec GZIP = gzip;
+
+/**
+ * The [GZipCodec] encodes raw bytes to GZip compressed bytes and decodes GZip
+ * compressed bytes to raw bytes.
+ *
+ * The difference between [ZLibCodec] and [GZipCodec] is that the [GZipCodec]
+ * wraps the `ZLib` compressed bytes in `GZip` frames.
+ */
+class GZipCodec extends Codec<List<int>, List<int>> {
+ /**
+ * When true, `GZip` frames will be added to the compressed data.
+ */
+ final bool gzip;
+
+ /**
+ * The compression-[level] can be set in the range of `-1..9`, with `6` being
+ * the default compression level. Levels above `6` will have higher
+ * compression rates at the cost of more CPU and memory usage. Levels below
+ * `6` will use less CPU and memory at the cost of lower compression rates.
+ */
+ final int level;
+
+ /**
+ * Specifies how much memory should be allocated for the internal compression
+ * state. `1` uses minimum memory but is slow and reduces compression ratio;
+ * `9` uses maximum memory for optimal speed. The default value is `8`.
+ *
+ * The memory requirements for deflate are (in bytes):
+ *
+ * (1 << (windowBits + 2)) + (1 << (memLevel + 9))
+ * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values)
+ */
+ final int memLevel;
+
+ /**
+ * Tunes the compression algorithm. Use the value
+ * [ZLibOption.strategyDefault] for normal data,
+ * [ZLibOption.strategyFiltered] for data produced by a filter
+ * (or predictor), [ZLibOption.strategyHuffmanOnly] to force Huffman
+ * encoding only (no string match), or [ZLibOption.strategyRle] to limit
+ * match distances to one (run-length encoding).
+ */
+ final int strategy;
+
+ /**
+ * Base two logarithm of the window size (the size of the history buffer). It
+ * should be in the range `8..15`. Larger values result in better compression
+ * at the expense of memory usage. The default value is `15`
+ */
+ final int windowBits;
+
+ /**
+ * Initial compression dictionary.
+ *
+ * It should consist of strings (byte sequences) that are likely to be
+ * encountered later in the data to be compressed, with the most commonly used
+ * strings preferably put towards the end of the dictionary. Using a
+ * dictionary is most useful when the data to be compressed is short and can
+ * be predicted with good accuracy; the data can then be compressed better
+ * than with the default empty dictionary.
+ */
+ final List<int> dictionary;
+
+ /**
+ * When true, deflate generates raw data with no zlib header or trailer, and
+ * will not compute an adler32 check value
+ */
+ final bool raw;
+
+ GZipCodec(
+ {this.level: ZLibOption.defaultLevel,
+ this.windowBits: ZLibOption.defaultWindowBits,
+ this.memLevel: ZLibOption.defaultMemLevel,
+ this.strategy: ZLibOption.strategyDefault,
+ this.dictionary,
+ this.raw: false,
+ this.gzip: true}) {
+ _validateZLibeLevel(level);
+ _validateZLibMemLevel(memLevel);
+ _validateZLibStrategy(strategy);
+ _validateZLibWindowBits(windowBits);
+ }
+
+ const GZipCodec._default()
+ : level = ZLibOption.defaultLevel,
+ windowBits = ZLibOption.defaultWindowBits,
+ memLevel = ZLibOption.defaultMemLevel,
+ strategy = ZLibOption.strategyDefault,
+ raw = false,
+ gzip = true,
+ dictionary = null;
+
+ /**
+ * Get a [ZLibEncoder] for encoding to `GZip` compressed data.
+ */
+ ZLibEncoder get encoder => new ZLibEncoder(
+ gzip: true,
+ level: level,
+ windowBits: windowBits,
+ memLevel: memLevel,
+ strategy: strategy,
+ dictionary: dictionary,
+ raw: raw);
+
+ /**
+ * Get a [ZLibDecoder] for decoding `GZip` compressed data.
+ */
+ ZLibDecoder get decoder =>
+ new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw);
+}
+
+/**
+ * The [ZLibEncoder] encoder is used by [ZLibCodec] and [GZipCodec] to compress
+ * data.
+ */
+class ZLibEncoder extends Converter<List<int>, List<int>> {
+ /**
+ * When true, `GZip` frames will be added to the compressed data.
+ */
+ final bool gzip;
+
+ /**
+ * The compression-[level] can be set in the range of `-1..9`, with `6` being
+ * the default compression level. Levels above `6` will have higher
+ * compression rates at the cost of more CPU and memory usage. Levels below
+ * `6` will use less CPU and memory at the cost of lower compression rates.
+ */
+ final int level;
+
+ /**
+ * Specifies how much memory should be allocated for the internal compression
+ * state. `1` uses minimum memory but is slow and reduces compression ratio;
+ * `9` uses maximum memory for optimal speed. The default value is `8`.
+ *
+ * The memory requirements for deflate are (in bytes):
+ *
+ * (1 << (windowBits + 2)) + (1 << (memLevel + 9))
+ * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values)
+ */
+ final int memLevel;
+
+ /**
+ * Tunes the compression algorithm. Use the value
+ * [ZLibOption.strategyDefault] for normal data,
+ * [ZLibOption.strategyFiltered] for data produced by a filter
+ * (or predictor), [ZLibOption.strategyHuffmanOnly] to force Huffman
+ * encoding only (no string match), or [ZLibOption.strategyRle] to limit
+ * match distances to one (run-length encoding).
+ */
+ final int strategy;
+
+ /**
+ * Base two logarithm of the window size (the size of the history buffer). It
+ * should be in the range `8..15`. Larger values result in better compression
+ * at the expense of memory usage. The default value is `15`
+ */
+ final int windowBits;
+
+ /**
+ * Initial compression dictionary.
+ *
+ * It should consist of strings (byte sequences) that are likely to be
+ * encountered later in the data to be compressed, with the most commonly used
+ * strings preferably put towards the end of the dictionary. Using a
+ * dictionary is most useful when the data to be compressed is short and can
+ * be predicted with good accuracy; the data can then be compressed better
+ * than with the default empty dictionary.
+ */
+ final List<int> dictionary;
+
+ /**
+ * When true, deflate generates raw data with no zlib header or trailer, and
+ * will not compute an adler32 check value
+ */
+ final bool raw;
+
+ ZLibEncoder(
+ {this.gzip: false,
+ this.level: ZLibOption.defaultLevel,
+ this.windowBits: ZLibOption.defaultWindowBits,
+ this.memLevel: ZLibOption.defaultMemLevel,
+ this.strategy: ZLibOption.strategyDefault,
+ this.dictionary,
+ this.raw: false}) {
+ _validateZLibeLevel(level);
+ _validateZLibMemLevel(memLevel);
+ _validateZLibStrategy(strategy);
+ _validateZLibWindowBits(windowBits);
+ }
+
+ /**
+ * Convert a list of bytes using the options given to the ZLibEncoder
+ * constructor.
+ */
+ List<int> convert(List<int> bytes) {
+ _BufferSink sink = new _BufferSink();
+ startChunkedConversion(sink)
+ ..add(bytes)
+ ..close();
+ return sink.builder.takeBytes();
+ }
+
+ /**
+ * Start a chunked conversion using the options given to the [ZLibEncoder]
+ * constructor. While it accepts any [Sink] taking [List<int>]'s,
+ * the optimal sink to be passed as [sink] is a [ByteConversionSink].
+ */
+ ByteConversionSink startChunkedConversion(Sink<List<int>> sink) {
+ if (sink is! ByteConversionSink) {
+ sink = new ByteConversionSink.from(sink);
+ }
+ return new _ZLibEncoderSink._(
+ sink, gzip, level, windowBits, memLevel, strategy, dictionary, raw);
+ }
+}
+
+/**
+ * The [ZLibDecoder] is used by [ZLibCodec] and [GZipCodec] to decompress data.
+ */
+class ZLibDecoder extends Converter<List<int>, List<int>> {
+ /**
+ * Base two logarithm of the window size (the size of the history buffer). It
+ * should be in the range `8..15`. Larger values result in better compression
+ * at the expense of memory usage. The default value is `15`.
+ */
+ final int windowBits;
+
+ /**
+ * Initial compression dictionary.
+ *
+ * It should consist of strings (byte sequences) that are likely to be
+ * encountered later in the data to be compressed, with the most commonly used
+ * strings preferably put towards the end of the dictionary. Using a
+ * dictionary is most useful when the data to be compressed is short and can
+ * be predicted with good accuracy; the data can then be compressed better
+ * than with the default empty dictionary.
+ */
+ final List<int> dictionary;
+
+ /**
+ * When true, deflate generates raw data with no zlib header or trailer, and
+ * will not compute an adler32 check value
+ */
+ final bool raw;
+
+ ZLibDecoder(
+ {this.windowBits: ZLibOption.defaultWindowBits,
+ this.dictionary,
+ this.raw: false}) {
+ _validateZLibWindowBits(windowBits);
+ }
+
+ /**
+ * Convert a list of bytes using the options given to the [ZLibDecoder]
+ * constructor.
+ */
+ List<int> convert(List<int> bytes) {
+ _BufferSink sink = new _BufferSink();
+ startChunkedConversion(sink)
+ ..add(bytes)
+ ..close();
+ return sink.builder.takeBytes();
+ }
+
+ /**
+ * Start a chunked conversion. While it accepts any [Sink]
+ * taking [List<int>]'s, the optimal sink to be passed as [sink] is a
+ * [ByteConversionSink].
+ */
+ ByteConversionSink startChunkedConversion(Sink<List<int>> sink) {
+ if (sink is! ByteConversionSink) {
+ sink = new ByteConversionSink.from(sink);
+ }
+ return new _ZLibDecoderSink._(sink, windowBits, dictionary, raw);
+ }
+}
+
+/**
+ * The [RawZLibFilter] class provides a low-level interface to zlib.
+ */
+abstract class RawZLibFilter {
+ /**
+ * Returns a a [RawZLibFilter] whose [process] and [processed] methods
+ * compress data.
+ */
+ factory RawZLibFilter.deflateFilter({
+ bool gzip: false,
+ int level: ZLibOption.defaultLevel,
+ int windowBits: ZLibOption.defaultWindowBits,
+ int memLevel: ZLibOption.defaultMemLevel,
+ int strategy: ZLibOption.strategyDefault,
+ List<int> dictionary,
+ bool raw: false,
+ }) {
+ return _makeZLibDeflateFilter(
+ gzip, level, windowBits, memLevel, strategy, dictionary, raw);
+ }
+
+ /**
+ * Returns a a [RawZLibFilter] whose [process] and [processed] methods
+ * decompress data.
+ */
+ factory RawZLibFilter.inflateFilter({
+ int windowBits: ZLibOption.defaultWindowBits,
+ List<int> dictionary,
+ bool raw: false,
+ }) {
+ return _makeZLibInflateFilter(windowBits, dictionary, raw);
+ }
+
+ /**
+ * Call to process a chunk of data. A call to [process] should only be made
+ * when [processed] returns [:null:].
+ */
+ void process(List<int> data, int start, int end);
+
+ /**
+ * Get a chunk of processed data. When there are no more data available,
+ * [processed] will return [:null:]. Set [flush] to [:false:] for non-final
+ * calls to improve performance of some filters.
+ *
+ * The last call to [processed] should have [end] set to [:true:]. This will
+ * make sure an 'end' packet is written on the stream.
+ */
+ List<int> processed({bool flush: true, bool end: false});
+
+ external static RawZLibFilter _makeZLibDeflateFilter(
+ bool gzip,
+ int level,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ List<int> dictionary,
+ bool raw);
+
+ external static RawZLibFilter _makeZLibInflateFilter(
+ int windowBits, List<int> dictionary, bool raw);
+}
+
+class _BufferSink extends ByteConversionSink {
+ final BytesBuilder builder = new BytesBuilder(copy: false);
+
+ void add(List<int> chunk) {
+ builder.add(chunk);
+ }
+
+ void addSlice(List<int> chunk, int start, int end, bool isLast) {
+ if (chunk is Uint8List) {
+ Uint8List list = chunk;
+ builder.add(new Uint8List.view(list.buffer, start, end - start));
+ } else {
+ builder.add(chunk.sublist(start, end));
+ }
+ }
+
+ void close() {}
+}
+
+class _ZLibEncoderSink extends _FilterSink {
+ _ZLibEncoderSink._(
+ ByteConversionSink sink,
+ bool gzip,
+ int level,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ List<int> dictionary,
+ bool raw)
+ : super(
+ sink,
+ RawZLibFilter._makeZLibDeflateFilter(
+ gzip, level, windowBits, memLevel, strategy, dictionary, raw));
+}
+
+class _ZLibDecoderSink extends _FilterSink {
+ _ZLibDecoderSink._(
+ ByteConversionSink sink, int windowBits, List<int> dictionary, bool raw)
+ : super(sink,
+ RawZLibFilter._makeZLibInflateFilter(windowBits, dictionary, raw));
+}
+
+class _FilterSink extends ByteConversionSink {
+ final RawZLibFilter _filter;
+ final ByteConversionSink _sink;
+ bool _closed = false;
+ bool _empty = true;
+
+ _FilterSink(this._sink, this._filter);
+
+ void add(List<int> data) {
+ addSlice(data, 0, data.length, false);
+ }
+
+ void addSlice(List<int> data, int start, int end, bool isLast) {
+ if (_closed) return;
+ if (end == null) throw new ArgumentError.notNull("end");
+ RangeError.checkValidRange(start, end, data.length);
+ try {
+ _empty = false;
+ _BufferAndStart bufferAndStart =
+ _ensureFastAndSerializableByteData(data, start, end);
+ _filter.process(bufferAndStart.buffer, bufferAndStart.start,
+ end - (start - bufferAndStart.start));
+ List<int> out;
+ while ((out = _filter.processed(flush: false)) != null) {
+ _sink.add(out);
+ }
+ } catch (e) {
+ _closed = true;
+ rethrow;
+ }
+
+ if (isLast) close();
+ }
+
+ void close() {
+ if (_closed) return;
+ // Be sure to send process an empty chunk of data. Without this, the empty
+ // message would not have a GZip frame (if compressed with GZip).
+ if (_empty) _filter.process(const [], 0, 0);
+ try {
+ List<int> out;
+ while ((out = _filter.processed(end: true)) != null) {
+ _sink.add(out);
+ }
+ } catch (e) {
+ // TODO(kevmoo): not sure why this isn't a try/finally
+ _closed = true;
+ throw e;
+ }
+ _closed = true;
+ _sink.close();
+ }
+}
+
+void _validateZLibWindowBits(int windowBits) {
+ if (ZLibOption.minWindowBits > windowBits ||
+ ZLibOption.maxWindowBits < windowBits) {
+ throw new RangeError.range(
+ windowBits, ZLibOption.minWindowBits, ZLibOption.maxWindowBits);
+ }
+}
+
+void _validateZLibeLevel(int level) {
+ if (ZLibOption.minLevel > level || ZLibOption.maxLevel < level) {
+ throw new RangeError.range(level, ZLibOption.minLevel, ZLibOption.maxLevel);
+ }
+}
+
+void _validateZLibMemLevel(int memLevel) {
+ if (ZLibOption.minMemLevel > memLevel || ZLibOption.maxMemLevel < memLevel) {
+ throw new RangeError.range(
+ memLevel, ZLibOption.minMemLevel, ZLibOption.maxMemLevel);
+ }
+}
+
+void _validateZLibStrategy(int strategy) {
+ const strategies = const <int>[
+ ZLibOption.strategyFiltered,
+ ZLibOption.strategyHuffmanOnly,
+ ZLibOption.strategyRle,
+ ZLibOption.strategyFixed,
+ ZLibOption.strategyDefault
+ ];
+ if (strategies.indexOf(strategy) == -1) {
+ throw new ArgumentError("Unsupported 'strategy'");
+ }
+}
diff --git a/sdk_nnbd/lib/io/directory.dart b/sdk_nnbd/lib/io/directory.dart
new file mode 100644
index 0000000..2f141cb
--- /dev/null
+++ b/sdk_nnbd/lib/io/directory.dart
@@ -0,0 +1,344 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * A reference to a directory (or _folder_) on the file system.
+ *
+ * A Directory instance is an object holding a [path] on which operations can
+ * be performed. The path to the directory can be [absolute] or relative.
+ * You can get the parent directory using the getter [parent],
+ * a property inherited from [FileSystemEntity].
+ *
+ * In addition to being used as an instance to access the file system,
+ * Directory has a number of static properties, such as [systemTemp],
+ * which gets the system's temporary directory, and the getter and setter
+ * [current], which you can use to access or change the current directory.
+ *
+ * Create a new Directory object with a pathname to access the specified
+ * directory on the file system from your program.
+ *
+ * var myDir = new Directory('myDir');
+ *
+ * Most methods in this class occur in synchronous and asynchronous pairs,
+ * for example, [create] and [createSync].
+ * Unless you have a specific reason for using the synchronous version
+ * of a method, prefer the asynchronous version to avoid blocking your program.
+ *
+ * ## Create a directory
+ *
+ * The following code sample creates a directory using the [create] method.
+ * By setting the `recursive` parameter to true, you can create the
+ * named directory and all its necessary parent directories,
+ * if they do not already exist.
+ *
+ * import 'dart:io';
+ *
+ * void main() {
+ * // Creates dir/ and dir/subdir/.
+ * new Directory('dir/subdir').create(recursive: true)
+ * // The created directory is returned as a Future.
+ * .then((Directory directory) {
+ * print(directory.path);
+ * });
+ * }
+ *
+ * ## List a directory
+ *
+ * Use the [list] or [listSync] methods to get the files and directories
+ * contained by a directory.
+ * Set `recursive` to true to recursively list all subdirectories.
+ * Set `followLinks` to true to follow symbolic links.
+ * The list method returns a [Stream] that provides FileSystemEntity
+ * objects. Use the listen callback function to process each object
+ * as it become available.
+ *
+ * import 'dart:io';
+ *
+ * void main() {
+ * // Get the system temp directory.
+ * var systemTempDir = Directory.systemTemp;
+ *
+ * // List directory contents, recursing into sub-directories,
+ * // but not following symbolic links.
+ * systemTempDir.list(recursive: true, followLinks: false)
+ * .listen((FileSystemEntity entity) {
+ * print(entity.path);
+ * });
+ * }
+ *
+ * ## The use of Futures
+ *
+ * I/O operations can block a program for some period of time while it waits for
+ * the operation to complete. To avoid this, all
+ * methods involving I/O have an asynchronous variant which returns a [Future].
+ * This future completes when the I/O operation finishes. While the I/O
+ * operation is in progress, the Dart program is not blocked,
+ * and can perform other operations.
+ *
+ * For example,
+ * the [exists] method, which determines whether the directory exists,
+ * returns a boolean value using a Future.
+ * Use `then` to register a callback function, which is called when
+ * the value is ready.
+ *
+ * import 'dart:io';
+ *
+ * main() {
+ * final myDir = new Directory('dir');
+ * myDir.exists().then((isThere) {
+ * isThere ? print('exists') : print('non-existent');
+ * });
+ * }
+ *
+ *
+ * In addition to exists, the [stat], [rename], and
+ * other methods, return Futures.
+ *
+ * ## Other resources
+ *
+ * * [Dart by Example](https://www.dartlang.org/dart-by-example/#files-directories-and-symlinks)
+ * provides additional task-oriented code samples that show how to use
+ * various API from the Directory class and the related [File] class.
+ *
+ * * [I/O for Command-Line
+ * Apps](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartio---io-for-command-line-apps)
+ * a section from _A Tour of the Dart Libraries_ covers files and directories.
+ *
+ * * [Write Command-Line Apps](https://www.dartlang.org/docs/tutorials/cmdline/),
+ * a tutorial about writing command-line apps, includes information about
+ * files and directories.
+ */
+@pragma("vm:entry-point")
+abstract class Directory implements FileSystemEntity {
+ /**
+ * Gets the path of this directory.
+ */
+ String get path;
+
+ /**
+ * Creates a [Directory] object.
+ *
+ * If [path] is a relative path, it will be interpreted relative to the
+ * current working directory (see [Directory.current]), when used.
+ *
+ * If [path] is an absolute path, it will be immune to changes to the
+ * current working directory.
+ */
+ @pragma("vm:entry-point")
+ factory Directory(String path) {
+ final IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return new _Directory(path);
+ }
+ return overrides.createDirectory(path);
+ }
+
+ @pragma("vm:entry-point")
+ factory Directory.fromRawPath(Uint8List path) {
+ // TODO(bkonyi): Handle overrides.
+ return new _Directory.fromRawPath(path);
+ }
+
+ /**
+ * Create a Directory object from a URI.
+ *
+ * If [uri] cannot reference a directory this throws [UnsupportedError].
+ */
+ factory Directory.fromUri(Uri uri) => new Directory(uri.toFilePath());
+
+ /**
+ * Creates a directory object pointing to the current working
+ * directory.
+ */
+ static Directory get current {
+ final IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return _Directory.current;
+ }
+ return overrides.getCurrentDirectory();
+ }
+
+ /**
+ * Returns a [Uri] representing the directory's location.
+ *
+ * The returned URI's scheme is always "file" if the entity's [path] is
+ * absolute, otherwise the scheme will be empty.
+ * The returned URI's path always ends in a slash ('/').
+ */
+ Uri get uri;
+
+ /**
+ * Sets the current working directory of the Dart process including
+ * all running isolates. The new value set can be either a [Directory]
+ * or a [String].
+ *
+ * The new value is passed to the OS's system call unchanged, so a
+ * relative path passed as the new working directory will be
+ * resolved by the OS.
+ *
+ * Note that setting the current working directory is a synchronous
+ * operation and that it changes the working directory of *all*
+ * isolates.
+ *
+ * Use this with care - especially when working with asynchronous
+ * operations and multiple isolates. Changing the working directory,
+ * while asynchronous operations are pending or when other isolates
+ * are working with the file system, can lead to unexpected results.
+ */
+ static void set current(path) {
+ final IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ _Directory.current = path;
+ return;
+ }
+ overrides.setCurrentDirectory(path);
+ }
+
+ /**
+ * Creates the directory with this name.
+ *
+ * If [recursive] is false, only the last directory in the path is
+ * created. If [recursive] is true, all non-existing path components
+ * are created. If the directory already exists nothing is done.
+ *
+ * Returns a [:Future<Directory>:] that completes with this
+ * directory once it has been created. If the directory cannot be
+ * created the future completes with an exception.
+ */
+ Future<Directory> create({bool recursive: false});
+
+ /**
+ * Synchronously creates the directory with this name.
+ *
+ * If [recursive] is false, only the last directory in the path is
+ * created. If [recursive] is true, all non-existing path components
+ * are created. If the directory already exists nothing is done.
+ *
+ * If the directory cannot be created an exception is thrown.
+ */
+ void createSync({bool recursive: false});
+
+ /**
+ * Gets the system temp directory.
+ *
+ * Gets the directory provided by the operating system for creating
+ * temporary files and directories in.
+ * The location of the system temp directory is platform-dependent,
+ * and may be set by an environment variable.
+ */
+ static Directory get systemTemp {
+ final IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return _Directory.systemTemp;
+ }
+ return overrides.getSystemTempDirectory();
+ }
+
+ /**
+ * Creates a temporary directory in this directory. Additional random
+ * characters are appended to [prefix] to produce a unique directory
+ * name. If [prefix] is missing or null, the empty string is used
+ * for [prefix].
+ *
+ * Returns a [:Future<Directory>:] that completes with the newly
+ * created temporary directory.
+ */
+ Future<Directory> createTemp([String prefix]);
+
+ /**
+ * Synchronously creates a temporary directory in this directory.
+ * Additional random characters are appended to [prefix] to produce
+ * a unique directory name. If [prefix] is missing or null, the empty
+ * string is used for [prefix].
+ *
+ * Returns the newly created temporary directory.
+ */
+ Directory createTempSync([String prefix]);
+
+ Future<String> resolveSymbolicLinks();
+
+ String resolveSymbolicLinksSync();
+
+ /**
+ * Renames this directory. Returns a [:Future<Directory>:] that completes
+ * with a [Directory] instance for the renamed directory.
+ *
+ * If newPath identifies an existing directory, that directory is
+ * replaced. If newPath identifies an existing file, the operation
+ * fails and the future completes with an exception.
+ */
+ Future<Directory> rename(String newPath);
+
+ /**
+ * Synchronously renames this directory. Returns a [Directory]
+ * instance for the renamed directory.
+ *
+ * If newPath identifies an existing directory, that directory is
+ * replaced. If newPath identifies an existing file the operation
+ * fails and an exception is thrown.
+ */
+ Directory renameSync(String newPath);
+
+ /**
+ * Returns a [Directory] instance whose path is the absolute path to [this].
+ *
+ * The absolute path is computed by prefixing
+ * a relative path with the current working directory, and returning
+ * an absolute path unchanged.
+ */
+ Directory get absolute;
+
+ /**
+ * Lists the sub-directories and files of this [Directory].
+ * Optionally recurses into sub-directories.
+ *
+ * If [followLinks] is false, then any symbolic links found
+ * are reported as [Link] objects, rather than as directories or files,
+ * and are not recursed into.
+ *
+ * If [followLinks] is true, then working links are reported as
+ * directories or files, depending on
+ * their type, and links to directories are recursed into.
+ * Broken links are reported as [Link] objects.
+ * If a symbolic link makes a loop in the file system, then a recursive
+ * listing will not follow a link twice in the
+ * same recursive descent, but will report it as a [Link]
+ * the second time it is seen.
+ *
+ * The result is a stream of [FileSystemEntity] objects
+ * for the directories, files, and links.
+ */
+ Stream<FileSystemEntity> list(
+ {bool recursive: false, bool followLinks: true});
+
+ /**
+ * Lists the sub-directories and files of this [Directory].
+ * Optionally recurses into sub-directories.
+ *
+ * If [followLinks] is false, then any symbolic links found
+ * are reported as [Link] objects, rather than as directories or files,
+ * and are not recursed into.
+ *
+ * If [followLinks] is true, then working links are reported as
+ * directories or files, depending on
+ * their type, and links to directories are recursed into.
+ * Broken links are reported as [Link] objects.
+ * If a link makes a loop in the file system, then a recursive
+ * listing will not follow a link twice in the
+ * same recursive descent, but will report it as a [Link]
+ * the second time it is seen.
+ *
+ * Returns a [List] containing [FileSystemEntity] objects for the
+ * directories, files, and links.
+ */
+ List<FileSystemEntity> listSync(
+ {bool recursive: false, bool followLinks: true});
+
+ /**
+ * Returns a human readable string for this Directory instance.
+ */
+ String toString();
+}
diff --git a/sdk_nnbd/lib/io/directory_impl.dart b/sdk_nnbd/lib/io/directory_impl.dart
new file mode 100644
index 0000000..faed892
--- /dev/null
+++ b/sdk_nnbd/lib/io/directory_impl.dart
@@ -0,0 +1,447 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+class _Directory extends FileSystemEntity implements Directory {
+ String _path;
+ Uint8List _rawPath;
+
+ _Directory(String path) {
+ ArgumentError.checkNotNull(path, 'path');
+ _path = path;
+ _rawPath = FileSystemEntity._toUtf8Array(_path);
+ }
+
+ _Directory.fromRawPath(Uint8List rawPath) {
+ if (rawPath == null) {
+ throw new ArgumentError('rawPath cannot be null');
+ }
+ _rawPath = FileSystemEntity._toNullTerminatedUtf8Array(rawPath);
+ _path = FileSystemEntity._toStringFromUtf8Array(rawPath);
+ }
+
+ String get path => _path;
+
+ external static _current(_Namespace namespace);
+ external static _setCurrent(_Namespace namespace, Uint8List rawPath);
+ external static _createTemp(_Namespace namespace, Uint8List rawPath);
+ external static String _systemTemp(_Namespace namespace);
+ external static _exists(_Namespace namespace, Uint8List rawPath);
+ external static _create(_Namespace namespace, Uint8List rawPath);
+ external static _deleteNative(
+ _Namespace namespace, Uint8List rawPath, bool recursive);
+ external static _rename(
+ _Namespace namespace, Uint8List rawPath, String newPath);
+ external static void _fillWithDirectoryListing(
+ _Namespace namespace,
+ List<FileSystemEntity> list,
+ Uint8List rawPath,
+ bool recursive,
+ bool followLinks);
+
+ static Directory get current {
+ var result = _current(_Namespace._namespace);
+ if (result is OSError) {
+ throw new FileSystemException(
+ "Getting current working directory failed", "", result);
+ }
+ return new _Directory(result);
+ }
+
+ static void set current(path) {
+ Uint8List _rawPath;
+ if (path is _Directory) {
+ // For our internal Directory implementation, go ahead and use the raw
+ // path.
+ _rawPath = path._rawPath;
+ } else if (path is Directory) {
+ // FIXME(bkonyi): package:file passes in instances of classes which do
+ // not have _path defined, so we will fallback to using the existing
+ // path String for now.
+ _rawPath = FileSystemEntity._toUtf8Array(path.path);
+ } else if (path is String) {
+ _rawPath = FileSystemEntity._toUtf8Array(path);
+ } else {
+ throw new ArgumentError('${Error.safeToString(path)} is not a String or'
+ ' Directory');
+ }
+ if (!_EmbedderConfig._mayChdir) {
+ throw new UnsupportedError(
+ "This embedder disallows setting Directory.current");
+ }
+ var result = _setCurrent(_Namespace._namespace, _rawPath);
+ if (result is ArgumentError) throw result;
+ if (result is OSError) {
+ throw new FileSystemException(
+ "Setting current working directory failed", path, result);
+ }
+ }
+
+ Uri get uri {
+ return new Uri.directory(path);
+ }
+
+ Future<bool> exists() {
+ return _File._dispatchWithNamespace(
+ _IOService.directoryExists, [null, _rawPath]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionOrErrorFromResponse(response, "Exists failed");
+ }
+ return response == 1;
+ });
+ }
+
+ bool existsSync() {
+ var result = _exists(_Namespace._namespace, _rawPath);
+ if (result is OSError) {
+ throw new FileSystemException("Exists failed", path, result);
+ }
+ return (result == 1);
+ }
+
+ Directory get absolute => new Directory(_absolutePath);
+
+ Future<Directory> create({bool recursive: false}) {
+ if (recursive) {
+ return exists().then((exists) {
+ if (exists) return this;
+ if (path != parent.path) {
+ return parent.create(recursive: true).then((_) {
+ return create();
+ });
+ } else {
+ return create();
+ }
+ });
+ } else {
+ return _File._dispatchWithNamespace(
+ _IOService.directoryCreate, [null, _rawPath]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionOrErrorFromResponse(response, "Creation failed");
+ }
+ return this;
+ });
+ }
+ }
+
+ void createSync({bool recursive: false}) {
+ if (recursive) {
+ if (existsSync()) return;
+ if (path != parent.path) {
+ parent.createSync(recursive: true);
+ }
+ }
+ var result = _create(_Namespace._namespace, _rawPath);
+ if (result is OSError) {
+ throw new FileSystemException("Creation failed", path, result);
+ }
+ }
+
+ static Directory get systemTemp =>
+ new Directory(_systemTemp(_Namespace._namespace));
+
+ Future<Directory> createTemp([String prefix]) {
+ prefix ??= '';
+ if (path == '') {
+ throw new ArgumentError("Directory.createTemp called with an empty path. "
+ "To use the system temp directory, use Directory.systemTemp");
+ }
+ String fullPrefix;
+ // FIXME(bkonyi): here we're using `path` directly, which might cause
+ // issues if it is not UTF-8 encoded.
+ if (path.endsWith('/') || (Platform.isWindows && path.endsWith('\\'))) {
+ fullPrefix = "$path$prefix";
+ } else {
+ fullPrefix = "$path${Platform.pathSeparator}$prefix";
+ }
+ return _File._dispatchWithNamespace(_IOService.directoryCreateTemp,
+ [null, FileSystemEntity._toUtf8Array(fullPrefix)]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionOrErrorFromResponse(
+ response, "Creation of temporary directory failed");
+ }
+ return new Directory(response);
+ });
+ }
+
+ Directory createTempSync([String prefix]) {
+ prefix ??= '';
+ if (path == '') {
+ throw new ArgumentError("Directory.createTemp called with an empty path. "
+ "To use the system temp directory, use Directory.systemTemp");
+ }
+ String fullPrefix;
+ // FIXME(bkonyi): here we're using `path` directly, which might cause
+ // issues if it is not UTF-8 encoded.
+ if (path.endsWith('/') || (Platform.isWindows && path.endsWith('\\'))) {
+ fullPrefix = "$path$prefix";
+ } else {
+ fullPrefix = "$path${Platform.pathSeparator}$prefix";
+ }
+ var result = _createTemp(
+ _Namespace._namespace, FileSystemEntity._toUtf8Array(fullPrefix));
+ if (result is OSError) {
+ throw new FileSystemException(
+ "Creation of temporary directory failed", fullPrefix, result);
+ }
+ return new Directory(result);
+ }
+
+ Future<Directory> _delete({bool recursive: false}) {
+ return _File._dispatchWithNamespace(
+ _IOService.directoryDelete, [null, _rawPath, recursive])
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionOrErrorFromResponse(response, "Deletion failed");
+ }
+ return this;
+ });
+ }
+
+ void _deleteSync({bool recursive: false}) {
+ var result = _deleteNative(_Namespace._namespace, _rawPath, recursive);
+ if (result is OSError) {
+ throw new FileSystemException("Deletion failed", path, result);
+ }
+ }
+
+ Future<Directory> rename(String newPath) {
+ return _File._dispatchWithNamespace(
+ _IOService.directoryRename, [null, _rawPath, newPath]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionOrErrorFromResponse(response, "Rename failed");
+ }
+ return new Directory(newPath);
+ });
+ }
+
+ Directory renameSync(String newPath) {
+ if (newPath is! String) {
+ throw new ArgumentError();
+ }
+ var result = _rename(_Namespace._namespace, _rawPath, newPath);
+ if (result is OSError) {
+ throw new FileSystemException("Rename failed", path, result);
+ }
+ return new Directory(newPath);
+ }
+
+ Stream<FileSystemEntity> list(
+ {bool recursive: false, bool followLinks: true}) {
+ return new _AsyncDirectoryLister(
+ // FIXME(bkonyi): here we're using `path` directly, which might cause issues
+ // if it is not UTF-8 encoded.
+ FileSystemEntity._toUtf8Array(
+ FileSystemEntity._ensureTrailingPathSeparators(path)),
+ recursive,
+ followLinks)
+ .stream;
+ }
+
+ List<FileSystemEntity> listSync(
+ {bool recursive: false, bool followLinks: true}) {
+ if (recursive is! bool || followLinks is! bool) {
+ throw new ArgumentError();
+ }
+ var result = <FileSystemEntity>[];
+ _fillWithDirectoryListing(
+ _Namespace._namespace,
+ result,
+ // FIXME(bkonyi): here we're using `path` directly, which might cause issues
+ // if it is not UTF-8 encoded.
+ FileSystemEntity._toUtf8Array(
+ FileSystemEntity._ensureTrailingPathSeparators(path)),
+ recursive,
+ followLinks);
+ return result;
+ }
+
+ String toString() => "Directory: '$path'";
+
+ bool _isErrorResponse(response) =>
+ response is List && response[0] != _successResponse;
+
+ _exceptionOrErrorFromResponse(response, String message) {
+ assert(_isErrorResponse(response));
+ switch (response[_errorResponseErrorType]) {
+ case _illegalArgumentResponse:
+ return new ArgumentError();
+ case _osErrorResponse:
+ var err = new OSError(response[_osErrorResponseMessage],
+ response[_osErrorResponseErrorCode]);
+ return new FileSystemException(message, path, err);
+ default:
+ return new Exception("Unknown error");
+ }
+ }
+}
+
+abstract class _AsyncDirectoryListerOps {
+ external factory _AsyncDirectoryListerOps(int pointer);
+
+ int getPointer();
+}
+
+class _AsyncDirectoryLister {
+ static const int listFile = 0;
+ static const int listDirectory = 1;
+ static const int listLink = 2;
+ static const int listError = 3;
+ static const int listDone = 4;
+
+ static const int responseType = 0;
+ static const int responsePath = 1;
+ static const int responseComplete = 1;
+ static const int responseError = 2;
+
+ final Uint8List rawPath;
+ final bool recursive;
+ final bool followLinks;
+
+ StreamController<FileSystemEntity> controller;
+ bool canceled = false;
+ bool nextRunning = false;
+ bool closed = false;
+ _AsyncDirectoryListerOps _ops;
+ Completer closeCompleter = new Completer();
+
+ _AsyncDirectoryLister(this.rawPath, this.recursive, this.followLinks) {
+ controller = new StreamController<FileSystemEntity>(
+ onListen: onListen, onResume: onResume, onCancel: onCancel, sync: true);
+ }
+
+ // WARNING:
+ // Calling this function will increase the reference count on the native
+ // object that implements the async directory lister operations. It should
+ // only be called to pass the pointer to the IO Service, which will decrement
+ // the reference count when it is finished with it.
+ int _pointer() {
+ return (_ops == null) ? null : _ops.getPointer();
+ }
+
+ Stream<FileSystemEntity> get stream => controller.stream;
+
+ void onListen() {
+ _File._dispatchWithNamespace(_IOService.directoryListStart,
+ [null, rawPath, recursive, followLinks]).then((response) {
+ if (response is int) {
+ _ops = new _AsyncDirectoryListerOps(response);
+ next();
+ } else if (response is Error) {
+ controller.addError(response, response.stackTrace);
+ close();
+ } else {
+ error(response);
+ close();
+ }
+ });
+ }
+
+ void onResume() {
+ if (!nextRunning) {
+ next();
+ }
+ }
+
+ Future onCancel() {
+ canceled = true;
+ // If we are active, but not requesting, close.
+ if (!nextRunning) {
+ close();
+ }
+
+ return closeCompleter.future;
+ }
+
+ void next() {
+ if (canceled) {
+ close();
+ return;
+ }
+ if (controller.isPaused || nextRunning) {
+ return;
+ }
+ var pointer = _pointer();
+ if (pointer == null) {
+ return;
+ }
+ nextRunning = true;
+ _IOService._dispatch(_IOService.directoryListNext, [pointer])
+ .then((result) {
+ nextRunning = false;
+ if (result is List) {
+ next();
+ assert(result.length % 2 == 0);
+ for (int i = 0; i < result.length; i++) {
+ assert(i % 2 == 0);
+ switch (result[i++]) {
+ case listFile:
+ controller.add(new File.fromRawPath(result[i]));
+ break;
+ case listDirectory:
+ controller.add(new Directory.fromRawPath(result[i]));
+ break;
+ case listLink:
+ controller.add(new Link.fromRawPath(result[i]));
+ break;
+ case listError:
+ error(result[i]);
+ break;
+ case listDone:
+ canceled = true;
+ return;
+ }
+ }
+ } else {
+ controller.addError(new FileSystemException("Internal error"));
+ }
+ });
+ }
+
+ void _cleanup() {
+ controller.close();
+ closeCompleter.complete();
+ _ops = null;
+ }
+
+ void close() {
+ if (closed) {
+ return;
+ }
+ if (nextRunning) {
+ return;
+ }
+ closed = true;
+
+ var pointer = _pointer();
+ if (pointer == null) {
+ _cleanup();
+ } else {
+ _IOService._dispatch(_IOService.directoryListStop, [pointer])
+ .whenComplete(_cleanup);
+ }
+ }
+
+ void error(message) {
+ var errorType = message[responseError][_errorResponseErrorType];
+ if (errorType == _illegalArgumentResponse) {
+ controller.addError(new ArgumentError());
+ } else if (errorType == _osErrorResponse) {
+ var responseErrorInfo = message[responseError];
+ var err = new OSError(responseErrorInfo[_osErrorResponseMessage],
+ responseErrorInfo[_osErrorResponseErrorCode]);
+ var errorPath = message[responsePath];
+ if (errorPath == null) {
+ errorPath = utf8.decode(rawPath, allowMalformed: true);
+ } else if (errorPath is Uint8List) {
+ errorPath = utf8.decode(message[responsePath], allowMalformed: true);
+ }
+ controller.addError(
+ new FileSystemException("Directory listing failed", errorPath, err));
+ } else {
+ controller.addError(new FileSystemException("Internal error"));
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/io/embedder_config.dart b/sdk_nnbd/lib/io/embedder_config.dart
new file mode 100644
index 0000000..cbc94f7
--- /dev/null
+++ b/sdk_nnbd/lib/io/embedder_config.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/// Embedder-specific, fine-grained dart:io configuration.
+///
+/// This class contains per-Isolate flags that an embedder can set to put
+/// fine-grained limitations on what process-visible operations Isolates are
+/// permitted to use (e.g. exit()). By default, the whole dart:io API is
+/// enabled. When a disallowed operation is attempted, an `UnsupportedError` is
+/// thrown.
+@pragma('vm:entry-point')
+abstract class _EmbedderConfig {
+ /// The Isolate may set Directory.current.
+ static bool _mayChdir = true;
+
+ /// The Isolate may call exit().
+ @pragma("vm:entry-point")
+ static bool _mayExit = true;
+
+ // The Isolate may set Stdin.echoMode.
+ @pragma('vm:entry-point')
+ static bool _maySetEchoMode = true;
+
+ // The Isolate may set Stdin.lineMode.
+ @pragma('vm:entry-point')
+ static bool _maySetLineMode = true;
+
+ /// The Isolate may call sleep().
+ @pragma('vm:entry-point')
+ static bool _maySleep = true;
+
+ // TODO(zra): Consider adding:
+ // - an option to disallow modifying SecurityContext.defaultContext
+ // - an option to disallow closing stdout and stderr.
+}
diff --git a/sdk_nnbd/lib/io/eventhandler.dart b/sdk_nnbd/lib/io/eventhandler.dart
new file mode 100644
index 0000000..36f54e6
--- /dev/null
+++ b/sdk_nnbd/lib/io/eventhandler.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+class _EventHandler {
+ external static void _sendData(Object sender, SendPort sendPort, int data);
+}
diff --git a/sdk_nnbd/lib/io/file.dart b/sdk_nnbd/lib/io/file.dart
new file mode 100644
index 0000000..861ce47
--- /dev/null
+++ b/sdk_nnbd/lib/io/file.dart
@@ -0,0 +1,1010 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * The modes in which a File can be opened.
+ */
+class FileMode {
+ /// The mode for opening a file only for reading.
+ static const read = const FileMode._internal(0);
+ @Deprecated("Use read instead")
+ static const READ = read;
+
+ /// Mode for opening a file for reading and writing. The file is
+ /// overwritten if it already exists. The file is created if it does not
+ /// already exist.
+ static const write = const FileMode._internal(1);
+ @Deprecated("Use write instead")
+ static const WRITE = write;
+
+ /// Mode for opening a file for reading and writing to the
+ /// end of it. The file is created if it does not already exist.
+ static const append = const FileMode._internal(2);
+ @Deprecated("Use append instead")
+ static const APPEND = append;
+
+ /// Mode for opening a file for writing *only*. The file is
+ /// overwritten if it already exists. The file is created if it does not
+ /// already exist.
+ static const writeOnly = const FileMode._internal(3);
+ @Deprecated("Use writeOnly instead")
+ static const WRITE_ONLY = writeOnly;
+
+ /// Mode for opening a file for writing *only* to the
+ /// end of it. The file is created if it does not already exist.
+ static const writeOnlyAppend = const FileMode._internal(4);
+ @Deprecated("Use writeOnlyAppend instead")
+ static const WRITE_ONLY_APPEND = writeOnlyAppend;
+
+ final int _mode;
+
+ const FileMode._internal(this._mode);
+}
+
+/// The mode for opening a file only for reading.
+@Deprecated("Use FileMode.read instead")
+const READ = FileMode.read;
+
+/// The mode for opening a file for reading and writing. The file is
+/// overwritten if it already exists. The file is created if it does not
+/// already exist.
+@Deprecated("Use FileMode.write instead")
+const WRITE = FileMode.write;
+
+/// The mode for opening a file for reading and writing to the
+/// end of it. The file is created if it does not already exist.
+@Deprecated("Use FileMode.append instead")
+const APPEND = FileMode.append;
+
+/// Mode for opening a file for writing *only*. The file is
+/// overwritten if it already exists. The file is created if it does not
+/// already exist.
+@Deprecated("Use FileMode.writeOnly instead")
+const WRITE_ONLY = FileMode.writeOnly;
+
+/// Mode for opening a file for writing *only* to the
+/// end of it. The file is created if it does not already exist.
+@Deprecated("Use FileMode.writeOnlyAppend instead")
+const WRITE_ONLY_APPEND = FileMode.writeOnlyAppend;
+
+/// Type of lock when requesting a lock on a file.
+class FileLock {
+ /// Shared file lock.
+ static const shared = const FileLock._internal(1);
+ @Deprecated("Use shared instead")
+ static const SHARED = shared;
+
+ /// Exclusive file lock.
+ static const exclusive = const FileLock._internal(2);
+ @Deprecated("Use exclusive instead")
+ static const EXCLUSIVE = exclusive;
+
+ /// Blocking shared file lock.
+ static const blockingShared = const FileLock._internal(3);
+ @Deprecated("Use blockingShared instead")
+ static const BLOCKING_SHARED = blockingShared;
+
+ /// Blocking exclusive file lock.
+ static const blockingExclusive = const FileLock._internal(4);
+ @Deprecated("Use blockingExclusive instead")
+ static const BLOCKING_EXCLUSIVE = blockingExclusive;
+
+ final int _type;
+
+ const FileLock._internal(this._type);
+}
+
+/**
+ * A reference to a file on the file system.
+ *
+ * A File instance is an object that holds a [path] on which operations can
+ * be performed.
+ * You can get the parent directory of the file using the getter [parent],
+ * a property inherited from [FileSystemEntity].
+ *
+ * Create a new File object with a pathname to access the specified file on the
+ * file system from your program.
+ *
+ * var myFile = new File('file.txt');
+ *
+ * The File class contains methods for manipulating files and their contents.
+ * Using methods in this class, you can open and close files, read to and write
+ * from them, create and delete them, and check for their existence.
+ *
+ * When reading or writing a file, you can use streams (with [openRead]),
+ * random access operations (with [open]),
+ * or convenience methods such as [readAsString],
+ *
+ * Most methods in this class occur in synchronous and asynchronous pairs,
+ * for example, [readAsString] and [readAsStringSync].
+ * Unless you have a specific reason for using the synchronous version
+ * of a method, prefer the asynchronous version to avoid blocking your program.
+ *
+ * ## If path is a link
+ *
+ * If [path] is a symbolic link, rather than a file,
+ * then the methods of File operate on the ultimate target of the
+ * link, except for [delete] and [deleteSync], which operate on
+ * the link.
+ *
+ * ## Read from a file
+ *
+ * The following code sample reads the entire contents from a file as a string
+ * using the asynchronous [readAsString] method:
+ *
+ * import 'dart:async';
+ * import 'dart:io';
+ *
+ * void main() {
+ * new File('file.txt').readAsString().then((String contents) {
+ * print(contents);
+ * });
+ * }
+ *
+ * A more flexible and useful way to read a file is with a [Stream].
+ * Open the file with [openRead], which returns a stream that
+ * provides the data in the file as chunks of bytes.
+ * Listen to the stream for data and process as needed.
+ * You can use various transformers in succession to manipulate the
+ * data into the required format or to prepare it for output.
+ *
+ * You might want to use a stream to read large files,
+ * to manipulate the data with transformers,
+ * or for compatibility with another API, such as [WebSocket]s.
+ *
+ * import 'dart:io';
+ * import 'dart:convert';
+ * import 'dart:async';
+ *
+ * main() {
+ * final file = new File('file.txt');
+ * Stream<List<int>> inputStream = file.openRead();
+ *
+ * inputStream
+ * .transform(utf8.decoder) // Decode bytes to UTF-8.
+ * .transform(new LineSplitter()) // Convert stream to individual lines.
+ * .listen((String line) { // Process results.
+ * print('$line: ${line.length} bytes');
+ * },
+ * onDone: () { print('File is now closed.'); },
+ * onError: (e) { print(e.toString()); });
+ * }
+ *
+ * ## Write to a file
+ *
+ * To write a string to a file, use the [writeAsString] method:
+ *
+ * import 'dart:io';
+ *
+ * void main() {
+ * final filename = 'file.txt';
+ * new File(filename).writeAsString('some content')
+ * .then((File file) {
+ * // Do something with the file.
+ * });
+ * }
+ *
+ * You can also write to a file using a [Stream]. Open the file with
+ * [openWrite], which returns an [IOSink] to which you can write data.
+ * Be sure to close the sink with the [IOSink.close] method.
+ *
+ * import 'dart:io';
+ *
+ * void main() {
+ * var file = new File('file.txt');
+ * var sink = file.openWrite();
+ * sink.write('FILE ACCESSED ${new DateTime.now()}\n');
+ *
+ * // Close the IOSink to free system resources.
+ * sink.close();
+ * }
+ *
+ * ## The use of Futures
+ *
+ * To avoid unintentional blocking of the program,
+ * several methods use a [Future] to return a value. For example,
+ * the [length] method, which gets the length of a file, returns a Future.
+ * Use `then` to register a callback function, which is called when
+ * the value is ready.
+ *
+ * import 'dart:io';
+ *
+ * main() {
+ * final file = new File('file.txt');
+ *
+ * file.length().then((len) {
+ * print(len);
+ * });
+ * }
+ *
+ * In addition to length, the [exists], [lastModified], [stat], and
+ * other methods, return Futures.
+ *
+ * ## Other resources
+ *
+ * * [Dart by Example](https://www.dartlang.org/dart-by-example/#files-directories-and-symlinks)
+ * provides additional task-oriented code samples that show how to use
+ * various API from the Directory class and the related [File] class.
+ *
+ * * [I/O for Command-Line
+ * Apps](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartio---io-for-command-line-apps)
+ * a section from _A Tour of the Dart Libraries_ covers files and directories.
+ *
+ * * [Write Command-Line Apps](https://www.dartlang.org/docs/tutorials/cmdline/),
+ * a tutorial about writing command-line apps, includes information about
+ * files and directories.
+ */
+@pragma("vm:entry-point")
+abstract class File implements FileSystemEntity {
+ /**
+ * Creates a [File] object.
+ *
+ * If [path] is a relative path, it will be interpreted relative to the
+ * current working directory (see [Directory.current]), when used.
+ *
+ * If [path] is an absolute path, it will be immune to changes to the
+ * current working directory.
+ */
+ @pragma("vm:entry-point")
+ factory File(String path) {
+ final IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return new _File(path);
+ }
+ return overrides.createFile(path);
+ }
+
+ /**
+ * Create a File object from a URI.
+ *
+ * If [uri] cannot reference a file this throws [UnsupportedError].
+ */
+ factory File.fromUri(Uri uri) => new File(uri.toFilePath());
+
+ /**
+ * Creates a File object from a raw path, that is, a sequence of bytes
+ * as represented by the OS.
+ */
+ @pragma("vm:entry-point")
+ factory File.fromRawPath(Uint8List rawPath) {
+ // TODO(bkonyi): Handle overrides.
+ return new _File.fromRawPath(rawPath);
+ }
+
+ /**
+ * Create the file. Returns a `Future<File>` that completes with
+ * the file when it has been created.
+ *
+ * If [recursive] is false, the default, the file is created only if
+ * all directories in the path exist. If [recursive] is true, all
+ * non-existing path components are created.
+ *
+ * Existing files are left untouched by [create]. Calling [create] on an
+ * existing file might fail if there are restrictive permissions on
+ * the file.
+ *
+ * Completes the future with a [FileSystemException] if the operation fails.
+ */
+ Future<File> create({bool recursive: false});
+
+ /**
+ * Synchronously create the file. Existing files are left untouched
+ * by [createSync]. Calling [createSync] on an existing file might fail
+ * if there are restrictive permissions on the file.
+ *
+ * If [recursive] is false, the default, the file is created
+ * only if all directories in the path exist.
+ * If [recursive] is true, all non-existing path components are created.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ void createSync({bool recursive: false});
+
+ /**
+ * Renames this file. Returns a `Future<File>` that completes
+ * with a [File] instance for the renamed file.
+ *
+ * If [newPath] identifies an existing file, that file is
+ * replaced. If [newPath] identifies an existing directory, the
+ * operation fails and the future completes with an exception.
+ */
+ Future<File> rename(String newPath);
+
+ /**
+ * Synchronously renames this file. Returns a [File]
+ * instance for the renamed file.
+ *
+ * If [newPath] identifies an existing file, that file is
+ * replaced. If [newPath] identifies an existing directory the
+ * operation fails and an exception is thrown.
+ */
+ File renameSync(String newPath);
+
+ /**
+ * Copy this file. Returns a `Future<File>` that completes
+ * with a [File] instance for the copied file.
+ *
+ * If [newPath] identifies an existing file, that file is
+ * replaced. If [newPath] identifies an existing directory, the
+ * operation fails and the future completes with an exception.
+ */
+ Future<File> copy(String newPath);
+
+ /**
+ * Synchronously copy this file. Returns a [File]
+ * instance for the copied file.
+ *
+ * If [newPath] identifies an existing file, that file is
+ * replaced. If [newPath] identifies an existing directory the
+ * operation fails and an exception is thrown.
+ */
+ File copySync(String newPath);
+
+ /**
+ * Get the length of the file. Returns a `Future<int>` that
+ * completes with the length in bytes.
+ */
+ Future<int> length();
+
+ /**
+ * Synchronously get the length of the file.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ int lengthSync();
+
+ /**
+ * Returns a [File] instance whose path is the absolute path to [this].
+ *
+ * The absolute path is computed by prefixing
+ * a relative path with the current working directory, and returning
+ * an absolute path unchanged.
+ */
+ File get absolute;
+
+/**
+ * Get the last-accessed time of the file.
+ *
+ * Returns a `Future<DateTime>` that completes with the date and time when the
+ * file was last accessed, if the information is available.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ Future<DateTime> lastAccessed();
+
+/**
+ * Get the last-accessed time of the file.
+ *
+ * Returns the date and time when the file was last accessed,
+ * if the information is available. Blocks until the information can be returned
+ * or it is determined that the information is not available.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ DateTime lastAccessedSync();
+
+ /**
+ * Modifies the time the file was last accessed.
+ *
+ * Returns a [Future] that completes once the operation has completed.
+ *
+ * Throws a [FileSystemException] if the time cannot be set.
+ */
+ Future setLastAccessed(DateTime time);
+
+ /**
+ * Synchronously modifies the time the file was last accessed.
+ *
+ * Throws a [FileSystemException] if the time cannot be set.
+ */
+ void setLastAccessedSync(DateTime time);
+
+/**
+ * Get the last-modified time of the file.
+ *
+ * Returns a `Future<DateTime>` that completes with the date and time when the
+ * file was last modified, if the information is available.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ Future<DateTime> lastModified();
+
+/**
+ * Get the last-modified time of the file.
+ *
+ * Returns the date and time when the file was last modified,
+ * if the information is available. Blocks until the information can be returned
+ * or it is determined that the information is not available.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ DateTime lastModifiedSync();
+
+ /**
+ * Modifies the time the file was last modified.
+ *
+ * Returns a [Future] that completes once the operation has completed.
+ *
+ * Throws a [FileSystemException] if the time cannot be set.
+ */
+ Future setLastModified(DateTime time);
+
+ /**
+ * Synchronously modifies the time the file was last modified.
+ *
+ * If the attributes cannot be set, throws a [FileSystemException].
+ */
+ void setLastModifiedSync(DateTime time);
+
+ /**
+ * Open the file for random access operations. Returns a
+ * `Future<RandomAccessFile>` that completes with the opened
+ * random access file. [RandomAccessFile]s must be closed using the
+ * [RandomAccessFile.close] method.
+ *
+ * Files can be opened in three modes:
+ *
+ * [FileMode.read]: open the file for reading.
+ *
+ * [FileMode.write]: open the file for both reading and writing and
+ * truncate the file to length zero. If the file does not exist the
+ * file is created.
+ *
+ * [FileMode.append]: same as [FileMode.write] except that the file is
+ * not truncated.
+ */
+ Future<RandomAccessFile> open({FileMode mode: FileMode.read});
+
+ /**
+ * Synchronously open the file for random access operations. The
+ * result is a [RandomAccessFile] on which random access operations
+ * can be performed. Opened [RandomAccessFile]s must be closed using
+ * the [RandomAccessFile.close] method.
+ *
+ * See [open] for information on the [mode] argument.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ RandomAccessFile openSync({FileMode mode: FileMode.read});
+
+ /**
+ * Create a new independent [Stream] for the contents of this file.
+ *
+ * If [start] is present, the file will be read from byte-offset [start].
+ * Otherwise from the beginning (index 0).
+ *
+ * If [end] is present, only up to byte-index [end] will be read. Otherwise,
+ * until end of file.
+ *
+ * In order to make sure that system resources are freed, the stream
+ * must be read to completion or the subscription on the stream must
+ * be cancelled.
+ */
+ Stream<List<int>> openRead([int start, int end]);
+
+ /**
+ * Creates a new independent [IOSink] for the file. The
+ * [IOSink] must be closed when no longer used, to free
+ * system resources.
+ *
+ * An [IOSink] for a file can be opened in two modes:
+ *
+ * * [FileMode.write]: truncates the file to length zero.
+ * * [FileMode.append]: sets the initial write position to the end
+ * of the file.
+ *
+ * When writing strings through the returned [IOSink] the encoding
+ * specified using [encoding] will be used. The returned [IOSink]
+ * has an `encoding` property which can be changed after the
+ * [IOSink] has been created.
+ */
+ IOSink openWrite({FileMode mode: FileMode.write, Encoding encoding: utf8});
+
+ /**
+ * Read the entire file contents as a list of bytes. Returns a
+ * `Future<Uint8List>` that completes with the list of bytes that
+ * is the contents of the file.
+ */
+ Future<Uint8List> readAsBytes();
+
+ /**
+ * Synchronously read the entire file contents as a list of bytes.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ Uint8List readAsBytesSync();
+
+ /**
+ * Read the entire file contents as a string using the given
+ * [Encoding].
+ *
+ * Returns a `Future<String>` that completes with the string once
+ * the file contents has been read.
+ */
+ Future<String> readAsString({Encoding encoding: utf8});
+
+ /**
+ * Synchronously read the entire file contents as a string using the
+ * given [Encoding].
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ String readAsStringSync({Encoding encoding: utf8});
+
+ /**
+ * Read the entire file contents as lines of text using the given
+ * [Encoding].
+ *
+ * Returns a `Future<List<String>>` that completes with the lines
+ * once the file contents has been read.
+ */
+ Future<List<String>> readAsLines({Encoding encoding: utf8});
+
+ /**
+ * Synchronously read the entire file contents as lines of text
+ * using the given [Encoding].
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ List<String> readAsLinesSync({Encoding encoding: utf8});
+
+ /**
+ * Write a list of bytes to a file.
+ *
+ * Opens the file, writes the list of bytes to it, and closes the file.
+ * Returns a `Future<File>` that completes with this [File] object once
+ * the entire operation has completed.
+ *
+ * By default [writeAsBytes] creates the file for writing and truncates the
+ * file if it already exists. In order to append the bytes to an existing
+ * file, pass [FileMode.append] as the optional mode parameter.
+ *
+ * If the argument [flush] is set to `true`, the data written will be
+ * flushed to the file system before the returned future completes.
+ */
+ Future<File> writeAsBytes(List<int> bytes,
+ {FileMode mode: FileMode.write, bool flush: false});
+
+ /**
+ * Synchronously write a list of bytes to a file.
+ *
+ * Opens the file, writes the list of bytes to it and closes the file.
+ *
+ * By default [writeAsBytesSync] creates the file for writing and truncates
+ * the file if it already exists. In order to append the bytes to an existing
+ * file, pass [FileMode.append] as the optional mode parameter.
+ *
+ * If the [flush] argument is set to `true` data written will be
+ * flushed to the file system before returning.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ void writeAsBytesSync(List<int> bytes,
+ {FileMode mode: FileMode.write, bool flush: false});
+
+ /**
+ * Write a string to a file.
+ *
+ * Opens the file, writes the string in the given encoding, and closes the
+ * file. Returns a `Future<File>` that completes with this [File] object
+ * once the entire operation has completed.
+ *
+ * By default [writeAsString] creates the file for writing and truncates the
+ * file if it already exists. In order to append the bytes to an existing
+ * file, pass [FileMode.append] as the optional mode parameter.
+ *
+ * If the argument [flush] is set to `true`, the data written will be
+ * flushed to the file system before the returned future completes.
+ *
+ */
+ Future<File> writeAsString(String contents,
+ {FileMode mode: FileMode.write,
+ Encoding encoding: utf8,
+ bool flush: false});
+
+ /**
+ * Synchronously write a string to a file.
+ *
+ * Opens the file, writes the string in the given encoding, and closes the
+ * file.
+ *
+ * By default [writeAsStringSync] creates the file for writing and
+ * truncates the file if it already exists. In order to append the bytes
+ * to an existing file, pass [FileMode.append] as the optional mode
+ * parameter.
+ *
+ * If the [flush] argument is set to `true` data written will be
+ * flushed to the file system before returning.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ void writeAsStringSync(String contents,
+ {FileMode mode: FileMode.write,
+ Encoding encoding: utf8,
+ bool flush: false});
+
+ /**
+ * Get the path of the file.
+ */
+ String get path;
+}
+
+/**
+ * `RandomAccessFile` provides random access to the data in a
+ * file.
+ *
+ * `RandomAccessFile` objects are obtained by calling the
+ * `open` method on a [File] object.
+ *
+ * A `RandomAccessFile` have both asynchronous and synchronous
+ * methods. The asynchronous methods all return a `Future`
+ * whereas the synchronous methods will return the result directly,
+ * and block the current isolate until the result is ready.
+ *
+ * At most one asynchronous method can be pending on a given `RandomAccessFile`
+ * instance at the time. If an asynchronous method is called when one is
+ * already in progress a [FileSystemException] is thrown.
+ *
+ * If an asynchronous method is pending it is also not possible to call any
+ * synchronous methods. This will also throw a [FileSystemException].
+ */
+abstract class RandomAccessFile {
+ /**
+ * Closes the file. Returns a `Future` that
+ * completes when it has been closed.
+ */
+ Future<void> close();
+
+ /**
+ * Synchronously closes the file.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ void closeSync();
+
+ /**
+ * Reads a byte from the file. Returns a `Future<int>` that
+ * completes with the byte, or with -1 if end-of-file has been reached.
+ */
+ Future<int> readByte();
+
+ /**
+ * Synchronously reads a single byte from the file. If end-of-file
+ * has been reached -1 is returned.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ int readByteSync();
+
+ /**
+ * Reads [bytes] bytes from a file and returns the result as a list of bytes.
+ */
+ Future<Uint8List> read(int bytes);
+
+ /**
+ * Synchronously reads a maximum of [bytes] bytes from a file and
+ * returns the result in a list of bytes.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ Uint8List readSync(int bytes);
+
+ /**
+ * Reads into an existing [List<int>] from the file. If [start] is present,
+ * the bytes will be filled into [buffer] from at index [start], otherwise
+ * index 0. If [end] is present, the [end] - [start] bytes will be read into
+ * [buffer], otherwise up to [buffer.length]. If [end] == [start] nothing
+ * happens.
+ *
+ * Returns a `Future<int>` that completes with the number of bytes read.
+ */
+ Future<int> readInto(List<int> buffer, [int start = 0, int end]);
+
+ /**
+ * Synchronously reads into an existing [List<int>] from the file. If [start]
+ * is present, the bytes will be filled into [buffer] from at index [start],
+ * otherwise index 0. If [end] is present, the [end] - [start] bytes will be
+ * read into [buffer], otherwise up to [buffer.length]. If [end] == [start]
+ * nothing happens.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ int readIntoSync(List<int> buffer, [int start = 0, int end]);
+
+ /**
+ * Writes a single byte to the file. Returns a
+ * `Future<RandomAccessFile>` that completes with this
+ * RandomAccessFile when the write completes.
+ */
+ Future<RandomAccessFile> writeByte(int value);
+
+ /**
+ * Synchronously writes a single byte to the file. Returns the
+ * number of bytes successfully written.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ int writeByteSync(int value);
+
+ /**
+ * Writes from a [List<int>] to the file. It will read the buffer from index
+ * [start] to index [end]. If [start] is omitted, it'll start from index 0.
+ * If [end] is omitted, it will write to end of [buffer].
+ *
+ * Returns a `Future<RandomAccessFile>` that completes with this
+ * [RandomAccessFile] when the write completes.
+ */
+ Future<RandomAccessFile> writeFrom(List<int> buffer,
+ [int start = 0, int end]);
+
+ /**
+ * Synchronously writes from a [List<int>] to the file. It will read the
+ * buffer from index [start] to index [end]. If [start] is omitted, it'll
+ * start from index 0. If [end] is omitted, it will write to the end of
+ * [buffer].
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ void writeFromSync(List<int> buffer, [int start = 0, int end]);
+
+ /**
+ * Writes a string to the file using the given [Encoding]. Returns a
+ * `Future<RandomAccessFile>` that completes with this
+ * RandomAccessFile when the write completes.
+ */
+ Future<RandomAccessFile> writeString(String string,
+ {Encoding encoding: utf8});
+
+ /**
+ * Synchronously writes a single string to the file using the given
+ * [Encoding].
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ void writeStringSync(String string, {Encoding encoding: utf8});
+
+ /**
+ * Gets the current byte position in the file. Returns a
+ * `Future<int>` that completes with the position.
+ */
+ Future<int> position();
+
+ /**
+ * Synchronously gets the current byte position in the file.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ int positionSync();
+
+ /**
+ * Sets the byte position in the file. Returns a
+ * `Future<RandomAccessFile>` that completes with this
+ * RandomAccessFile when the position has been set.
+ */
+ Future<RandomAccessFile> setPosition(int position);
+
+ /**
+ * Synchronously sets the byte position in the file.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ void setPositionSync(int position);
+
+ /**
+ * Truncates (or extends) the file to [length] bytes. Returns a
+ * `Future<RandomAccessFile>` that completes with this
+ * RandomAccessFile when the truncation has been performed.
+ */
+ Future<RandomAccessFile> truncate(int length);
+
+ /**
+ * Synchronously truncates (or extends) the file to [length] bytes.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ void truncateSync(int length);
+
+ /**
+ * Gets the length of the file. Returns a `Future<int>` that
+ * completes with the length in bytes.
+ */
+ Future<int> length();
+
+ /**
+ * Synchronously gets the length of the file.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ int lengthSync();
+
+ /**
+ * Flushes the contents of the file to disk. Returns a
+ * `Future<RandomAccessFile>` that completes with this
+ * RandomAccessFile when the flush operation completes.
+ */
+ Future<RandomAccessFile> flush();
+
+ /**
+ * Synchronously flushes the contents of the file to disk.
+ *
+ * Throws a [FileSystemException] if the operation fails.
+ */
+ void flushSync();
+
+ /**
+ * Locks the file or part of the file.
+ *
+ * By default an exclusive lock will be obtained, but that can be overridden
+ * by the [mode] argument.
+ *
+ * Locks the byte range from [start] to [end] of the file, with the
+ * byte at position `end` not included. If no arguments are
+ * specified, the full file is locked, If only `start` is specified
+ * the file is locked from byte position `start` to the end of the
+ * file, no matter how large it grows. It is possible to specify an
+ * explicit value of `end` which is past the current length of the file.
+ *
+ * To obtain an exclusive lock on a file it must be opened for writing.
+ *
+ * If [mode] is [FileLock.exclusive] or [FileLock.shared], an error is
+ * signaled if the lock cannot be obtained. If [mode] is
+ * [FileLock.blockingExclusive] or [FileLock.blockingShared], the
+ * returned [Future] is resolved only when the lock has been obtained.
+ *
+ * *NOTE* file locking does have slight differences in behavior across
+ * platforms:
+ *
+ * On Linux and OS X this uses advisory locks, which have the
+ * surprising semantics that all locks associated with a given file
+ * are removed when *any* file descriptor for that file is closed by
+ * the process. Note that this does not actually lock the file for
+ * access. Also note that advisory locks are on a process
+ * level. This means that several isolates in the same process can
+ * obtain an exclusive lock on the same file.
+ *
+ * On Windows the regions used for lock and unlock needs to match. If that
+ * is not the case unlocking will result in the OS error "The segment is
+ * already unlocked".
+ */
+ Future<RandomAccessFile> lock(
+ [FileLock mode = FileLock.exclusive, int start = 0, int end = -1]);
+
+ /**
+ * Synchronously locks the file or part of the file.
+ *
+ * By default an exclusive lock will be obtained, but that can be overridden
+ * by the [mode] argument.
+ *
+ * Locks the byte range from [start] to [end] of the file ,with the
+ * byte at position `end` not included. If no arguments are
+ * specified, the full file is locked, If only `start` is specified
+ * the file is locked from byte position `start` to the end of the
+ * file, no matter how large it grows. It is possible to specify an
+ * explicit value of `end` which is past the current length of the file.
+ *
+ * To obtain an exclusive lock on a file it must be opened for writing.
+ *
+ * If [mode] is [FileLock.exclusive] or [FileLock.shared], an exception is
+ * thrown if the lock cannot be obtained. If [mode] is
+ * [FileLock.blockingExclusive] or [FileLock.blockingShared], the
+ * call returns only after the lock has been obtained.
+ *
+ * *NOTE* file locking does have slight differences in behavior across
+ * platforms:
+ *
+ * On Linux and OS X this uses advisory locks, which have the
+ * surprising semantics that all locks associated with a given file
+ * are removed when *any* file descriptor for that file is closed by
+ * the process. Note that this does not actually lock the file for
+ * access. Also note that advisory locks are on a process
+ * level. This means that several isolates in the same process can
+ * obtain an exclusive lock on the same file.
+ *
+ * On Windows the regions used for lock and unlock needs to match. If that
+ * is not the case unlocking will result in the OS error "The segment is
+ * already unlocked".
+ *
+ */
+ void lockSync(
+ [FileLock mode = FileLock.exclusive, int start = 0, int end = -1]);
+
+ /**
+ * Unlocks the file or part of the file.
+ *
+ * Unlocks the byte range from [start] to [end] of the file, with
+ * the byte at position `end` not included. If no arguments are
+ * specified, the full file is unlocked, If only `start` is
+ * specified the file is unlocked from byte position `start` to the
+ * end of the file.
+ *
+ * *NOTE* file locking does have slight differences in behavior across
+ * platforms:
+ *
+ * See [lock] for more details.
+ */
+ Future<RandomAccessFile> unlock([int start = 0, int end = -1]);
+
+ /**
+ * Synchronously unlocks the file or part of the file.
+ *
+ * Unlocks the byte range from [start] to [end] of the file, with
+ * the byte at position `end` not included. If no arguments are
+ * specified, the full file is unlocked, If only `start` is
+ * specified the file is unlocked from byte position `start` to the
+ * end of the file.
+ *
+ * *NOTE* file locking does have slight differences in behavior across
+ * platforms:
+ *
+ * See [lockSync] for more details.
+ */
+ void unlockSync([int start = 0, int end = -1]);
+
+ /**
+ * Returns a human-readable string for this RandomAccessFile instance.
+ */
+ String toString();
+
+ /**
+ * Gets the path of the file underlying this RandomAccessFile.
+ */
+ String get path;
+}
+
+/**
+ * Exception thrown when a file operation fails.
+ */
+@pragma("vm:entry-point")
+class FileSystemException implements IOException {
+ /**
+ * Message describing the error. This does not include any detailed
+ * information form the underlying OS error. Check [osError] for
+ * that information.
+ */
+ final String message;
+
+ /**
+ * The file system path on which the error occurred. Can be `null`
+ * if the exception does not relate directly to a file system path.
+ */
+ final String path;
+
+ /**
+ * The underlying OS error. Can be `null` if the exception is not
+ * raised due to an OS error.
+ */
+ final OSError osError;
+
+ /**
+ * Creates a new FileSystemException with an optional error message
+ * [message], optional file system path [path] and optional OS error
+ * [osError].
+ */
+ @pragma("vm:entry-point")
+ const FileSystemException([this.message = "", this.path = "", this.osError]);
+
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.write("FileSystemException");
+ if (message.isNotEmpty) {
+ sb.write(": $message");
+ if (path != null) {
+ sb.write(", path = '$path'");
+ }
+ if (osError != null) {
+ sb.write(" ($osError)");
+ }
+ } else if (osError != null) {
+ sb.write(": $osError");
+ if (path != null) {
+ sb.write(", path = '$path'");
+ }
+ } else if (path != null) {
+ sb.write(": $path");
+ }
+ return sb.toString();
+ }
+}
diff --git a/sdk_nnbd/lib/io/file_impl.dart b/sdk_nnbd/lib/io/file_impl.dart
new file mode 100644
index 0000000..410182c
--- /dev/null
+++ b/sdk_nnbd/lib/io/file_impl.dart
@@ -0,0 +1,1095 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+// Read the file in blocks of size 64k.
+const int _blockSize = 64 * 1024;
+
+class _FileStream extends Stream<List<int>> {
+ // Stream controller.
+ StreamController<Uint8List> _controller;
+
+ // Information about the underlying file.
+ String _path;
+ RandomAccessFile _openedFile;
+ int _position;
+ int _end;
+ final Completer _closeCompleter = new Completer();
+
+ // Has the stream been paused or unsubscribed?
+ bool _unsubscribed = false;
+
+ // Is there a read currently in progress?
+ bool _readInProgress = true;
+ bool _closed = false;
+
+ bool _atEnd = false;
+
+ _FileStream(this._path, this._position, this._end) {
+ _position ??= 0;
+ }
+
+ _FileStream.forStdin() : _position = 0;
+
+ StreamSubscription<Uint8List> listen(void onData(Uint8List event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ _setupController();
+ return _controller.stream.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ void _setupController() {
+ _controller = new StreamController<Uint8List>(
+ sync: true,
+ onListen: _start,
+ onResume: _readBlock,
+ onCancel: () {
+ _unsubscribed = true;
+ return _closeFile();
+ });
+ }
+
+ Future _closeFile() {
+ if (_readInProgress || _closed) {
+ return _closeCompleter.future;
+ }
+ _closed = true;
+
+ void done() {
+ _closeCompleter.complete();
+ _controller.close();
+ }
+
+ _openedFile.close().catchError(_controller.addError).whenComplete(done);
+ return _closeCompleter.future;
+ }
+
+ void _readBlock() {
+ // Don't start a new read if one is already in progress.
+ if (_readInProgress) return;
+ if (_atEnd) {
+ _closeFile();
+ return;
+ }
+ _readInProgress = true;
+ int readBytes = _blockSize;
+ if (_end != null) {
+ readBytes = min(readBytes, _end - _position);
+ if (readBytes < 0) {
+ _readInProgress = false;
+ if (!_unsubscribed) {
+ _controller.addError(new RangeError("Bad end position: $_end"));
+ _closeFile();
+ _unsubscribed = true;
+ }
+ return;
+ }
+ }
+ _openedFile.read(readBytes).then((block) {
+ _readInProgress = false;
+ if (_unsubscribed) {
+ _closeFile();
+ return;
+ }
+ _position += block.length;
+ if (block.length < readBytes || (_end != null && _position == _end)) {
+ _atEnd = true;
+ }
+ if (!_atEnd && !_controller.isPaused) {
+ _readBlock();
+ }
+ _controller.add(block);
+ if (_atEnd) {
+ _closeFile();
+ }
+ }).catchError((e, s) {
+ if (!_unsubscribed) {
+ _controller.addError(e, s);
+ _closeFile();
+ _unsubscribed = true;
+ }
+ });
+ }
+
+ void _start() {
+ if (_position < 0) {
+ _controller.addError(new RangeError("Bad start position: $_position"));
+ _controller.close();
+ _closeCompleter.complete();
+ return;
+ }
+
+ void onReady(RandomAccessFile file) {
+ _openedFile = file;
+ _readInProgress = false;
+ _readBlock();
+ }
+
+ void onOpenFile(RandomAccessFile file) {
+ if (_position > 0) {
+ file.setPosition(_position).then(onReady, onError: (e, s) {
+ _controller.addError(e, s);
+ _readInProgress = false;
+ _closeFile();
+ });
+ } else {
+ onReady(file);
+ }
+ }
+
+ void openFailed(error, stackTrace) {
+ _controller.addError(error, stackTrace);
+ _controller.close();
+ _closeCompleter.complete();
+ }
+
+ if (_path != null) {
+ new File(_path)
+ .open(mode: FileMode.read)
+ .then(onOpenFile, onError: openFailed);
+ } else {
+ try {
+ onOpenFile(_File._openStdioSync(0));
+ } catch (e, s) {
+ openFailed(e, s);
+ }
+ }
+ }
+}
+
+class _FileStreamConsumer extends StreamConsumer<List<int>> {
+ File _file;
+ Future<RandomAccessFile> _openFuture;
+
+ _FileStreamConsumer(this._file, FileMode mode) {
+ _openFuture = _file.open(mode: mode);
+ }
+
+ _FileStreamConsumer.fromStdio(int fd) {
+ _openFuture = new Future.value(_File._openStdioSync(fd));
+ }
+
+ Future<File> addStream(Stream<List<int>> stream) {
+ Completer<File> completer = new Completer<File>.sync();
+ _openFuture.then((openedFile) {
+ var _subscription;
+ void error(e, [StackTrace stackTrace]) {
+ _subscription.cancel();
+ openedFile.close();
+ completer.completeError(e, stackTrace);
+ }
+
+ _subscription = stream.listen((d) {
+ _subscription.pause();
+ try {
+ openedFile
+ .writeFrom(d, 0, d.length)
+ .then((_) => _subscription.resume(), onError: error);
+ } catch (e, stackTrace) {
+ error(e, stackTrace);
+ }
+ }, onDone: () {
+ completer.complete(_file);
+ }, onError: error, cancelOnError: true);
+ }).catchError(completer.completeError);
+ return completer.future;
+ }
+
+ Future<File> close() =>
+ _openFuture.then((openedFile) => openedFile.close()).then((_) => _file);
+}
+
+// Class for encapsulating the native implementation of files.
+class _File extends FileSystemEntity implements File {
+ String _path;
+ Uint8List _rawPath;
+
+ _File(String path) {
+ ArgumentError.checkNotNull(path, 'path');
+ _path = path;
+ _rawPath = FileSystemEntity._toUtf8Array(path);
+ }
+
+ _File.fromRawPath(Uint8List rawPath) {
+ ArgumentError.checkNotNull(rawPath, 'rawPath');
+ _rawPath = FileSystemEntity._toNullTerminatedUtf8Array(rawPath);
+ _path = FileSystemEntity._toStringFromUtf8Array(rawPath);
+ }
+
+ String get path => _path;
+
+ // WARNING:
+ // Calling this function will increase the reference count on the native
+ // namespace object. It should only be called to pass the pointer to the
+ // IOService, which will decrement the reference count when it is finished
+ // with it.
+ static int _namespacePointer() => _Namespace._namespacePointer;
+
+ static Future _dispatchWithNamespace(int request, List data) {
+ data[0] = _namespacePointer();
+ return _IOService._dispatch(request, data);
+ }
+
+ Future<bool> exists() {
+ return _dispatchWithNamespace(_IOService.fileExists, [null, _rawPath])
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "Cannot check existence", path);
+ }
+ return response;
+ });
+ }
+
+ external static _exists(_Namespace namespace, Uint8List rawPath);
+
+ bool existsSync() {
+ var result = _exists(_Namespace._namespace, _rawPath);
+ throwIfError(result, "Cannot check existence of file", path);
+ return result;
+ }
+
+ File get absolute => new File(_absolutePath);
+
+ Future<File> create({bool recursive: false}) {
+ var result =
+ recursive ? parent.create(recursive: true) : new Future.value(null);
+ return result
+ .then((_) =>
+ _dispatchWithNamespace(_IOService.fileCreate, [null, _rawPath]))
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "Cannot create file", path);
+ }
+ return this;
+ });
+ }
+
+ external static _create(_Namespace namespace, Uint8List rawPath);
+
+ external static _createLink(
+ _Namespace namespace, Uint8List rawPath, String target);
+
+ external static _linkTarget(_Namespace namespace, Uint8List rawPath);
+
+ void createSync({bool recursive: false}) {
+ if (recursive) {
+ parent.createSync(recursive: true);
+ }
+ var result = _create(_Namespace._namespace, _rawPath);
+ throwIfError(result, "Cannot create file", path);
+ }
+
+ Future<File> _delete({bool recursive: false}) {
+ if (recursive) {
+ return new Directory(path).delete(recursive: true).then((_) => this);
+ }
+ return _dispatchWithNamespace(_IOService.fileDelete, [null, _rawPath])
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "Cannot delete file", path);
+ }
+ return this;
+ });
+ }
+
+ external static _deleteNative(_Namespace namespace, Uint8List rawPath);
+
+ external static _deleteLinkNative(_Namespace namespace, Uint8List rawPath);
+
+ void _deleteSync({bool recursive: false}) {
+ if (recursive) {
+ return new Directory.fromRawPath(_rawPath).deleteSync(recursive: true);
+ }
+ var result = _deleteNative(_Namespace._namespace, _rawPath);
+ throwIfError(result, "Cannot delete file", path);
+ }
+
+ Future<File> rename(String newPath) {
+ return _dispatchWithNamespace(
+ _IOService.fileRename, [null, _rawPath, newPath]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(
+ response, "Cannot rename file to '$newPath'", path);
+ }
+ return new File(newPath);
+ });
+ }
+
+ external static _rename(
+ _Namespace namespace, Uint8List oldPath, String newPath);
+
+ external static _renameLink(
+ _Namespace namespace, Uint8List oldPath, String newPath);
+
+ File renameSync(String newPath) {
+ var result = _rename(_Namespace._namespace, _rawPath, newPath);
+ throwIfError(result, "Cannot rename file to '$newPath'", path);
+ return new File(newPath);
+ }
+
+ Future<File> copy(String newPath) {
+ return _dispatchWithNamespace(
+ _IOService.fileCopy, [null, _rawPath, newPath]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(
+ response, "Cannot copy file to '$newPath'", path);
+ }
+ return new File(newPath);
+ });
+ }
+
+ external static _copy(
+ _Namespace namespace, Uint8List oldPath, String newPath);
+
+ File copySync(String newPath) {
+ var result = _copy(_Namespace._namespace, _rawPath, newPath);
+ throwIfError(result, "Cannot copy file to '$newPath'", path);
+ return new File(newPath);
+ }
+
+ Future<RandomAccessFile> open({FileMode mode: FileMode.read}) {
+ if (mode != FileMode.read &&
+ mode != FileMode.write &&
+ mode != FileMode.append &&
+ mode != FileMode.writeOnly &&
+ mode != FileMode.writeOnlyAppend) {
+ return new Future.error(
+ new ArgumentError('Invalid file mode for this operation'));
+ }
+ return _dispatchWithNamespace(
+ _IOService.fileOpen, [null, _rawPath, mode._mode]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "Cannot open file", path);
+ }
+ return new _RandomAccessFile(response, path);
+ });
+ }
+
+ Future<int> length() {
+ return _dispatchWithNamespace(
+ _IOService.fileLengthFromPath, [null, _rawPath]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(
+ response, "Cannot retrieve length of file", path);
+ }
+ return response;
+ });
+ }
+
+ external static _lengthFromPath(_Namespace namespace, Uint8List rawPath);
+
+ int lengthSync() {
+ var result = _lengthFromPath(_Namespace._namespace, _rawPath);
+ throwIfError(result, "Cannot retrieve length of file", path);
+ return result;
+ }
+
+ Future<DateTime> lastAccessed() {
+ return _dispatchWithNamespace(_IOService.fileLastAccessed, [null, _rawPath])
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(
+ response, "Cannot retrieve access time", path);
+ }
+ return new DateTime.fromMillisecondsSinceEpoch(response);
+ });
+ }
+
+ external static _lastAccessed(_Namespace namespace, Uint8List rawPath);
+
+ DateTime lastAccessedSync() {
+ var ms = _lastAccessed(_Namespace._namespace, _rawPath);
+ throwIfError(ms, "Cannot retrieve access time", path);
+ return new DateTime.fromMillisecondsSinceEpoch(ms);
+ }
+
+ Future setLastAccessed(DateTime time) {
+ int millis = time.millisecondsSinceEpoch;
+ return _dispatchWithNamespace(
+ _IOService.fileSetLastAccessed, [null, _rawPath, millis])
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "Cannot set access time", path);
+ }
+ return null;
+ });
+ }
+
+ external static _setLastAccessed(
+ _Namespace namespace, Uint8List rawPath, int millis);
+
+ void setLastAccessedSync(DateTime time) {
+ int millis = time.millisecondsSinceEpoch;
+ var result = _setLastAccessed(_Namespace._namespace, _rawPath, millis);
+ if (result is OSError) {
+ throw new FileSystemException(
+ "Failed to set file access time", path, result);
+ }
+ }
+
+ Future<DateTime> lastModified() {
+ return _dispatchWithNamespace(_IOService.fileLastModified, [null, _rawPath])
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(
+ response, "Cannot retrieve modification time", path);
+ }
+ return new DateTime.fromMillisecondsSinceEpoch(response);
+ });
+ }
+
+ external static _lastModified(_Namespace namespace, Uint8List rawPath);
+
+ DateTime lastModifiedSync() {
+ var ms = _lastModified(_Namespace._namespace, _rawPath);
+ throwIfError(ms, "Cannot retrieve modification time", path);
+ return new DateTime.fromMillisecondsSinceEpoch(ms);
+ }
+
+ Future setLastModified(DateTime time) {
+ int millis = time.millisecondsSinceEpoch;
+ return _dispatchWithNamespace(
+ _IOService.fileSetLastModified, [null, _rawPath, millis])
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(
+ response, "Cannot set modification time", path);
+ }
+ return null;
+ });
+ }
+
+ external static _setLastModified(
+ _Namespace namespace, Uint8List rawPath, int millis);
+
+ void setLastModifiedSync(DateTime time) {
+ int millis = time.millisecondsSinceEpoch;
+ var result = _setLastModified(_Namespace._namespace, _rawPath, millis);
+ if (result is OSError) {
+ throw new FileSystemException(
+ "Failed to set file modification time", path, result);
+ }
+ }
+
+ external static _open(_Namespace namespace, Uint8List rawPath, int mode);
+
+ RandomAccessFile openSync({FileMode mode: FileMode.read}) {
+ if (mode != FileMode.read &&
+ mode != FileMode.write &&
+ mode != FileMode.append &&
+ mode != FileMode.writeOnly &&
+ mode != FileMode.writeOnlyAppend) {
+ throw new ArgumentError('Invalid file mode for this operation');
+ }
+ var id = _open(_Namespace._namespace, _rawPath, mode._mode);
+ throwIfError(id, "Cannot open file", path);
+ return new _RandomAccessFile(id, _path);
+ }
+
+ external static int _openStdio(int fd);
+
+ static RandomAccessFile _openStdioSync(int fd) {
+ var id = _openStdio(fd);
+ if (id == 0) {
+ throw new FileSystemException("Cannot open stdio file for: $fd");
+ }
+ return new _RandomAccessFile(id, "");
+ }
+
+ Stream<List<int>> openRead([int start, int end]) {
+ return new _FileStream(path, start, end);
+ }
+
+ IOSink openWrite({FileMode mode: FileMode.write, Encoding encoding: utf8}) {
+ if (mode != FileMode.write &&
+ mode != FileMode.append &&
+ mode != FileMode.writeOnly &&
+ mode != FileMode.writeOnlyAppend) {
+ throw new ArgumentError('Invalid file mode for this operation');
+ }
+ var consumer = new _FileStreamConsumer(this, mode);
+ return new IOSink(consumer, encoding: encoding);
+ }
+
+ Future<Uint8List> readAsBytes() {
+ Future<Uint8List> readDataChunked(RandomAccessFile file) {
+ var builder = new BytesBuilder(copy: false);
+ var completer = new Completer<Uint8List>();
+ void read() {
+ file.read(_blockSize).then((data) {
+ if (data.length > 0) {
+ builder.add(data);
+ read();
+ } else {
+ completer.complete(builder.takeBytes());
+ }
+ }, onError: completer.completeError);
+ }
+
+ read();
+ return completer.future;
+ }
+
+ return open().then((file) {
+ return file.length().then((length) {
+ if (length == 0) {
+ // May be character device, try to read it in chunks.
+ return readDataChunked(file);
+ }
+ return file.read(length);
+ }).whenComplete(file.close);
+ });
+ }
+
+ Uint8List readAsBytesSync() {
+ var opened = openSync();
+ try {
+ Uint8List data;
+ var length = opened.lengthSync();
+ if (length == 0) {
+ // May be character device, try to read it in chunks.
+ var builder = new BytesBuilder(copy: false);
+ do {
+ data = opened.readSync(_blockSize);
+ if (data.length > 0) builder.add(data);
+ } while (data.length > 0);
+ data = builder.takeBytes();
+ } else {
+ data = opened.readSync(length);
+ }
+ return data;
+ } finally {
+ opened.closeSync();
+ }
+ }
+
+ String _tryDecode(List<int> bytes, Encoding encoding) {
+ try {
+ return encoding.decode(bytes);
+ } catch (_) {
+ throw new FileSystemException(
+ "Failed to decode data using encoding '${encoding.name}'", path);
+ }
+ }
+
+ Future<String> readAsString({Encoding encoding: utf8}) {
+ // TODO(dart:io): If the change in async semantics to run synchronously
+ // until await lands, this is as efficient as
+ // return _tryDecode(await readAsBytes(), encoding);
+ var stack = StackTrace.current;
+ return readAsBytes().then((bytes) {
+ try {
+ return _tryDecode(bytes, encoding);
+ } catch (e) {
+ return new Future.error(e, stack);
+ }
+ });
+ }
+
+ String readAsStringSync({Encoding encoding: utf8}) =>
+ _tryDecode(readAsBytesSync(), encoding);
+
+ Future<List<String>> readAsLines({Encoding encoding: utf8}) =>
+ readAsString(encoding: encoding).then(const LineSplitter().convert);
+
+ List<String> readAsLinesSync({Encoding encoding: utf8}) =>
+ const LineSplitter().convert(readAsStringSync(encoding: encoding));
+
+ Future<File> writeAsBytes(List<int> bytes,
+ {FileMode mode: FileMode.write, bool flush: false}) {
+ return open(mode: mode).then((file) {
+ return file.writeFrom(bytes, 0, bytes.length).then<File>((_) {
+ if (flush) return file.flush().then((_) => this);
+ return this;
+ }).whenComplete(file.close);
+ });
+ }
+
+ void writeAsBytesSync(List<int> bytes,
+ {FileMode mode: FileMode.write, bool flush: false}) {
+ RandomAccessFile opened = openSync(mode: mode);
+ try {
+ opened.writeFromSync(bytes, 0, bytes.length);
+ if (flush) opened.flushSync();
+ } finally {
+ opened.closeSync();
+ }
+ }
+
+ Future<File> writeAsString(String contents,
+ {FileMode mode: FileMode.write,
+ Encoding encoding: utf8,
+ bool flush: false}) {
+ try {
+ return writeAsBytes(encoding.encode(contents), mode: mode, flush: flush);
+ } catch (e) {
+ return new Future.error(e);
+ }
+ }
+
+ void writeAsStringSync(String contents,
+ {FileMode mode: FileMode.write,
+ Encoding encoding: utf8,
+ bool flush: false}) {
+ writeAsBytesSync(encoding.encode(contents), mode: mode, flush: flush);
+ }
+
+ String toString() => "File: '$path'";
+
+ static throwIfError(Object result, String msg, String path) {
+ if (result is OSError) {
+ throw new FileSystemException(msg, path, result);
+ }
+ }
+}
+
+abstract class _RandomAccessFileOps {
+ external factory _RandomAccessFileOps(int pointer);
+
+ int getPointer();
+ int close();
+ readByte();
+ read(int bytes);
+ readInto(List<int> buffer, int start, int end);
+ writeByte(int value);
+ writeFrom(List<int> buffer, int start, int end);
+ position();
+ setPosition(int position);
+ truncate(int length);
+ length();
+ flush();
+ lock(int lock, int start, int end);
+}
+
+class _RandomAccessFile implements RandomAccessFile {
+ static bool _connectedResourceHandler = false;
+
+ final String path;
+
+ bool _asyncDispatched = false;
+ SendPort _fileService;
+
+ _FileResourceInfo _resourceInfo;
+ _RandomAccessFileOps _ops;
+
+ _RandomAccessFile(int pointer, this.path) {
+ _ops = new _RandomAccessFileOps(pointer);
+ _resourceInfo = new _FileResourceInfo(this);
+ _maybeConnectHandler();
+ }
+
+ void _maybePerformCleanup() {
+ if (closed) {
+ _FileResourceInfo.FileClosed(_resourceInfo);
+ }
+ }
+
+ _maybeConnectHandler() {
+ if (!_connectedResourceHandler) {
+ // TODO(ricow): We probably need to set these in some initialization code.
+ // We need to make sure that these are always available from the
+ // observatory even if no files (or sockets for the socket ones) are
+ // open.
+ registerExtension(
+ 'ext.dart.io.getOpenFiles', _FileResourceInfo.getOpenFiles);
+ registerExtension(
+ 'ext.dart.io.getFileByID', _FileResourceInfo.getFileInfoMapByID);
+ _connectedResourceHandler = true;
+ }
+ }
+
+ Future<void> close() {
+ return _dispatch(_IOService.fileClose, [null], markClosed: true)
+ .then((result) {
+ if (result == -1) {
+ throw new FileSystemException("Cannot close file", path);
+ }
+ closed = closed || (result == 0);
+ _maybePerformCleanup();
+ });
+ }
+
+ void closeSync() {
+ _checkAvailable();
+ var id = _ops.close();
+ if (id == -1) {
+ throw new FileSystemException("Cannot close file", path);
+ }
+ closed = closed || (id == 0);
+ _maybePerformCleanup();
+ }
+
+ Future<int> readByte() {
+ return _dispatch(_IOService.fileReadByte, [null]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "readByte failed", path);
+ }
+ _resourceInfo.addRead(1);
+ return response;
+ });
+ }
+
+ int readByteSync() {
+ _checkAvailable();
+ var result = _ops.readByte();
+ if (result is OSError) {
+ throw new FileSystemException("readByte failed", path, result);
+ }
+ _resourceInfo.addRead(1);
+ return result;
+ }
+
+ Future<Uint8List> read(int bytes) {
+ ArgumentError.checkNotNull(bytes, 'bytes');
+ return _dispatch(_IOService.fileRead, [null, bytes]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "read failed", path);
+ }
+ _resourceInfo.addRead(response[1].length);
+ Uint8List result = response[1];
+ return result;
+ });
+ }
+
+ Uint8List readSync(int bytes) {
+ _checkAvailable();
+ ArgumentError.checkNotNull(bytes, 'bytes');
+ var result = _ops.read(bytes);
+ if (result is OSError) {
+ throw new FileSystemException("readSync failed", path, result);
+ }
+ _resourceInfo.addRead(result.length);
+ return result;
+ }
+
+ Future<int> readInto(List<int> buffer, [int start = 0, int end]) {
+ if ((buffer is! List) ||
+ ((start != null) && (start is! int)) ||
+ ((end != null) && (end is! int))) {
+ throw new ArgumentError();
+ }
+ end = RangeError.checkValidRange(start, end, buffer.length);
+ if (end == start) {
+ return new Future.value(0);
+ }
+ int length = end - start;
+ return _dispatch(_IOService.fileReadInto, [null, length]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "readInto failed", path);
+ }
+ int read = response[1];
+ List<int> data = response[2];
+ buffer.setRange(start, start + read, data);
+ _resourceInfo.addRead(read);
+ return read;
+ });
+ }
+
+ int readIntoSync(List<int> buffer, [int start = 0, int end]) {
+ _checkAvailable();
+ if ((buffer is! List) ||
+ ((start != null) && (start is! int)) ||
+ ((end != null) && (end is! int))) {
+ throw new ArgumentError();
+ }
+ end = RangeError.checkValidRange(start, end, buffer.length);
+ if (end == start) {
+ return 0;
+ }
+ var result = _ops.readInto(buffer, start, end);
+ if (result is OSError) {
+ throw new FileSystemException("readInto failed", path, result);
+ }
+ _resourceInfo.addRead(result);
+ return result;
+ }
+
+ Future<RandomAccessFile> writeByte(int value) {
+ ArgumentError.checkNotNull(value, 'value');
+ return _dispatch(_IOService.fileWriteByte, [null, value]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "writeByte failed", path);
+ }
+ _resourceInfo.addWrite(1);
+ return this;
+ });
+ }
+
+ int writeByteSync(int value) {
+ _checkAvailable();
+ ArgumentError.checkNotNull(value, 'value');
+ var result = _ops.writeByte(value);
+ if (result is OSError) {
+ throw new FileSystemException("writeByte failed", path, result);
+ }
+ _resourceInfo.addWrite(1);
+ return result;
+ }
+
+ Future<RandomAccessFile> writeFrom(List<int> buffer,
+ [int start = 0, int end]) {
+ if ((buffer is! List) ||
+ ((start != null) && (start is! int)) ||
+ ((end != null) && (end is! int))) {
+ throw new ArgumentError("Invalid arguments to writeFrom");
+ }
+ end = RangeError.checkValidRange(start, end, buffer.length);
+ if (end == start) {
+ return new Future.value(this);
+ }
+ _BufferAndStart result;
+ try {
+ result = _ensureFastAndSerializableByteData(buffer, start, end);
+ } catch (e) {
+ return new Future.error(e);
+ }
+
+ List request = new List(4);
+ request[0] = null;
+ request[1] = result.buffer;
+ request[2] = result.start;
+ request[3] = end - (start - result.start);
+ return _dispatch(_IOService.fileWriteFrom, request).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "writeFrom failed", path);
+ }
+ _resourceInfo.addWrite(end - (start - result.start));
+ return this;
+ });
+ }
+
+ void writeFromSync(List<int> buffer, [int start = 0, int end]) {
+ _checkAvailable();
+ if ((buffer is! List) ||
+ ((start != null) && (start is! int)) ||
+ ((end != null) && (end is! int))) {
+ throw new ArgumentError("Invalid arguments to writeFromSync");
+ }
+ end = RangeError.checkValidRange(start, end, buffer.length);
+ if (end == start) {
+ return;
+ }
+ _BufferAndStart bufferAndStart =
+ _ensureFastAndSerializableByteData(buffer, start, end);
+ var result = _ops.writeFrom(bufferAndStart.buffer, bufferAndStart.start,
+ end - (start - bufferAndStart.start));
+ if (result is OSError) {
+ throw new FileSystemException("writeFrom failed", path, result);
+ }
+ _resourceInfo.addWrite(end - (start - bufferAndStart.start));
+ }
+
+ Future<RandomAccessFile> writeString(String string,
+ {Encoding encoding: utf8}) {
+ ArgumentError.checkNotNull(encoding, 'encoding');
+ var data = encoding.encode(string);
+ return writeFrom(data, 0, data.length);
+ }
+
+ void writeStringSync(String string, {Encoding encoding: utf8}) {
+ ArgumentError.checkNotNull(encoding, 'encoding');
+ var data = encoding.encode(string);
+ writeFromSync(data, 0, data.length);
+ }
+
+ Future<int> position() {
+ return _dispatch(_IOService.filePosition, [null]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "position failed", path);
+ }
+ return response;
+ });
+ }
+
+ int positionSync() {
+ _checkAvailable();
+ var result = _ops.position();
+ if (result is OSError) {
+ throw new FileSystemException("position failed", path, result);
+ }
+ return result;
+ }
+
+ Future<RandomAccessFile> setPosition(int position) {
+ return _dispatch(_IOService.fileSetPosition, [null, position])
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "setPosition failed", path);
+ }
+ return this;
+ });
+ }
+
+ void setPositionSync(int position) {
+ _checkAvailable();
+ var result = _ops.setPosition(position);
+ if (result is OSError) {
+ throw new FileSystemException("setPosition failed", path, result);
+ }
+ }
+
+ Future<RandomAccessFile> truncate(int length) {
+ return _dispatch(_IOService.fileTruncate, [null, length]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "truncate failed", path);
+ }
+ return this;
+ });
+ }
+
+ void truncateSync(int length) {
+ _checkAvailable();
+ var result = _ops.truncate(length);
+ if (result is OSError) {
+ throw new FileSystemException("truncate failed", path, result);
+ }
+ }
+
+ Future<int> length() {
+ return _dispatch(_IOService.fileLength, [null]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "length failed", path);
+ }
+ return response;
+ });
+ }
+
+ int lengthSync() {
+ _checkAvailable();
+ var result = _ops.length();
+ if (result is OSError) {
+ throw new FileSystemException("length failed", path, result);
+ }
+ return result;
+ }
+
+ Future<RandomAccessFile> flush() {
+ return _dispatch(_IOService.fileFlush, [null]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "flush failed", path);
+ }
+ return this;
+ });
+ }
+
+ void flushSync() {
+ _checkAvailable();
+ var result = _ops.flush();
+ if (result is OSError) {
+ throw new FileSystemException("flush failed", path, result);
+ }
+ }
+
+ static const int lockUnlock = 0;
+ // static const int lockShared = 1;
+ // static const int lockExclusive = 2;
+ // static const int lockBlockingShared = 3;
+ // static const int lockBlockingExclusive = 4;
+
+ int _fileLockValue(FileLock fl) => fl._type;
+
+ Future<RandomAccessFile> lock(
+ [FileLock mode = FileLock.exclusive, int start = 0, int end = -1]) {
+ if ((mode is! FileLock) || (start is! int) || (end is! int)) {
+ throw new ArgumentError();
+ }
+ if ((start < 0) || (end < -1) || ((end != -1) && (start >= end))) {
+ throw new ArgumentError();
+ }
+ int lock = _fileLockValue(mode);
+ return _dispatch(_IOService.fileLock, [null, lock, start, end])
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, 'lock failed', path);
+ }
+ return this;
+ });
+ }
+
+ Future<RandomAccessFile> unlock([int start = 0, int end = -1]) {
+ if ((start is! int) || (end is! int)) {
+ throw new ArgumentError();
+ }
+ if (start == end) {
+ throw new ArgumentError();
+ }
+ return _dispatch(_IOService.fileLock, [null, lockUnlock, start, end])
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, 'unlock failed', path);
+ }
+ return this;
+ });
+ }
+
+ void lockSync(
+ [FileLock mode = FileLock.exclusive, int start = 0, int end = -1]) {
+ _checkAvailable();
+ if ((mode is! FileLock) || (start is! int) || (end is! int)) {
+ throw new ArgumentError();
+ }
+ if ((start < 0) || (end < -1) || ((end != -1) && (start >= end))) {
+ throw new ArgumentError();
+ }
+ int lock = _fileLockValue(mode);
+ var result = _ops.lock(lock, start, end);
+ if (result is OSError) {
+ throw new FileSystemException('lock failed', path, result);
+ }
+ }
+
+ void unlockSync([int start = 0, int end = -1]) {
+ _checkAvailable();
+ if ((start is! int) || (end is! int)) {
+ throw new ArgumentError();
+ }
+ if (start == end) {
+ throw new ArgumentError();
+ }
+ var result = _ops.lock(lockUnlock, start, end);
+ if (result is OSError) {
+ throw new FileSystemException('unlock failed', path, result);
+ }
+ }
+
+ bool closed = false;
+
+ // WARNING:
+ // Calling this function will increase the reference count on the native
+ // object that implements the file operations. It should only be called to
+ // pass the pointer to the IO Service, which will decrement the reference
+ // count when it is finished with it.
+ int _pointer() => _ops.getPointer();
+
+ Future _dispatch(int request, List data, {bool markClosed: false}) {
+ if (closed) {
+ return new Future.error(new FileSystemException("File closed", path));
+ }
+ if (_asyncDispatched) {
+ var msg = "An async operation is currently pending";
+ return new Future.error(new FileSystemException(msg, path));
+ }
+ if (markClosed) {
+ // Set closed to true to ensure that no more async requests can be issued
+ // for this file.
+ closed = true;
+ }
+ _asyncDispatched = true;
+ data[0] = _pointer();
+ return _IOService._dispatch(request, data).whenComplete(() {
+ _asyncDispatched = false;
+ });
+ }
+
+ void _checkAvailable() {
+ if (_asyncDispatched) {
+ throw new FileSystemException(
+ "An async operation is currently pending", path);
+ }
+ if (closed) {
+ throw new FileSystemException("File closed", path);
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/io/file_system_entity.dart b/sdk_nnbd/lib/io/file_system_entity.dart
new file mode 100644
index 0000000..16e99e6
--- /dev/null
+++ b/sdk_nnbd/lib/io/file_system_entity.dart
@@ -0,0 +1,1002 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * The type of an entity on the file system, such as a file, directory, or link.
+ *
+ * These constants are used by the [FileSystemEntity] class
+ * to indicate the object's type.
+ *
+ */
+
+class FileSystemEntityType {
+ static const file = const FileSystemEntityType._internal(0);
+ @Deprecated("Use file instead")
+ static const FILE = file;
+
+ static const directory = const FileSystemEntityType._internal(1);
+ @Deprecated("Use directory instead")
+ static const DIRECTORY = directory;
+
+ static const link = const FileSystemEntityType._internal(2);
+ @Deprecated("Use link instead")
+ static const LINK = link;
+
+ static const notFound = const FileSystemEntityType._internal(3);
+ @Deprecated("Use notFound instead")
+ static const NOT_FOUND = notFound;
+
+ static const _typeList = const [
+ FileSystemEntityType.file,
+ FileSystemEntityType.directory,
+ FileSystemEntityType.link,
+ FileSystemEntityType.notFound,
+ ];
+ final int _type;
+
+ const FileSystemEntityType._internal(this._type);
+
+ static FileSystemEntityType _lookup(int type) => _typeList[type];
+ String toString() => const ['file', 'directory', 'link', 'notFound'][_type];
+}
+
+/**
+ * A FileStat object represents the result of calling the POSIX stat() function
+ * on a file system object. It is an immutable object, representing the
+ * snapshotted values returned by the stat() call.
+ */
+class FileStat {
+ // These must agree with enum FileStat in file.h.
+ static const _type = 0;
+ static const _changedTime = 1;
+ static const _modifiedTime = 2;
+ static const _accessedTime = 3;
+ static const _mode = 4;
+ static const _size = 5;
+
+ static const _notFound = const FileStat._internalNotFound();
+
+ /**
+ * The time of the last change to the data or metadata of the file system
+ * object.
+ *
+ * On Windows platforms, this is instead the file creation time.
+ */
+ final DateTime changed;
+
+ /**
+ * The time of the last change to the data of the file system object.
+ */
+ final DateTime modified;
+
+ /**
+ * The time of the last access to the data of the file system object.
+ *
+ * On Windows platforms, this may have 1 day granularity, and be
+ * out of date by an hour.
+ */
+ final DateTime accessed;
+
+ /**
+ * The type of the underlying file system object.
+ *
+ * [FileSystemEntityType.notFound] if [stat] or [statSync] failed.
+ */
+ final FileSystemEntityType type;
+
+ /**
+ * The mode of the file system object.
+ *
+ * Permissions are encoded in the lower 16 bits of this number, and can be
+ * decoded using the [modeString] getter.
+ */
+ final int mode;
+
+ /**
+ * The size of the file system object.
+ */
+ final int size;
+
+ FileStat._internal(this.changed, this.modified, this.accessed, this.type,
+ this.mode, this.size);
+
+ const FileStat._internalNotFound()
+ : changed = null,
+ modified = null,
+ accessed = null,
+ type = FileSystemEntityType.notFound,
+ mode = 0,
+ size = -1;
+
+ external static _statSync(_Namespace namespace, String path);
+
+ /**
+ * Calls the operating system's `stat()` function (or equivalent) on [path].
+ *
+ * Returns a [FileStat] object containing the data returned by `stat()`.
+ * If the call fails, returns a [FileStat] object with [FileStat.type] set to
+ * [FileSystemEntityType.notFound] and the other fields invalid.
+ */
+ static FileStat statSync(String path) {
+ final IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return _statSyncInternal(path);
+ }
+ return overrides.statSync(path);
+ }
+
+ static FileStat _statSyncInternal(String path) {
+ // Trailing path is not supported on Windows.
+ if (Platform.isWindows) {
+ path = FileSystemEntity._trimTrailingPathSeparators(path);
+ }
+ var data = _statSync(_Namespace._namespace, path);
+ if (data is OSError) return FileStat._notFound;
+ return new FileStat._internal(
+ new DateTime.fromMillisecondsSinceEpoch(data[_changedTime]),
+ new DateTime.fromMillisecondsSinceEpoch(data[_modifiedTime]),
+ new DateTime.fromMillisecondsSinceEpoch(data[_accessedTime]),
+ FileSystemEntityType._lookup(data[_type]),
+ data[_mode],
+ data[_size]);
+ }
+
+ /**
+ * Asynchronously calls the operating system's `stat()` function (or
+ * equivalent) on [path].
+ *
+ * Returns a [Future] which completes with the same results as [statSync].
+ */
+ static Future<FileStat> stat(String path) {
+ final IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return _stat(path);
+ }
+ return overrides.stat(path);
+ }
+
+ static Future<FileStat> _stat(String path) {
+ // Trailing path is not supported on Windows.
+ if (Platform.isWindows) {
+ path = FileSystemEntity._trimTrailingPathSeparators(path);
+ }
+ return _File._dispatchWithNamespace(_IOService.fileStat, [null, path])
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ return FileStat._notFound;
+ }
+ // Unwrap the real list from the "I'm not an error" wrapper.
+ List data = response[1];
+ return new FileStat._internal(
+ new DateTime.fromMillisecondsSinceEpoch(data[_changedTime]),
+ new DateTime.fromMillisecondsSinceEpoch(data[_modifiedTime]),
+ new DateTime.fromMillisecondsSinceEpoch(data[_accessedTime]),
+ FileSystemEntityType._lookup(data[_type]),
+ data[_mode],
+ data[_size]);
+ });
+ }
+
+ String toString() => """
+FileStat: type $type
+ changed $changed
+ modified $modified
+ accessed $accessed
+ mode ${modeString()}
+ size $size""";
+
+ /**
+ * Returns the mode value as a human-readable string.
+ *
+ * The string is in the format "rwxrwxrwx", reflecting the user, group, and
+ * world permissions to read, write, and execute the file system object, with
+ * "-" replacing the letter for missing permissions. Extra permission bits
+ * may be represented by prepending "(suid)", "(guid)", and/or "(sticky)" to
+ * the mode string.
+ */
+ String modeString() {
+ var permissions = mode & 0xFFF;
+ var codes = const ['---', '--x', '-w-', '-wx', 'r--', 'r-x', 'rw-', 'rwx'];
+ var result = [];
+ if ((permissions & 0x800) != 0) result.add("(suid) ");
+ if ((permissions & 0x400) != 0) result.add("(guid) ");
+ if ((permissions & 0x200) != 0) result.add("(sticky) ");
+ result
+ ..add(codes[(permissions >> 6) & 0x7])
+ ..add(codes[(permissions >> 3) & 0x7])
+ ..add(codes[permissions & 0x7]);
+ return result.join();
+ }
+}
+
+/**
+ * The common super class for [File], [Directory], and [Link] objects.
+ *
+ * [FileSystemEntity] objects are returned from directory listing
+ * operations. To determine if a FileSystemEntity is a [File], a
+ * [Directory], or a [Link] perform a type check:
+ *
+ * if (entity is File) (entity as File).readAsStringSync();
+ *
+ * You can also use the [type] or [typeSync] methods to determine
+ * the type of a file system object.
+ *
+ * Most methods in this class occur in synchronous and asynchronous pairs,
+ * for example, [exists] and [existsSync].
+ * Unless you have a specific reason for using the synchronous version
+ * of a method, prefer the asynchronous version to avoid blocking your program.
+ *
+ * Here's the exists method in action:
+ *
+ * entity.exists().then((isThere) {
+ * isThere ? print('exists') : print('non-existent');
+ * });
+ *
+ *
+ * ## Other resources
+ *
+ * * [Dart by
+ * Example](https://www.dartlang.org/dart-by-example/#files-directories-and-symlinks)
+ * provides additional task-oriented code samples that show how to use various
+ * API from the [Directory] class and the [File] class, both subclasses of
+ * FileSystemEntity.
+ *
+ * * [I/O for Command-Line
+ * Apps](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartio---io-for-command-line-apps),
+ * a section from _A Tour of the Dart Libraries_ covers files and directories.
+ *
+ * * [Write Command-Line Apps](https://www.dartlang.org/docs/tutorials/cmdline/),
+ * a tutorial about writing command-line apps, includes information about
+ * files and directories.
+ */
+abstract class FileSystemEntity {
+ String _path;
+ Uint8List _rawPath;
+
+ String get path;
+
+ /**
+ * Returns a [Uri] representing the file system entity's location.
+ *
+ * The returned URI's scheme is always "file" if the entity's [path] is
+ * absolute, otherwise the scheme will be empty.
+ */
+ Uri get uri => new Uri.file(path);
+
+ /**
+ * Checks whether the file system entity with this path exists. Returns
+ * a [:Future<bool>:] that completes with the result.
+ *
+ * Since FileSystemEntity is abstract, every FileSystemEntity object
+ * is actually an instance of one of the subclasses [File],
+ * [Directory], and [Link]. Calling [exists] on an instance of one
+ * of these subclasses checks whether the object exists in the file
+ * system object exists and is of the correct type (file, directory,
+ * or link). To check whether a path points to an object on the
+ * file system, regardless of the object's type, use the [type]
+ * static method.
+ *
+ */
+ Future<bool> exists();
+
+ /**
+ * Synchronously checks whether the file system entity with this path
+ * exists.
+ *
+ * Since FileSystemEntity is abstract, every FileSystemEntity object
+ * is actually an instance of one of the subclasses [File],
+ * [Directory], and [Link]. Calling [existsSync] on an instance of
+ * one of these subclasses checks whether the object exists in the
+ * file system object exists and is of the correct type (file,
+ * directory, or link). To check whether a path points to an object
+ * on the file system, regardless of the object's type, use the
+ * [typeSync] static method.
+ */
+ bool existsSync();
+
+ /**
+ * Renames this file system entity.
+ *
+ * Returns a `Future<FileSystemEntity>` that completes with a
+ * [FileSystemEntity] instance for the renamed file system entity.
+ *
+ * If [newPath] identifies an existing entity of the same type, that entity
+ * is replaced. If [newPath] identifies an existing entity of a different
+ * type, the operation fails and the future completes with an exception.
+ */
+ Future<FileSystemEntity> rename(String newPath);
+
+ /**
+ * Synchronously renames this file system entity.
+ *
+ * Returns a [FileSystemEntity] instance for the renamed entity.
+ *
+ * If [newPath] identifies an existing entity of the same type, that entity
+ * is replaced. If [newPath] identifies an existing entity of a different
+ * type, the operation fails and an exception is thrown.
+ */
+ FileSystemEntity renameSync(String newPath);
+
+ /**
+ * Resolves the path of a file system object relative to the
+ * current working directory.
+ *
+ * Resolves all symbolic links on the path and resolves all `..` and `.` path
+ * segments.
+ *
+ * [resolveSymbolicLinks] uses the operating system's native
+ * file system API to resolve the path, using the `realpath` function
+ * on linux and OS X, and the `GetFinalPathNameByHandle` function on
+ * Windows. If the path does not point to an existing file system object,
+ * `resolveSymbolicLinks` throws a `FileSystemException`.
+ *
+ * On Windows the `..` segments are resolved _before_ resolving the symbolic
+ * link, and on other platforms the symbolic links are _resolved to their
+ * target_ before applying a `..` that follows.
+ *
+ * To ensure the same behavior on all platforms resolve `..` segments before
+ * calling `resolveSymbolicLinks`. One way of doing this is with the `Uri`
+ * class:
+ *
+ * var path = Uri.parse('.').resolveUri(new Uri.file(input)).toFilePath();
+ * if (path == '') path = '.';
+ * new File(path).resolveSymbolicLinks().then((resolved) {
+ * print(resolved);
+ * });
+ *
+ * since `Uri.resolve` removes `..` segments. This will result in the Windows
+ * behavior.
+ */
+ Future<String> resolveSymbolicLinks() {
+ return _File._dispatchWithNamespace(
+ _IOService.fileResolveSymbolicLinks, [null, _rawPath]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(
+ response, "Cannot resolve symbolic links", path);
+ }
+ return response;
+ });
+ }
+
+ /**
+ * Resolves the path of a file system object relative to the
+ * current working directory.
+ *
+ * Resolves all symbolic links on the path and resolves all `..` and `.` path
+ * segments.
+ *
+ * [resolveSymbolicLinksSync] uses the operating system's native
+ * file system API to resolve the path, using the `realpath` function
+ * on linux and OS X, and the `GetFinalPathNameByHandle` function on
+ * Windows. If the path does not point to an existing file system object,
+ * `resolveSymbolicLinksSync` throws a `FileSystemException`.
+ *
+ * On Windows the `..` segments are resolved _before_ resolving the symbolic
+ * link, and on other platforms the symbolic links are _resolved to their
+ * target_ before applying a `..` that follows.
+ *
+ * To ensure the same behavior on all platforms resolve `..` segments before
+ * calling `resolveSymbolicLinksSync`. One way of doing this is with the `Uri`
+ * class:
+ *
+ * var path = Uri.parse('.').resolveUri(new Uri.file(input)).toFilePath();
+ * if (path == '') path = '.';
+ * var resolved = new File(path).resolveSymbolicLinksSync();
+ * print(resolved);
+ *
+ * since `Uri.resolve` removes `..` segments. This will result in the Windows
+ * behavior.
+ */
+ String resolveSymbolicLinksSync() {
+ var result = _resolveSymbolicLinks(_Namespace._namespace, _rawPath);
+ _throwIfError(result, "Cannot resolve symbolic links", path);
+ return result;
+ }
+
+ /**
+ * Calls the operating system's stat() function on the [path] of this
+ * [FileSystemEntity].
+ *
+ * Identical to [:FileStat.stat(this.path):].
+ *
+ * Returns a [:Future<FileStat>:] object containing the data returned by
+ * stat().
+ *
+ * If the call fails, completes the future with a [FileStat] object
+ * with `.type` set to [FileSystemEntityType.notFound] and the other fields
+ * invalid.
+ */
+ Future<FileStat> stat() => FileStat.stat(path);
+
+ /**
+ * Synchronously calls the operating system's stat() function on the
+ * [path] of this [FileSystemEntity].
+ *
+ * Identical to [:FileStat.statSync(this.path):].
+ *
+ * Returns a [FileStat] object containing the data returned by stat().
+ *
+ * If the call fails, returns a [FileStat] object with `.type` set to
+ * [FileSystemEntityType.notFound] and the other fields invalid.
+ */
+ FileStat statSync() => FileStat.statSync(path);
+
+ /**
+ * Deletes this [FileSystemEntity].
+ *
+ * If the [FileSystemEntity] is a directory, and if [recursive] is false,
+ * the directory must be empty. Otherwise, if [recursive] is true, the
+ * directory and all sub-directories and files in the directories are
+ * deleted. Links are not followed when deleting recursively. Only the link
+ * is deleted, not its target.
+ *
+ * If [recursive] is true, the [FileSystemEntity] is deleted even if the type
+ * of the [FileSystemEntity] doesn't match the content of the file system.
+ * This behavior allows [delete] to be used to unconditionally delete any file
+ * system object.
+ *
+ * Returns a [:Future<FileSystemEntity>:] that completes with this
+ * [FileSystemEntity] when the deletion is done. If the [FileSystemEntity]
+ * cannot be deleted, the future completes with an exception.
+ */
+ Future<FileSystemEntity> delete({bool recursive: false}) =>
+ _delete(recursive: recursive);
+
+ /**
+ * Synchronously deletes this [FileSystemEntity].
+ *
+ * If the [FileSystemEntity] is a directory, and if [recursive] is false,
+ * the directory must be empty. Otherwise, if [recursive] is true, the
+ * directory and all sub-directories and files in the directories are
+ * deleted. Links are not followed when deleting recursively. Only the link
+ * is deleted, not its target.
+ *
+ * If [recursive] is true, the [FileSystemEntity] is deleted even if the type
+ * of the [FileSystemEntity] doesn't match the content of the file system.
+ * This behavior allows [deleteSync] to be used to unconditionally delete any
+ * file system object.
+ *
+ * Throws an exception if the [FileSystemEntity] cannot be deleted.
+ */
+ void deleteSync({bool recursive: false}) => _deleteSync(recursive: recursive);
+
+ /**
+ * Start watching the [FileSystemEntity] for changes.
+ *
+ * The implementation uses platform-dependent event-based APIs for receiving
+ * file-system notifications, thus behavior depends on the platform.
+ *
+ * * `Windows`: Uses `ReadDirectoryChangesW`. The implementation only
+ * supports watching directories. Recursive watching is supported.
+ * * `Linux`: Uses `inotify`. The implementation supports watching both
+ * files and directories. Recursive watching is not supported.
+ * Note: When watching files directly, delete events might not happen
+ * as expected.
+ * * `OS X`: Uses `FSEvents`. The implementation supports watching both
+ * files and directories. Recursive watching is supported.
+ *
+ * The system will start listening for events once the returned [Stream] is
+ * being listened to, not when the call to [watch] is issued.
+ *
+ * The returned value is an endless broadcast [Stream], that only stops when
+ * one of the following happens:
+ *
+ * * The [Stream] is canceled, e.g. by calling `cancel` on the
+ * [StreamSubscription].
+ * * The [FileSystemEntity] being watches, is deleted.
+ *
+ * Use `events` to specify what events to listen for. The constants in
+ * [FileSystemEvent] can be or'ed together to mix events. Default is
+ * [FileSystemEvent.ALL].
+ *
+ * A move event may be reported as seperate delete and create events.
+ */
+ Stream<FileSystemEvent> watch(
+ {int events: FileSystemEvent.all, bool recursive: false}) {
+ // FIXME(bkonyi): find a way to do this using the raw path.
+ final String trimmedPath = _trimTrailingPathSeparators(path);
+ final IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return _FileSystemWatcher._watch(trimmedPath, events, recursive);
+ }
+ return overrides.fsWatch(trimmedPath, events, recursive);
+ }
+
+ Future<FileSystemEntity> _delete({bool recursive: false});
+ void _deleteSync({bool recursive: false});
+
+ static Future<bool> _identical(String path1, String path2) {
+ return _File._dispatchWithNamespace(
+ _IOService.fileIdentical, [null, path1, path2]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response,
+ "Error in FileSystemEntity.identical($path1, $path2)", "");
+ }
+ return response;
+ });
+ }
+
+ /**
+ * Checks whether two paths refer to the same object in the
+ * file system.
+ *
+ * Returns a [:Future<bool>:] that completes with the result.
+ *
+ * Comparing a link to its target returns false, as does comparing two links
+ * that point to the same target. To check the target of a link, use
+ * Link.target explicitly to fetch it. Directory links appearing
+ * inside a path are followed, though, to find the file system object.
+ *
+ * Completes the returned Future with an error if one of the paths points
+ * to an object that does not exist.
+ */
+ static Future<bool> identical(String path1, String path2) {
+ IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return _identical(path1, path2);
+ }
+ return overrides.fseIdentical(path1, path2);
+ }
+
+ static final RegExp _absoluteWindowsPathPattern =
+ new RegExp(r'^(\\\\|[a-zA-Z]:[/\\])');
+
+ /**
+ * Returns a [bool] indicating whether this object's path is absolute.
+ *
+ * On Windows, a path is absolute if it starts with \\\\ or a drive letter
+ * between a and z (upper or lower case) followed by :\\ or :/.
+ * On non-Windows, a path is absolute if it starts with /.
+ */
+ bool get isAbsolute {
+ if (Platform.isWindows) {
+ return path.startsWith(_absoluteWindowsPathPattern);
+ } else {
+ return path.startsWith('/');
+ }
+ }
+
+ /**
+ * Returns a [FileSystemEntity] whose path is the absolute path to [this].
+ *
+ * The type of the returned instance is the type of [this].
+ *
+ * The absolute path is computed by prefixing
+ * a relative path with the current working directory, and returning
+ * an absolute path unchanged.
+ */
+ FileSystemEntity get absolute;
+
+ String get _absolutePath {
+ if (isAbsolute) return path;
+ String current = Directory.current.path;
+ if (current.endsWith('/') ||
+ (Platform.isWindows && current.endsWith('\\'))) {
+ return '$current$path';
+ } else {
+ return '$current${Platform.pathSeparator}$path';
+ }
+ }
+
+ Uint8List get _rawAbsolutePath {
+ if (isAbsolute) return _rawPath;
+ var current = Directory.current._rawPath.toList();
+ assert(current.last == 0);
+ current.removeLast(); // Remove null terminator.
+ if ((current.last == '/'.codeUnitAt(0)) ||
+ (Platform.isWindows && (current.last == '\\'.codeUnitAt(0)))) {
+ current.addAll(_rawPath);
+ return new Uint8List.fromList(current);
+ } else {
+ current.addAll(utf8.encode(Platform.pathSeparator));
+ current.addAll(_rawPath);
+ return new Uint8List.fromList(current);
+ }
+ }
+
+ static bool _identicalSync(String path1, String path2) {
+ var result = _identicalNative(_Namespace._namespace, path1, path2);
+ _throwIfError(result, 'Error in FileSystemEntity.identicalSync');
+ return result;
+ }
+
+ /**
+ * Synchronously checks whether two paths refer to the same object in the
+ * file system.
+ *
+ * Comparing a link to its target returns false, as does comparing two links
+ * that point to the same target. To check the target of a link, use
+ * Link.target explicitly to fetch it. Directory links appearing
+ * inside a path are followed, though, to find the file system object.
+ *
+ * Throws an error if one of the paths points to an object that does not
+ * exist.
+ */
+ static bool identicalSync(String path1, String path2) {
+ IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return _identicalSync(path1, path2);
+ }
+ return overrides.fseIdenticalSync(path1, path2);
+ }
+
+ /**
+ * Test if [watch] is supported on the current system.
+ *
+ * OS X 10.6 and below is not supported.
+ */
+ static bool get isWatchSupported {
+ final IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return _FileSystemWatcher.isSupported;
+ }
+ return overrides.fsWatchIsSupported();
+ }
+
+ // The native methods which determine type of the FileSystemEntity require
+ // that the buffer provided is null terminated.
+ static Uint8List _toUtf8Array(String s) =>
+ _toNullTerminatedUtf8Array(utf8.encode(s));
+
+ static Uint8List _toNullTerminatedUtf8Array(Uint8List l) {
+ if (l == null) {
+ return null;
+ }
+ if (l.isNotEmpty && l.last != 0) {
+ final tmp = new Uint8List(l.length + 1);
+ tmp.setRange(0, l.length, l);
+ return tmp;
+ } else {
+ return l;
+ }
+ }
+
+ static String _toStringFromUtf8Array(Uint8List l) {
+ if (l == null) {
+ return '';
+ }
+ Uint8List nonNullTerminated = l;
+ if (l.last == 0) {
+ nonNullTerminated = new Uint8List.view(l.buffer, 0, l.length - 1);
+ }
+ return utf8.decode(nonNullTerminated, allowMalformed: true);
+ }
+
+ /**
+ * Finds the type of file system object that a path points to.
+ *
+ * Returns a [:Future<FileSystemEntityType>:] that completes with the same
+ * results as [typeSync].
+ */
+ static Future<FileSystemEntityType> type(String path,
+ {bool followLinks: true}) {
+ return _getType(_toUtf8Array(path), followLinks);
+ }
+
+ /**
+ * Synchronously finds the type of file system object that a path points to.
+ *
+ * Returns a [FileSystemEntityType].
+ *
+ * Returns [FileSystemEntityType.link] only if [followLinks] is false and if
+ * [path] points to a link.
+ *
+ * Returns [FileSystemEntityType.notFound] if [path] does not point to a file
+ * system object or if any other error occurs in looking up the path.
+ */
+ static FileSystemEntityType typeSync(String path, {bool followLinks: true}) {
+ return _getTypeSync(_toUtf8Array(path), followLinks);
+ }
+
+ /**
+ * Checks if type(path, followLinks: false) returns FileSystemEntityType.link.
+ */
+ static Future<bool> isLink(String path) => _isLinkRaw(_toUtf8Array(path));
+
+ static Future<bool> _isLinkRaw(Uint8List rawPath) => _getType(rawPath, false)
+ .then((type) => (type == FileSystemEntityType.link));
+
+ /**
+ * Checks if type(path) returns FileSystemEntityType.file.
+ */
+ static Future<bool> isFile(String path) => _getType(_toUtf8Array(path), true)
+ .then((type) => (type == FileSystemEntityType.file));
+
+ /**
+ * Checks if type(path) returns FileSystemEntityType.directory.
+ */
+ static Future<bool> isDirectory(String path) =>
+ _getType(_toUtf8Array(path), true)
+ .then((type) => (type == FileSystemEntityType.directory));
+
+ /**
+ * Synchronously checks if typeSync(path, followLinks: false) returns
+ * FileSystemEntityType.link.
+ */
+ static bool isLinkSync(String path) => _isLinkRawSync(_toUtf8Array(path));
+
+ static bool _isLinkRawSync(rawPath) =>
+ (_getTypeSync(rawPath, false) == FileSystemEntityType.link);
+
+ /**
+ * Synchronously checks if typeSync(path) returns
+ * FileSystemEntityType.file.
+ */
+ static bool isFileSync(String path) =>
+ (_getTypeSync(_toUtf8Array(path), true) == FileSystemEntityType.file);
+
+ /**
+ * Synchronously checks if typeSync(path) returns
+ * FileSystemEntityType.directory.
+ */
+ static bool isDirectorySync(String path) =>
+ (_getTypeSync(_toUtf8Array(path), true) ==
+ FileSystemEntityType.directory);
+
+ external static _getTypeNative(
+ _Namespace namespace, Uint8List rawPath, bool followLinks);
+ external static _identicalNative(
+ _Namespace namespace, String path1, String path2);
+ external static _resolveSymbolicLinks(_Namespace namespace, Uint8List path);
+
+ // Finds the next-to-last component when dividing at path separators.
+ static final RegExp _parentRegExp = Platform.isWindows
+ ? new RegExp(r'[^/\\][/\\]+[^/\\]')
+ : new RegExp(r'[^/]/+[^/]');
+
+ /**
+ * Removes the final path component of a path, using the platform's
+ * path separator to split the path.
+ *
+ * Will not remove the root component of a Windows path, like "C:\\" or
+ * "\\\\server_name\\". Ignores trailing path separators, and leaves no
+ * trailing path separators.
+ */
+ static String parentOf(String path) {
+ int rootEnd = -1;
+ if (Platform.isWindows) {
+ if (path.startsWith(_absoluteWindowsPathPattern)) {
+ // Root ends at first / or \ after the first two characters.
+ rootEnd = path.indexOf(new RegExp(r'[/\\]'), 2);
+ if (rootEnd == -1) return path;
+ } else if (path.startsWith('\\') || path.startsWith('/')) {
+ rootEnd = 0;
+ }
+ } else if (path.startsWith('/')) {
+ rootEnd = 0;
+ }
+ // Ignore trailing slashes.
+ // All non-trivial cases have separators between two non-separators.
+ int pos = path.lastIndexOf(_parentRegExp);
+ if (pos > rootEnd) {
+ return path.substring(0, pos + 1);
+ } else if (rootEnd > -1) {
+ return path.substring(0, rootEnd + 1);
+ } else {
+ return '.';
+ }
+ }
+
+ /**
+ * The directory containing [this].
+ */
+ Directory get parent => new Directory(parentOf(path));
+
+ static FileSystemEntityType _getTypeSyncHelper(
+ Uint8List rawPath, bool followLinks) {
+ var result = _getTypeNative(_Namespace._namespace, rawPath, followLinks);
+ _throwIfError(result, 'Error getting type of FileSystemEntity');
+ return FileSystemEntityType._lookup(result);
+ }
+
+ static FileSystemEntityType _getTypeSync(
+ Uint8List rawPath, bool followLinks) {
+ IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return _getTypeSyncHelper(rawPath, followLinks);
+ }
+ return overrides.fseGetTypeSync(
+ utf8.decode(rawPath, allowMalformed: true), followLinks);
+ }
+
+ static Future<FileSystemEntityType> _getTypeRequest(
+ Uint8List rawPath, bool followLinks) {
+ return _File._dispatchWithNamespace(
+ _IOService.fileType, [null, rawPath, followLinks]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "Error getting type",
+ utf8.decode(rawPath, allowMalformed: true));
+ }
+ return FileSystemEntityType._lookup(response);
+ });
+ }
+
+ static Future<FileSystemEntityType> _getType(
+ Uint8List rawPath, bool followLinks) {
+ IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return _getTypeRequest(rawPath, followLinks);
+ }
+ return overrides.fseGetType(
+ utf8.decode(rawPath, allowMalformed: true), followLinks);
+ }
+
+ static _throwIfError(Object result, String msg, [String path]) {
+ if (result is OSError) {
+ throw new FileSystemException(msg, path, result);
+ } else if (result is ArgumentError) {
+ throw result;
+ }
+ }
+
+ // TODO(bkonyi): find a way to do this with raw paths.
+ static String _trimTrailingPathSeparators(String path) {
+ // Don't handle argument errors here.
+ if (path == null) return path;
+ if (Platform.isWindows) {
+ while (path.length > 1 &&
+ (path.endsWith(Platform.pathSeparator) || path.endsWith('/'))) {
+ path = path.substring(0, path.length - 1);
+ }
+ } else {
+ while (path.length > 1 && path.endsWith(Platform.pathSeparator)) {
+ path = path.substring(0, path.length - 1);
+ }
+ }
+ return path;
+ }
+
+ // TODO(bkonyi): find a way to do this with raw paths.
+ static String _ensureTrailingPathSeparators(String path) {
+ // Don't handle argument errors here.
+ if (path == null) return path;
+ if (path.isEmpty) path = '.';
+ if (Platform.isWindows) {
+ while (!path.endsWith(Platform.pathSeparator) && !path.endsWith('/')) {
+ path = "$path${Platform.pathSeparator}";
+ }
+ } else {
+ while (!path.endsWith(Platform.pathSeparator)) {
+ path = "$path${Platform.pathSeparator}";
+ }
+ }
+ return path;
+ }
+}
+
+/**
+ * Base event class emitted by [FileSystemEntity.watch].
+ */
+class FileSystemEvent {
+ /**
+ * Bitfield for [FileSystemEntity.watch], to enable [FileSystemCreateEvent]s.
+ */
+ static const int create = 1 << 0;
+ @Deprecated("Use create instead")
+ static const int CREATE = 1 << 0;
+
+ /**
+ * Bitfield for [FileSystemEntity.watch], to enable [FileSystemModifyEvent]s.
+ */
+ static const int modify = 1 << 1;
+ @Deprecated("Use modify instead")
+ static const int MODIFY = 1 << 1;
+
+ /**
+ * Bitfield for [FileSystemEntity.watch], to enable [FileSystemDeleteEvent]s.
+ */
+ static const int delete = 1 << 2;
+ @Deprecated("Use delete instead")
+ static const int DELETE = 1 << 2;
+
+ /**
+ * Bitfield for [FileSystemEntity.watch], to enable [FileSystemMoveEvent]s.
+ */
+ static const int move = 1 << 3;
+ @Deprecated("Use move instead")
+ static const int MOVE = 1 << 3;
+
+ /**
+ * Bitfield for [FileSystemEntity.watch], for enabling all of [create],
+ * [modify], [delete] and [move].
+ */
+ static const int all = create | modify | delete | move;
+ @Deprecated("Use all instead")
+ static const int ALL = create | modify | delete | move;
+
+ static const int _modifyAttributes = 1 << 4;
+ static const int _deleteSelf = 1 << 5;
+ static const int _isDir = 1 << 6;
+
+ /**
+ * The type of event. See [FileSystemEvent] for a list of events.
+ */
+ final int type;
+
+ /**
+ * The path that triggered the event.
+ *
+ * Depending on the platform and the FileSystemEntity, the path may be
+ * relative.
+ */
+ final String path;
+
+ /**
+ * Is `true` if the event target was a directory.
+ *
+ * Note that if the file has been deleted by the time the event has arrived,
+ * this will always be `false` on Windows. In particular, it will always be
+ * `false` for `delete` events.
+ */
+ final bool isDirectory;
+
+ FileSystemEvent._(this.type, this.path, this.isDirectory);
+}
+
+/**
+ * File system event for newly created file system objects.
+ */
+class FileSystemCreateEvent extends FileSystemEvent {
+ FileSystemCreateEvent._(path, isDirectory)
+ : super._(FileSystemEvent.create, path, isDirectory);
+
+ String toString() => "FileSystemCreateEvent('$path')";
+}
+
+/**
+ * File system event for modifications of file system objects.
+ */
+class FileSystemModifyEvent extends FileSystemEvent {
+ /**
+ * If the content was changed and not only the attributes, [contentChanged]
+ * is `true`.
+ */
+ final bool contentChanged;
+
+ FileSystemModifyEvent._(path, isDirectory, this.contentChanged)
+ : super._(FileSystemEvent.modify, path, isDirectory);
+
+ String toString() =>
+ "FileSystemModifyEvent('$path', contentChanged=$contentChanged)";
+}
+
+/**
+ * File system event for deletion of file system objects.
+ */
+class FileSystemDeleteEvent extends FileSystemEvent {
+ FileSystemDeleteEvent._(path, isDirectory)
+ : super._(FileSystemEvent.delete, path, isDirectory);
+
+ String toString() => "FileSystemDeleteEvent('$path')";
+}
+
+/**
+ * File system event for moving of file system objects.
+ */
+class FileSystemMoveEvent extends FileSystemEvent {
+ /**
+ * If the underlying implementation is able to identify the destination of
+ * the moved file, [destination] will be set. Otherwise, it will be `null`.
+ */
+ final String destination;
+
+ FileSystemMoveEvent._(path, isDirectory, this.destination)
+ : super._(FileSystemEvent.move, path, isDirectory);
+
+ String toString() {
+ var buffer = new StringBuffer();
+ buffer.write("FileSystemMoveEvent('$path'");
+ if (destination != null) buffer.write(", '$destination'");
+ buffer.write(')');
+ return buffer.toString();
+ }
+}
+
+class _FileSystemWatcher {
+ external static Stream<FileSystemEvent> _watch(
+ String path, int events, bool recursive);
+ external static bool get isSupported;
+}
diff --git a/sdk_nnbd/lib/io/io.dart b/sdk_nnbd/lib/io/io.dart
new file mode 100644
index 0000000..c640c5b
--- /dev/null
+++ b/sdk_nnbd/lib/io/io.dart
@@ -0,0 +1,227 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * File, socket, HTTP, and other I/O support for non-web applications.
+ *
+ * **Important:** Browser-based applications can't use this library.
+ * Only servers, command-line scripts, and Flutter mobile apps can import
+ * and use dart:io.
+ *
+ * This library allows you to work with files, directories,
+ * sockets, processes, HTTP servers and clients, and more.
+ * Many operations related to input and output are asynchronous
+ * and are handled using [Future]s or [Stream]s, both of which
+ * are defined in the [dart:async
+ * library](../dart-async/dart-async-library.html).
+ *
+ * To use the dart:io library in your code:
+ *
+ * import 'dart:io';
+ *
+ * For an introduction to I/O in Dart, see the [dart:io library
+ * tour](https://www.dartlang.org/dart-vm/io-library-tour).
+ *
+ * ## File, Directory, and Link
+ *
+ * An instance of [File], [Directory], or [Link] represents a file,
+ * directory, or link, respectively, in the native file system.
+ *
+ * You can manipulate the file system through objects of these types.
+ * For example, you can rename a file or directory:
+ *
+ * File myFile = new File('myFile.txt');
+ * myFile.rename('yourFile.txt').then((_) => print('file renamed'));
+ *
+ * Many methods provided by the File, Directory, and Link classes
+ * run asynchronously and return a Future.
+ *
+ * ## FileSystemEntity
+ *
+ * File, Directory, and Link all extend [FileSystemEntity].
+ * In addition to being the superclass for these classes,
+ * FileSystemEntity has a number of static methods for working with paths.
+ *
+ * To get information about a path,
+ * you can use the FileSystemEntity static methods
+ * such as 'isDirectory', 'isFile', and 'exists'.
+ * Because file system access involves I/O, these methods
+ * are asynchronous and return a Future.
+ *
+ * FileSystemEntity.isDirectory(myPath).then((isDir) {
+ * if (isDir) {
+ * print('$myPath is a directory');
+ * } else {
+ * print('$myPath is not a directory');
+ * }
+ * });
+ *
+ * ## HttpServer and HttpClient
+ *
+ * The classes [HttpServer] and [HttpClient]
+ * provide HTTP server and HTTP client functionality.
+ *
+ * The [HttpServer] class provides the basic functionality for
+ * implementing an HTTP server.
+ * For some higher-level building-blocks, we recommend that you try
+ * the [shelf](https://pub.dartlang.org/packages/shelf)
+ * pub package, which contains
+ * a set of high-level classes that, together with the [HttpServer] class
+ * in this library, make it easier to implement HTTP servers.
+ *
+ * ## Process
+ *
+ * The [Process] class provides a way to run a process on
+ * the native machine.
+ * For example, the following code spawns a process that recursively lists
+ * the files under `web`.
+ *
+ * Process.start('ls', ['-R', 'web']).then((process) {
+ * stdout.addStream(process.stdout);
+ * stderr.addStream(process.stderr);
+ * process.exitCode.then(print);
+ * });
+ *
+ * Using `start()` returns a Future, which completes with a [Process] object
+ * when the process has started. This [Process] object allows you to interact
+ * with the process while it is running. Using `run()` returns a Future, which
+ * completes with a [ProcessResult] object when the spawned process has
+ * terminated. This [ProcessResult] object collects the output and exit code
+ * from the process.
+ *
+ * When using `start()`,
+ * you need to read all data coming on the stdout and stderr streams otherwise
+ * the system resources will not be freed.
+ *
+ * ## WebSocket
+ *
+ * The [WebSocket] class provides support for the web socket protocol. This
+ * allows full-duplex communications between client and server applications.
+ *
+ * A web socket server uses a normal HTTP server for accepting web socket
+ * connections. The initial handshake is a HTTP request which is then upgraded to a
+ * web socket connection.
+ * The server upgrades the request using [WebSocketTransformer]
+ * and listens for the data on the returned web socket.
+ * For example, here's a mini server that listens for 'ws' data
+ * on a WebSocket:
+ *
+ * runZoned(() async {
+ * var server = await HttpServer.bind('127.0.0.1', 4040);
+ * server.listen((HttpRequest req) async {
+ * if (req.uri.path == '/ws') {
+ * var socket = await WebSocketTransformer.upgrade(req);
+ * socket.listen(handleMsg);
+ * }
+ * });
+ * }, onError: (e) => print("An error occurred."));
+ *
+ * The client connects to the WebSocket using the `connect()` method
+ * and a URI that uses the Web Socket protocol.
+ * The client can write to the WebSocket with the `add()` method.
+ * For example,
+ *
+ * var socket = await WebSocket.connect('ws://127.0.0.1:4040/ws');
+ * socket.add('Hello, World!');
+ *
+ * Check out the
+ * [websocket_sample](https://github.com/dart-lang/dart-samples/tree/master/html5/web/websockets/basics)
+ * app, which uses WebSockets to communicate with a server.
+ *
+ * ## Socket and ServerSocket
+ *
+ * Clients and servers use [Socket]s to communicate using the TCP protocol.
+ * Use [ServerSocket] on the server side and [Socket] on the client.
+ * The server creates a listening socket using the `bind()` method and
+ * then listens for incoming connections on the socket. For example:
+ *
+ * ServerSocket.bind('127.0.0.1', 4041)
+ * .then((serverSocket) {
+ * serverSocket.listen((socket) {
+ * socket.transform(utf8.decoder).listen(print);
+ * });
+ * });
+ *
+ * A client connects a Socket using the `connect()` method,
+ * which returns a Future.
+ * Using `write()`, `writeln()`, or `writeAll()` are the easiest ways to
+ * send data over the socket.
+ * For example:
+ *
+ * Socket.connect('127.0.0.1', 4041).then((socket) {
+ * socket.write('Hello, World!');
+ * });
+ *
+ * Besides [Socket] and [ServerSocket], the [RawSocket] and
+ * [RawServerSocket] classes are available for lower-level access
+ * to async socket IO.
+ *
+ * ## Standard output, error, and input streams
+ *
+ * This library provides the standard output, error, and input
+ * streams, named 'stdout', 'stderr', and 'stdin', respectively.
+ *
+ * The stdout and stderr streams are both [IOSink]s and have the same set
+ * of methods and properties.
+ *
+ * To write a string to 'stdout':
+ *
+ * stdout.writeln('Hello, World!');
+ *
+ * To write a list of objects to 'stderr':
+ *
+ * stderr.writeAll([ 'That ', 'is ', 'an ', 'error.', '\n']);
+ *
+ * The standard input stream is a true [Stream], so it inherits
+ * properties and methods from the Stream class.
+ *
+ * To read text synchronously from the command line
+ * (the program blocks waiting for user to type information):
+ *
+ * String inputText = stdin.readLineSync();
+ *
+ * {@category VM}
+ */
+library dart.io;
+
+import 'dart:async';
+import 'dart:_internal' hide Symbol;
+import 'dart:collection'
+ show HashMap, HashSet, Queue, ListQueue, MapBase, UnmodifiableMapView;
+import 'dart:convert';
+import 'dart:developer' hide log;
+import 'dart:isolate';
+import 'dart:math';
+import 'dart:typed_data';
+
+export 'dart:_http';
+export 'dart:_internal' show HttpStatus;
+
+part 'bytes_builder.dart';
+part 'common.dart';
+part 'data_transformer.dart';
+part 'directory.dart';
+part 'directory_impl.dart';
+part 'embedder_config.dart';
+part 'eventhandler.dart';
+part 'file.dart';
+part 'file_impl.dart';
+part 'file_system_entity.dart';
+part 'io_resource_info.dart';
+part 'io_sink.dart';
+part 'io_service.dart';
+part 'link.dart';
+part 'namespace_impl.dart';
+part 'overrides.dart';
+part 'platform.dart';
+part 'platform_impl.dart';
+part 'process.dart';
+part 'secure_server_socket.dart';
+part 'secure_socket.dart';
+part 'security_context.dart';
+part 'service_object.dart';
+part 'socket.dart';
+part 'stdio.dart';
+part 'string_transformer.dart';
+part 'sync_socket.dart';
diff --git a/sdk_nnbd/lib/io/io_resource_info.dart b/sdk_nnbd/lib/io/io_resource_info.dart
new file mode 100644
index 0000000..3e29221
--- /dev/null
+++ b/sdk_nnbd/lib/io/io_resource_info.dart
@@ -0,0 +1,282 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+abstract class _IOResourceInfo {
+ final String type;
+ final int id;
+ String get name;
+ static int _count = 0;
+
+ static final Stopwatch _sw = new Stopwatch()..start();
+ static final _startTime = new DateTime.now().millisecondsSinceEpoch;
+
+ static double get timestamp => _startTime + _sw.elapsedMicroseconds / 1000;
+
+ _IOResourceInfo(this.type) : id = _IOResourceInfo.getNextID();
+
+ /// Get the full set of values for a specific implementation. This is normally
+ /// looked up based on an id from a referenceValueMap.
+ Map<String, dynamic> get fullValueMap;
+
+ /// The reference map, used to return a list of values, e.g., getting
+ /// all open sockets. The structure of this is shared among all subclasses.
+ Map<String, dynamic> get referenceValueMap => {
+ // The type for a reference object is prefixed with @ in observatory.
+ 'type': '@$type',
+ 'id': id,
+ 'name': name,
+ };
+
+ static int getNextID() => _count++;
+}
+
+abstract class _ReadWriteResourceInfo extends _IOResourceInfo {
+ int totalRead;
+ int totalWritten;
+ int readCount;
+ int writeCount;
+ double lastRead;
+ double lastWrite;
+
+ // Not all call sites use this. In some cases, e.g., a socket, a read does
+ // not always mean that we actually read some bytes (we may do a read to see
+ // if there are some bytes available).
+ void addRead(int bytes) {
+ totalRead += bytes;
+ readCount++;
+ lastRead = _IOResourceInfo.timestamp;
+ }
+
+ // In cases where we read but did not necessarily get any bytes, use this to
+ // update the readCount and timestamp. Manually update totalRead if any bytes
+ // where actually read.
+ void didRead() {
+ addRead(0);
+ }
+
+ void addWrite(int bytes) {
+ totalWritten += bytes;
+ writeCount++;
+ lastWrite = _IOResourceInfo.timestamp;
+ }
+
+ _ReadWriteResourceInfo(String type)
+ : totalRead = 0,
+ totalWritten = 0,
+ readCount = 0,
+ writeCount = 0,
+ lastRead = 0.0,
+ lastWrite = 0.0,
+ super(type);
+
+ Map<String, dynamic> get fullValueMap => {
+ 'type': type,
+ 'id': id,
+ 'name': name,
+ 'totalRead': totalRead,
+ 'totalWritten': totalWritten,
+ 'readCount': readCount,
+ 'writeCount': writeCount,
+ 'lastRead': lastRead,
+ 'lastWrite': lastWrite
+ };
+}
+
+class _FileResourceInfo extends _ReadWriteResourceInfo {
+ static const String _type = '_file';
+
+ final file;
+
+ static Map<int, _FileResourceInfo> openFiles =
+ new Map<int, _FileResourceInfo>();
+
+ _FileResourceInfo(this.file) : super(_type) {
+ FileOpened(this);
+ }
+
+ static FileOpened(_FileResourceInfo info) {
+ assert(!openFiles.containsKey(info.id));
+ openFiles[info.id] = info;
+ }
+
+ static FileClosed(_FileResourceInfo info) {
+ assert(openFiles.containsKey(info.id));
+ openFiles.remove(info.id);
+ }
+
+ static Iterable<Map<String, dynamic>> getOpenFilesList() {
+ return new List.from(openFiles.values.map((e) => e.referenceValueMap));
+ }
+
+ static Future<ServiceExtensionResponse> getOpenFiles(function, params) {
+ assert(function == 'ext.dart.io.getOpenFiles');
+ var data = {'type': '_openfiles', 'data': getOpenFilesList()};
+ var jsonValue = json.encode(data);
+ return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+ }
+
+ Map<String, dynamic> getFileInfoMap() {
+ return fullValueMap;
+ }
+
+ static Future<ServiceExtensionResponse> getFileInfoMapByID(function, params) {
+ assert(params.containsKey('id'));
+ var id = int.parse(params['id']);
+ var result =
+ openFiles.containsKey(id) ? openFiles[id].getFileInfoMap() : {};
+ var jsonValue = json.encode(result);
+ return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+ }
+
+ String get name {
+ return '${file.path}';
+ }
+}
+
+class _ProcessResourceInfo extends _IOResourceInfo {
+ static const String _type = '_process';
+ final process;
+ final double startedAt;
+
+ static Map<int, _ProcessResourceInfo> startedProcesses =
+ new Map<int, _ProcessResourceInfo>();
+
+ _ProcessResourceInfo(this.process)
+ : startedAt = _IOResourceInfo.timestamp,
+ super(_type) {
+ ProcessStarted(this);
+ }
+
+ String get name => process._path;
+
+ void stopped() {
+ ProcessStopped(this);
+ }
+
+ Map<String, dynamic> get fullValueMap => {
+ 'type': type,
+ 'id': id,
+ 'name': name,
+ 'pid': process.pid,
+ 'startedAt': startedAt,
+ 'arguments': process._arguments,
+ 'workingDirectory':
+ process._workingDirectory == null ? '.' : process._workingDirectory,
+ };
+
+ static ProcessStarted(_ProcessResourceInfo info) {
+ assert(!startedProcesses.containsKey(info.id));
+ startedProcesses[info.id] = info;
+ }
+
+ static ProcessStopped(_ProcessResourceInfo info) {
+ assert(startedProcesses.containsKey(info.id));
+ startedProcesses.remove(info.id);
+ }
+
+ static Iterable<Map<String, dynamic>> getStartedProcessesList() =>
+ new List.from(startedProcesses.values.map((e) => e.referenceValueMap));
+
+ static Future<ServiceExtensionResponse> getStartedProcesses(
+ String function, Map<String, String> params) {
+ assert(function == 'ext.dart.io.getProcesses');
+ var data = {'type': '_startedprocesses', 'data': getStartedProcessesList()};
+ var jsonValue = json.encode(data);
+ return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+ }
+
+ static Future<ServiceExtensionResponse> getProcessInfoMapById(
+ String function, Map<String, String> params) {
+ var id = int.parse(params['id']);
+ var result = startedProcesses.containsKey(id)
+ ? startedProcesses[id].fullValueMap
+ : {};
+ var jsonValue = json.encode(result);
+ return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+ }
+}
+
+class _SocketResourceInfo extends _ReadWriteResourceInfo {
+ static const String _tcpString = 'TCP';
+ static const String _udpString = 'UDP';
+ static const String _type = '_socket';
+
+ final /*_NativeSocket|*/ socket;
+
+ static Map<int, _SocketResourceInfo> openSockets =
+ new Map<int, _SocketResourceInfo>();
+
+ _SocketResourceInfo(this.socket) : super(_type) {
+ SocketOpened(this);
+ }
+
+ String get name {
+ if (socket.isListening) {
+ return 'listening:${socket.address.host}:${socket.port}';
+ }
+ var remote = '';
+ try {
+ var remoteHost = socket.remoteAddress.host;
+ var remotePort = socket.remotePort;
+ remote = ' -> $remoteHost:$remotePort';
+ } catch (e) {} // ignored if we can't get the information
+ return '${socket.address.host}:${socket.port}$remote';
+ }
+
+ static Iterable<Map<String, dynamic>> getOpenSocketsList() {
+ return new List.from(openSockets.values.map((e) => e.referenceValueMap));
+ }
+
+ Map<String, dynamic> getSocketInfoMap() {
+ var result = fullValueMap;
+ result['socketType'] = socket.isTcp ? _tcpString : _udpString;
+ result['listening'] = socket.isListening;
+ result['host'] = socket.address.host;
+ result['port'] = socket.port;
+ if (!socket.isListening) {
+ try {
+ result['remoteHost'] = socket.remoteAddress.host;
+ result['remotePort'] = socket.remotePort;
+ } catch (e) {
+ // UDP.
+ result['remotePort'] = 'NA';
+ result['remoteHost'] = 'NA';
+ }
+ } else {
+ result['remotePort'] = 'NA';
+ result['remoteHost'] = 'NA';
+ }
+ result['addressType'] = socket.address.type.name;
+ return result;
+ }
+
+ static Future<ServiceExtensionResponse> getSocketInfoMapByID(
+ String function, Map<String, String> params) {
+ assert(params.containsKey('id'));
+ var id = int.parse(params['id']);
+ var result =
+ openSockets.containsKey(id) ? openSockets[id].getSocketInfoMap() : {};
+ var jsonValue = json.encode(result);
+ return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+ }
+
+ static Future<ServiceExtensionResponse> getOpenSockets(function, params) {
+ assert(function == 'ext.dart.io.getOpenSockets');
+ var data = {'type': '_opensockets', 'data': getOpenSocketsList()};
+ var jsonValue = json.encode(data);
+ return new Future.value(new ServiceExtensionResponse.result(jsonValue));
+ }
+
+ static SocketOpened(_SocketResourceInfo info) {
+ assert(!openSockets.containsKey(info.id));
+ openSockets[info.id] = info;
+ }
+
+ static SocketClosed(_SocketResourceInfo info) {
+ assert(openSockets.containsKey(info.id));
+ openSockets.remove(info.id);
+ }
+}
diff --git a/sdk_nnbd/lib/io/io_service.dart b/sdk_nnbd/lib/io/io_service.dart
new file mode 100644
index 0000000..7af382c
--- /dev/null
+++ b/sdk_nnbd/lib/io/io_service.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+class _IOService {
+ // This list must be kept in sync with the list in runtime/bin/io_service.h
+ static const int fileExists = 0;
+ static const int fileCreate = 1;
+ static const int fileDelete = 2;
+ static const int fileRename = 3;
+ static const int fileCopy = 4;
+ static const int fileOpen = 5;
+ static const int fileResolveSymbolicLinks = 6;
+ static const int fileClose = 7;
+ static const int filePosition = 8;
+ static const int fileSetPosition = 9;
+ static const int fileTruncate = 10;
+ static const int fileLength = 11;
+ static const int fileLengthFromPath = 12;
+ static const int fileLastAccessed = 13;
+ static const int fileSetLastAccessed = 14;
+ static const int fileLastModified = 15;
+ static const int fileSetLastModified = 16;
+ static const int fileFlush = 17;
+ static const int fileReadByte = 18;
+ static const int fileWriteByte = 19;
+ static const int fileRead = 20;
+ static const int fileReadInto = 21;
+ static const int fileWriteFrom = 22;
+ static const int fileCreateLink = 23;
+ static const int fileDeleteLink = 24;
+ static const int fileRenameLink = 25;
+ static const int fileLinkTarget = 26;
+ static const int fileType = 27;
+ static const int fileIdentical = 28;
+ static const int fileStat = 29;
+ static const int fileLock = 30;
+ static const int socketLookup = 31;
+ static const int socketListInterfaces = 32;
+ static const int socketReverseLookup = 33;
+ static const int directoryCreate = 34;
+ static const int directoryDelete = 35;
+ static const int directoryExists = 36;
+ static const int directoryCreateTemp = 37;
+ static const int directoryListStart = 38;
+ static const int directoryListNext = 39;
+ static const int directoryListStop = 40;
+ static const int directoryRename = 41;
+ static const int sslProcessFilter = 42;
+
+ external static Future _dispatch(int request, List data);
+}
diff --git a/sdk_nnbd/lib/io/io_sink.dart b/sdk_nnbd/lib/io/io_sink.dart
new file mode 100644
index 0000000..5481265
--- /dev/null
+++ b/sdk_nnbd/lib/io/io_sink.dart
@@ -0,0 +1,316 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * A combined byte and text output.
+ *
+ * An [IOSink] combines a [StreamSink] of bytes with a [StringSink],
+ * and allows easy output of both bytes and text.
+ *
+ * Writing text ([write]) and adding bytes ([add]) may be interleaved freely.
+ *
+ * While a stream is being added using [addStream], any further attempts
+ * to add or write to the [IOSink] will fail until the [addStream] completes.
+ *
+ * It is an error to add data to the [IOSink] after the sink is closed.
+ */
+abstract class IOSink implements StreamSink<List<int>>, StringSink {
+ /**
+ * Create an [IOSink] that outputs to a [target] [StreamConsumer] of bytes.
+ *
+ * Text written to [StreamSink] methods is encoded to bytes using [encoding]
+ * before being output on [target].
+ */
+ factory IOSink(StreamConsumer<List<int>> target, {Encoding encoding: utf8}) =>
+ new _IOSinkImpl(target, encoding);
+
+ /**
+ * The [Encoding] used when writing strings. Depending on the
+ * underlying consumer this property might be mutable.
+ */
+ Encoding encoding;
+
+ /**
+ * Adds byte [data] to the target consumer, ignoring [encoding].
+ *
+ * The [encoding] does not apply to this method, and the `data` list is passed
+ * directly to the target consumer as a stream event.
+ *
+ * This function must not be called when a stream is currently being added
+ * using [addStream].
+ *
+ * This operation is non-blocking. See [flush] or [done] for how to get any
+ * errors generated by this call.
+ *
+ * The data list should not be modified after it has been passed to `add`.
+ */
+ void add(List<int> data);
+
+ /**
+ * Converts [obj] to a String by invoking [Object.toString] and
+ * [add]s the encoding of the result to the target consumer.
+ *
+ * This operation is non-blocking. See [flush] or [done] for how to get any
+ * errors generated by this call.
+ */
+ void write(Object obj);
+
+ /**
+ * Iterates over the given [objects] and [write]s them in sequence.
+ *
+ * If [separator] is provided, a `write` with the `separator` is performed
+ * between any two elements of objects`.
+ *
+ * This operation is non-blocking. See [flush] or [done] for how to get any
+ * errors generated by this call.
+ */
+ void writeAll(Iterable objects, [String separator = ""]);
+
+ /**
+ * Converts [obj] to a String by invoking [Object.toString] and
+ * writes the result to `this`, followed by a newline.
+ *
+ * This operation is non-blocking. See [flush] or [done] for how to get any
+ * errors generated by this call.
+ */
+ void writeln([Object obj = ""]);
+
+ /**
+ * Writes the character of [charCode].
+ *
+ * This method is equivalent to `write(new String.fromCharCode(charCode))`.
+ *
+ * This operation is non-blocking. See [flush] or [done] for how to get any
+ * errors generated by this call.
+ */
+ void writeCharCode(int charCode);
+
+ /**
+ * Passes the error to the target consumer as an error event.
+ *
+ * This function must not be called when a stream is currently being added
+ * using [addStream].
+ *
+ * This operation is non-blocking. See [flush] or [done] for how to get any
+ * errors generated by this call.
+ */
+ void addError(error, [StackTrace stackTrace]);
+
+ /**
+ * Adds all elements of the given [stream] to `this`.
+ *
+ * Returns a [Future] that completes when
+ * all elements of the given [stream] are added to `this`.
+ *
+ * This function must not be called when a stream is currently being added
+ * using this function.
+ */
+ Future addStream(Stream<List<int>> stream);
+
+ /**
+ * Returns a [Future] that completes once all buffered data is accepted by the
+ * underlying [StreamConsumer].
+ *
+ * This method must not be called while an [addStream] is incomplete.
+ *
+ * NOTE: This is not necessarily the same as the data being flushed by the
+ * operating system.
+ */
+ Future flush();
+
+ /**
+ * Close the target consumer.
+ *
+ * NOTE: Writes to the [IOSink] may be buffered, and may not be flushed by
+ * a call to `close()`. To flush all buffered writes, call `flush()` before
+ * calling `close()`.
+ */
+ Future close();
+
+ /**
+ * Get a future that will complete when the consumer closes, or when an
+ * error occurs. This future is identical to the future returned by
+ * [close].
+ */
+ Future get done;
+}
+
+class _StreamSinkImpl<T> implements StreamSink<T> {
+ final StreamConsumer<T> _target;
+ final Completer _doneCompleter = new Completer();
+ StreamController<T> _controllerInstance;
+ Completer _controllerCompleter;
+ bool _isClosed = false;
+ bool _isBound = false;
+ bool _hasError = false;
+
+ _StreamSinkImpl(this._target);
+
+ void add(T data) {
+ if (_isClosed) {
+ throw StateError("StreamSink is closed");
+ }
+ _controller.add(data);
+ }
+
+ void addError(error, [StackTrace stackTrace]) {
+ if (_isClosed) {
+ throw StateError("StreamSink is closed");
+ }
+ _controller.addError(error, stackTrace);
+ }
+
+ Future addStream(Stream<T> stream) {
+ if (_isBound) {
+ throw new StateError("StreamSink is already bound to a stream");
+ }
+ if (_hasError) return done;
+
+ _isBound = true;
+ var future = _controllerCompleter == null
+ ? _target.addStream(stream)
+ : _controllerCompleter.future.then((_) => _target.addStream(stream));
+ _controllerInstance?.close();
+
+ // Wait for any pending events in [_controller] to be dispatched before
+ // adding [stream].
+ return future.whenComplete(() {
+ _isBound = false;
+ });
+ }
+
+ Future flush() {
+ if (_isBound) {
+ throw new StateError("StreamSink is bound to a stream");
+ }
+ if (_controllerInstance == null) return new Future.value(this);
+ // Adding an empty stream-controller will return a future that will complete
+ // when all data is done.
+ _isBound = true;
+ var future = _controllerCompleter.future;
+ _controllerInstance.close();
+ return future.whenComplete(() {
+ _isBound = false;
+ });
+ }
+
+ Future close() {
+ if (_isBound) {
+ throw new StateError("StreamSink is bound to a stream");
+ }
+ if (!_isClosed) {
+ _isClosed = true;
+ if (_controllerInstance != null) {
+ _controllerInstance.close();
+ } else {
+ _closeTarget();
+ }
+ }
+ return done;
+ }
+
+ void _closeTarget() {
+ _target.close().then(_completeDoneValue, onError: _completeDoneError);
+ }
+
+ Future get done => _doneCompleter.future;
+
+ void _completeDoneValue(value) {
+ if (!_doneCompleter.isCompleted) {
+ _doneCompleter.complete(value);
+ }
+ }
+
+ void _completeDoneError(error, StackTrace stackTrace) {
+ if (!_doneCompleter.isCompleted) {
+ _hasError = true;
+ _doneCompleter.completeError(error, stackTrace);
+ }
+ }
+
+ StreamController<T> get _controller {
+ if (_isBound) {
+ throw new StateError("StreamSink is bound to a stream");
+ }
+ if (_isClosed) {
+ throw new StateError("StreamSink is closed");
+ }
+ if (_controllerInstance == null) {
+ _controllerInstance = new StreamController<T>(sync: true);
+ _controllerCompleter = new Completer();
+ _target.addStream(_controller.stream).then((_) {
+ if (_isBound) {
+ // A new stream takes over - forward values to that stream.
+ _controllerCompleter.complete(this);
+ _controllerCompleter = null;
+ _controllerInstance = null;
+ } else {
+ // No new stream, .close was called. Close _target.
+ _closeTarget();
+ }
+ }, onError: (error, stackTrace) {
+ if (_isBound) {
+ // A new stream takes over - forward errors to that stream.
+ _controllerCompleter.completeError(error, stackTrace);
+ _controllerCompleter = null;
+ _controllerInstance = null;
+ } else {
+ // No new stream. No need to close target, as it has already
+ // failed.
+ _completeDoneError(error, stackTrace);
+ }
+ });
+ }
+ return _controllerInstance;
+ }
+}
+
+class _IOSinkImpl extends _StreamSinkImpl<List<int>> implements IOSink {
+ Encoding _encoding;
+ bool _encodingMutable = true;
+
+ _IOSinkImpl(StreamConsumer<List<int>> target, this._encoding) : super(target);
+
+ Encoding get encoding => _encoding;
+
+ void set encoding(Encoding value) {
+ if (!_encodingMutable) {
+ throw new StateError("IOSink encoding is not mutable");
+ }
+ _encoding = value;
+ }
+
+ void write(Object obj) {
+ String string = '$obj';
+ if (string.isEmpty) return;
+ add(_encoding.encode(string));
+ }
+
+ void writeAll(Iterable objects, [String separator = ""]) {
+ Iterator iterator = objects.iterator;
+ if (!iterator.moveNext()) return;
+ if (separator.isEmpty) {
+ do {
+ write(iterator.current);
+ } while (iterator.moveNext());
+ } else {
+ write(iterator.current);
+ while (iterator.moveNext()) {
+ write(separator);
+ write(iterator.current);
+ }
+ }
+ }
+
+ void writeln([Object object = ""]) {
+ write(object);
+ write("\n");
+ }
+
+ void writeCharCode(int charCode) {
+ write(new String.fromCharCode(charCode));
+ }
+}
diff --git a/sdk_nnbd/lib/io/io_sources.gni b/sdk_nnbd/lib/io/io_sources.gni
new file mode 100644
index 0000000..51e283a
--- /dev/null
+++ b/sdk_nnbd/lib/io/io_sources.gni
@@ -0,0 +1,36 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+io_sdk_sources = [
+ "io.dart",
+
+ # The above file needs to be first if additional parts are added to the lib.
+ "bytes_builder.dart",
+ "common.dart",
+ "data_transformer.dart",
+ "directory.dart",
+ "directory_impl.dart",
+ "embedder_config.dart",
+ "eventhandler.dart",
+ "file.dart",
+ "file_impl.dart",
+ "file_system_entity.dart",
+ "io_resource_info.dart",
+ "io_sink.dart",
+ "io_service.dart",
+ "link.dart",
+ "namespace_impl.dart",
+ "overrides.dart",
+ "platform.dart",
+ "platform_impl.dart",
+ "process.dart",
+ "service_object.dart",
+ "secure_server_socket.dart",
+ "secure_socket.dart",
+ "security_context.dart",
+ "socket.dart",
+ "stdio.dart",
+ "string_transformer.dart",
+ "sync_socket.dart",
+]
diff --git a/sdk_nnbd/lib/io/link.dart b/sdk_nnbd/lib/io/link.dart
new file mode 100644
index 0000000..79f8656
--- /dev/null
+++ b/sdk_nnbd/lib/io/link.dart
@@ -0,0 +1,300 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * [Link] objects are references to filesystem links.
+ *
+ */
+@pragma("vm:entry-point")
+abstract class Link implements FileSystemEntity {
+ /**
+ * Creates a Link object.
+ */
+ @pragma("vm:entry-point")
+ factory Link(String path) {
+ final IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return new _Link(path);
+ }
+ return overrides.createLink(path);
+ }
+
+ @pragma("vm:entry-point")
+ factory Link.fromRawPath(Uint8List rawPath) {
+ // TODO(bkonyi): handle overrides
+ return new _Link.fromRawPath(rawPath);
+ }
+
+ /**
+ * Creates a [Link] object.
+ *
+ * If [path] is a relative path, it will be interpreted relative to the
+ * current working directory (see [Directory.current]), when used.
+ *
+ * If [path] is an absolute path, it will be immune to changes to the
+ * current working directory.
+ */
+ factory Link.fromUri(Uri uri) => new Link(uri.toFilePath());
+
+ /**
+ * Creates a symbolic link. Returns a [:Future<Link>:] that completes with
+ * the link when it has been created. If the link exists,
+ * the future will complete with an error.
+ *
+ * If [recursive] is false, the default, the link is created
+ * only if all directories in its path exist.
+ * If [recursive] is true, all non-existing path
+ * components are created. The directories in the path of [target] are
+ * not affected, unless they are also in [path].
+ *
+ * On the Windows platform, this call will create a true symbolic link
+ * instead of a Junction. In order to create a symbolic link on Windows, Dart
+ * must be run in Administrator mode or the system must have Developer Mode
+ * enabled, otherwise a [FileSystemException] will be raised with
+ * `ERROR_PRIVILEGE_NOT_HELD` set as the errno when this call is made.
+ *
+ * On other platforms, the posix symlink() call is used to make a symbolic
+ * link containing the string [target]. If [target] is a relative path,
+ * it will be interpreted relative to the directory containing the link.
+ */
+ Future<Link> create(String target, {bool recursive: false});
+
+ /**
+ * Synchronously create the link. Calling [createSync] on an existing link
+ * will throw an exception.
+ *
+ * If [recursive] is false, the default, the link is created only if all
+ * directories in its path exist. If [recursive] is true, all
+ * non-existing path components are created. The directories in
+ * the path of [target] are not affected, unless they are also in [path].
+ *
+ * On the Windows platform, this call will create a true symbolic link
+ * instead of a Junction. In order to create a symbolic link on Windows, Dart
+ * must be run in Administrator mode or the system must have Developer Mode
+ * enabled, otherwise a [FileSystemException] will be raised with
+ * `ERROR_PRIVILEGE_NOT_HELD` set as the errno when this call is made.
+ *
+ * On other platforms, the posix symlink() call is used to make a symbolic
+ * link containing the string [target]. If [target] is a relative path,
+ * it will be interpreted relative to the directory containing the link.
+ */
+ void createSync(String target, {bool recursive: false});
+
+ /**
+ * Synchronously updates the link. Calling [updateSync] on a non-existing link
+ * will throw an exception.
+ */
+ void updateSync(String target);
+
+ /**
+ * Updates the link. Returns a [:Future<Link>:] that completes with the
+ * link when it has been updated. Calling [update] on a non-existing link
+ * will complete its returned future with an exception.
+ */
+ Future<Link> update(String target);
+
+ Future<String> resolveSymbolicLinks();
+
+ String resolveSymbolicLinksSync();
+
+ /**
+ * Renames this link. Returns a `Future<Link>` that completes
+ * with a [Link] instance for the renamed link.
+ *
+ * If [newPath] identifies an existing link, that link is
+ * replaced. If [newPath] identifies an existing file or directory,
+ * the operation fails and the future completes with an exception.
+ */
+ Future<Link> rename(String newPath);
+
+ /**
+ * Synchronously renames this link. Returns a [Link]
+ * instance for the renamed link.
+ *
+ * If [newPath] identifies an existing link, that link is
+ * replaced. If [newPath] identifies an existing file or directory
+ * the operation fails and an exception is thrown.
+ */
+ Link renameSync(String newPath);
+
+ /**
+ * Returns a [Link] instance whose path is the absolute path to [this].
+ *
+ * The absolute path is computed by prefixing
+ * a relative path with the current working directory, and returning
+ * an absolute path unchanged.
+ */
+ Link get absolute;
+
+ /**
+ * Gets the target of the link. Returns a future that completes with
+ * the path to the target.
+ *
+ * If the returned target is a relative path, it is relative to the
+ * directory containing the link.
+ *
+ * If the link does not exist, or is not a link, the future completes with
+ * a FileSystemException.
+ */
+ Future<String> target();
+
+ /**
+ * Synchronously gets the target of the link. Returns the path to the target.
+ *
+ * If the returned target is a relative path, it is relative to the
+ * directory containing the link.
+ *
+ * If the link does not exist, or is not a link, throws a FileSystemException.
+ */
+ String targetSync();
+}
+
+class _Link extends FileSystemEntity implements Link {
+ String _path;
+ Uint8List _rawPath;
+
+ _Link(String path) {
+ ArgumentError.checkNotNull(path, 'path');
+ _path = path;
+ _rawPath = FileSystemEntity._toUtf8Array(path);
+ }
+
+ _Link.fromRawPath(Uint8List rawPath) {
+ _rawPath = FileSystemEntity._toNullTerminatedUtf8Array(rawPath);
+ _path = FileSystemEntity._toStringFromUtf8Array(rawPath);
+ }
+
+ String get path => _path;
+
+ String toString() => "Link: '$path'";
+
+ Future<bool> exists() => FileSystemEntity._isLinkRaw(_rawPath);
+
+ bool existsSync() => FileSystemEntity._isLinkRawSync(_rawPath);
+
+ Link get absolute => new Link.fromRawPath(_rawAbsolutePath);
+
+ Future<Link> create(String target, {bool recursive: false}) {
+ var result =
+ recursive ? parent.create(recursive: true) : new Future.value(null);
+ return result
+ .then((_) => _File._dispatchWithNamespace(
+ _IOService.fileCreateLink, [null, _rawPath, target]))
+ .then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(
+ response, "Cannot create link to target '$target'", path);
+ }
+ return this;
+ });
+ }
+
+ void createSync(String target, {bool recursive: false}) {
+ if (recursive) {
+ parent.createSync(recursive: true);
+ }
+ var result = _File._createLink(_Namespace._namespace, _rawPath, target);
+ throwIfError(result, "Cannot create link", path);
+ }
+
+ void updateSync(String target) {
+ // TODO(12414): Replace with atomic update, where supported by platform.
+ // Atomically changing a link can be done by creating the new link, with
+ // a different name, and using the rename() posix call to move it to
+ // the old name atomically.
+ deleteSync();
+ createSync(target);
+ }
+
+ Future<Link> update(String target) {
+ // TODO(12414): Replace with atomic update, where supported by platform.
+ // Atomically changing a link can be done by creating the new link, with
+ // a different name, and using the rename() posix call to move it to
+ // the old name atomically.
+ return delete().then<Link>((_) => create(target));
+ }
+
+ Future<Link> _delete({bool recursive: false}) {
+ if (recursive) {
+ return new Directory.fromRawPath(_rawPath)
+ .delete(recursive: true)
+ .then((_) => this);
+ }
+ return _File._dispatchWithNamespace(
+ _IOService.fileDeleteLink, [null, _rawPath]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(response, "Cannot delete link", path);
+ }
+ return this;
+ });
+ }
+
+ void _deleteSync({bool recursive: false}) {
+ if (recursive) {
+ return new Directory.fromRawPath(_rawPath).deleteSync(recursive: true);
+ }
+ var result = _File._deleteLinkNative(_Namespace._namespace, _rawPath);
+ throwIfError(result, "Cannot delete link", path);
+ }
+
+ Future<Link> rename(String newPath) {
+ return _File._dispatchWithNamespace(
+ _IOService.fileRenameLink, [null, _rawPath, newPath]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(
+ response, "Cannot rename link to '$newPath'", path);
+ }
+ return new Link(newPath);
+ });
+ }
+
+ Link renameSync(String newPath) {
+ var result = _File._renameLink(_Namespace._namespace, _rawPath, newPath);
+ throwIfError(result, "Cannot rename link '$path' to '$newPath'");
+ return new Link(newPath);
+ }
+
+ Future<String> target() {
+ return _File._dispatchWithNamespace(
+ _IOService.fileLinkTarget, [null, _rawPath]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(
+ response, "Cannot get target of link", path);
+ }
+ return response;
+ });
+ }
+
+ String targetSync() {
+ var result = _File._linkTarget(_Namespace._namespace, _rawPath);
+ throwIfError(result, "Cannot read link", path);
+ return result;
+ }
+
+ static throwIfError(Object result, String msg, [String path = ""]) {
+ if (result is OSError) {
+ throw new FileSystemException(msg, path, result);
+ }
+ }
+
+ bool _isErrorResponse(response) {
+ return response is List && response[0] != _successResponse;
+ }
+
+ _exceptionFromResponse(response, String message, String path) {
+ assert(_isErrorResponse(response));
+ switch (response[_errorResponseErrorType]) {
+ case _illegalArgumentResponse:
+ return new ArgumentError();
+ case _osErrorResponse:
+ var err = new OSError(response[_osErrorResponseMessage],
+ response[_osErrorResponseErrorCode]);
+ return new FileSystemException(message, path, err);
+ default:
+ return new Exception("Unknown error");
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/io/namespace_impl.dart b/sdk_nnbd/lib/io/namespace_impl.dart
new file mode 100644
index 0000000..88987b6
--- /dev/null
+++ b/sdk_nnbd/lib/io/namespace_impl.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+// Each Isolate may run in a different "namespace", which provides the scope in
+// which file paths are resolved.
+abstract class _Namespace {
+ // This getter does not increase the reference count on the underlying native
+ // object. It cannot be passed in a dispatch message to the IOService thread.
+ external static _Namespace get _namespace;
+
+ // This getter does increase the reference count on the underlying native
+ // object. It must be passed in a dispatch message to the IOService thread.
+ external static int get _namespacePointer;
+
+ // This sets up the Isolate's namespace. It should be set up by the embedder.
+ // If it is not set up by the embedder, relative paths will be resolved
+ // relative to the process's current working directory and absolute paths will
+ // be left relative to the file system root.
+ @pragma("vm:entry-point")
+ external static void _setupNamespace(var namespace);
+}
diff --git a/sdk_nnbd/lib/io/overrides.dart b/sdk_nnbd/lib/io/overrides.dart
new file mode 100644
index 0000000..1a71881
--- /dev/null
+++ b/sdk_nnbd/lib/io/overrides.dart
@@ -0,0 +1,481 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+final _ioOverridesToken = new Object();
+
+const _asyncRunZoned = runZoned;
+
+/// This class facilitates overriding various APIs of dart:io with mock
+/// implementations.
+///
+/// This abstract base class should be extended with overrides for the
+/// operations needed to construct mocks. The implementations in this base class
+/// default to the actual dart:io implementation. For example:
+///
+/// ```
+/// class MyDirectory implements Directory {
+/// ...
+/// // An implementation of the Directory interface
+/// ...
+/// }
+///
+/// main() {
+/// IOOverrides.runZoned(() {
+/// ...
+/// // Operations will use MyDirectory instead of dart:io's Directory
+/// // implementation whenever Directory is used.
+/// ...
+/// }, createDirectory: (String path) => new MyDirectory(path));
+/// }
+/// ```
+abstract class IOOverrides {
+ static IOOverrides _global;
+
+ static IOOverrides get current {
+ return Zone.current[_ioOverridesToken] ?? _global;
+ }
+
+ /// The [IOOverrides] to use in the root [Zone].
+ ///
+ /// These are the [IOOverrides] that will be used in the root Zone, and in
+ /// Zone's that do not set [IOOverrides] and whose ancestors up to the root
+ /// Zone do not set [IOOverrides].
+ static set global(IOOverrides overrides) {
+ _global = overrides;
+ }
+
+ /// Runs [body] in a fresh [Zone] using the provided overrides.
+ ///
+ /// See the documentation on the corresponding methods of IOOverrides for
+ /// information about what the optional arguments do.
+ static R runZoned<R>(R body(),
+ {
+ // Directory
+ Directory Function(String) createDirectory,
+ Directory Function() getCurrentDirectory,
+ void Function(String) setCurrentDirectory,
+ Directory Function() getSystemTempDirectory,
+
+ // File
+ File Function(String) createFile,
+
+ // FileStat
+ Future<FileStat> Function(String) stat,
+ FileStat Function(String) statSync,
+
+ // FileSystemEntity
+ Future<bool> Function(String, String) fseIdentical,
+ bool Function(String, String) fseIdenticalSync,
+ Future<FileSystemEntityType> Function(String, bool) fseGetType,
+ FileSystemEntityType Function(String, bool) fseGetTypeSync,
+
+ // _FileSystemWatcher
+ Stream<FileSystemEvent> Function(String, int, bool) fsWatch,
+ bool Function() fsWatchIsSupported,
+
+ // Link
+ Link Function(String) createLink,
+
+ // Socket
+ Future<Socket> Function(dynamic, int,
+ {dynamic sourceAddress, Duration timeout})
+ socketConnect,
+ Future<ConnectionTask<Socket>> Function(dynamic, int,
+ {dynamic sourceAddress})
+ socketStartConnect,
+
+ // Optional Zone parameters
+ ZoneSpecification zoneSpecification,
+ Function onError}) {
+ IOOverrides overrides = new _IOOverridesScope(
+ // Directory
+ createDirectory,
+ getCurrentDirectory,
+ setCurrentDirectory,
+ getSystemTempDirectory,
+
+ // File
+ createFile,
+
+ // FileStat
+ stat,
+ statSync,
+
+ // FileSystemEntity
+ fseIdentical,
+ fseIdenticalSync,
+ fseGetType,
+ fseGetTypeSync,
+
+ // _FileSystemWatcher
+ fsWatch,
+ fsWatchIsSupported,
+
+ // Link
+ createLink,
+
+ // Socket
+ socketConnect,
+ socketStartConnect,
+ );
+ return _asyncRunZoned<R>(body,
+ zoneValues: {_ioOverridesToken: overrides},
+ zoneSpecification: zoneSpecification,
+ onError: onError);
+ }
+
+ /// Runs [body] in a fresh [Zone] using the overrides found in [overrides].
+ ///
+ /// Note that [overrides] should be an instance of a class that extends
+ /// [IOOverrides].
+ static R runWithIOOverrides<R>(R body(), IOOverrides overrides,
+ {ZoneSpecification zoneSpecification, Function onError}) {
+ return _asyncRunZoned<R>(body,
+ zoneValues: {_ioOverridesToken: overrides},
+ zoneSpecification: zoneSpecification,
+ onError: onError);
+ }
+
+ // Directory
+
+ /// Creates a new [Directory] object for the given [path].
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `new Directory()` and `new Directory.fromUri()`.
+ Directory createDirectory(String path) => new _Directory(path);
+
+ /// Returns the current working directory.
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// the static getter `Directory.current`
+ Directory getCurrentDirectory() => _Directory.current;
+
+ /// Sets the current working directory to be [path].
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// the setter `Directory.current`.
+ void setCurrentDirectory(String path) {
+ _Directory.current = path;
+ }
+
+ /// Returns the system temporary directory.
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `Directory.systemTemp`.
+ Directory getSystemTempDirectory() => _Directory.systemTemp;
+
+ // File
+
+ /// Creates a new [File] object for the given [path].
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `new File()` and `new File.fromUri()`.
+ File createFile(String path) => new _File(path);
+
+ // FileStat
+
+ /// Asynchronously returns [FileStat] information for [path].
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `FileStat.stat()`.
+ Future<FileStat> stat(String path) {
+ return FileStat._stat(path);
+ }
+
+ /// Returns [FileStat] information for [path].
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `FileStat.statSync()`.
+ FileStat statSync(String path) {
+ return FileStat._statSyncInternal(path);
+ }
+
+ // FileSystemEntity
+
+ /// Asynchronously returns `true` if [path1] and [path2] are paths to the
+ /// same file system object.
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `FileSystemEntity.identical`.
+ Future<bool> fseIdentical(String path1, String path2) {
+ return FileSystemEntity._identical(path1, path2);
+ }
+
+ /// Returns `true` if [path1] and [path2] are paths to the
+ /// same file system object.
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `FileSystemEntity.identicalSync`.
+ bool fseIdenticalSync(String path1, String path2) {
+ return FileSystemEntity._identicalSync(path1, path2);
+ }
+
+ /// Asynchronously returns the [FileSystemEntityType] for [path].
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `FileSystemEntity.type`.
+ Future<FileSystemEntityType> fseGetType(String path, bool followLinks) {
+ return FileSystemEntity._getTypeRequest(utf8.encode(path), followLinks);
+ }
+
+ /// Returns the [FileSystemEntityType] for [path].
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `FileSystemEntity.typeSync`.
+ FileSystemEntityType fseGetTypeSync(String path, bool followLinks) {
+ return FileSystemEntity._getTypeSyncHelper(utf8.encode(path), followLinks);
+ }
+
+ // _FileSystemWatcher
+
+ /// Returns a [Stream] of [FileSystemEvent]s.
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `FileSystemEntity.watch()`.
+ Stream<FileSystemEvent> fsWatch(String path, int events, bool recursive) {
+ return _FileSystemWatcher._watch(path, events, recursive);
+ }
+
+ /// Returns `true` when [FileSystemEntity.watch] is supported.
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `FileSystemEntity.isWatchSupported`.
+ bool fsWatchIsSupported() => _FileSystemWatcher.isSupported;
+
+ // Link
+
+ /// Returns a new [Link] object for the given [path].
+ ///
+ /// When this override is installed, this function overrides the behavior of
+ /// `new Link()` and `new Link.fromUri()`.
+ Link createLink(String path) => new _Link(path);
+
+ // Socket
+
+ /// Asynchronously returns a [Socket] connected to the given host and port.
+ ///
+ /// When this override is installed, this functions overrides the behavior of
+ /// `Socket.connect(...)`.
+ Future<Socket> socketConnect(host, int port,
+ {sourceAddress, Duration timeout}) {
+ return Socket._connect(host, port,
+ sourceAddress: sourceAddress, timeout: timeout);
+ }
+
+ /// Asynchronously returns a [ConnectionTask] that connects to the given host
+ /// and port when successful.
+ ///
+ /// When this override is installed, this functions overrides the behavior of
+ /// `Socket.startConnect(...)`.
+ Future<ConnectionTask<Socket>> socketStartConnect(host, int port,
+ {sourceAddress}) {
+ return Socket._startConnect(host, port, sourceAddress: sourceAddress);
+ }
+}
+
+class _IOOverridesScope extends IOOverrides {
+ final IOOverrides _previous = IOOverrides.current;
+
+ // Directory
+ Directory Function(String) _createDirectory;
+ Directory Function() _getCurrentDirectory;
+ void Function(String) _setCurrentDirectory;
+ Directory Function() _getSystemTempDirectory;
+
+ // File
+ File Function(String) _createFile;
+
+ // FileStat
+ Future<FileStat> Function(String) _stat;
+ FileStat Function(String) _statSync;
+
+ // FileSystemEntity
+ Future<bool> Function(String, String) _fseIdentical;
+ bool Function(String, String) _fseIdenticalSync;
+ Future<FileSystemEntityType> Function(String, bool) _fseGetType;
+ FileSystemEntityType Function(String, bool) _fseGetTypeSync;
+
+ // _FileSystemWatcher
+ Stream<FileSystemEvent> Function(String, int, bool) _fsWatch;
+ bool Function() _fsWatchIsSupported;
+
+ // Link
+ Link Function(String) _createLink;
+
+ // Socket
+ Future<Socket> Function(dynamic, int,
+ {dynamic sourceAddress, Duration timeout}) _socketConnect;
+ Future<ConnectionTask<Socket>> Function(dynamic, int, {dynamic sourceAddress})
+ _socketStartConnect;
+
+ _IOOverridesScope(
+ // Directory
+ this._createDirectory,
+ this._getCurrentDirectory,
+ this._setCurrentDirectory,
+ this._getSystemTempDirectory,
+
+ // File
+ this._createFile,
+
+ // FileStat
+ this._stat,
+ this._statSync,
+
+ // FileSystemEntity
+ this._fseIdentical,
+ this._fseIdenticalSync,
+ this._fseGetType,
+ this._fseGetTypeSync,
+
+ // _FileSystemWatcher
+ this._fsWatch,
+ this._fsWatchIsSupported,
+
+ // Link
+ this._createLink,
+
+ // Socket
+ this._socketConnect,
+ this._socketStartConnect,
+ );
+
+ // Directory
+ @override
+ Directory createDirectory(String path) {
+ if (_createDirectory != null) return _createDirectory(path);
+ if (_previous != null) return _previous.createDirectory(path);
+ return super.createDirectory(path);
+ }
+
+ @override
+ Directory getCurrentDirectory() {
+ if (_getCurrentDirectory != null) return _getCurrentDirectory();
+ if (_previous != null) return _previous.getCurrentDirectory();
+ return super.getCurrentDirectory();
+ }
+
+ @override
+ void setCurrentDirectory(String path) {
+ if (_setCurrentDirectory != null)
+ _setCurrentDirectory(path);
+ else if (_previous != null)
+ _previous.setCurrentDirectory(path);
+ else
+ super.setCurrentDirectory(path);
+ }
+
+ @override
+ Directory getSystemTempDirectory() {
+ if (_getSystemTempDirectory != null) return _getSystemTempDirectory();
+ if (_previous != null) return _previous.getSystemTempDirectory();
+ return super.getSystemTempDirectory();
+ }
+
+ // File
+ @override
+ File createFile(String path) {
+ if (_createFile != null) return _createFile(path);
+ if (_previous != null) return _previous.createFile(path);
+ return super.createFile(path);
+ }
+
+ // FileStat
+ @override
+ Future<FileStat> stat(String path) {
+ if (_stat != null) return _stat(path);
+ if (_previous != null) return _previous.stat(path);
+ return super.stat(path);
+ }
+
+ @override
+ FileStat statSync(String path) {
+ if (_stat != null) return _statSync(path);
+ if (_previous != null) return _previous.statSync(path);
+ return super.statSync(path);
+ }
+
+ // FileSystemEntity
+ @override
+ Future<bool> fseIdentical(String path1, String path2) {
+ if (_fseIdentical != null) return _fseIdentical(path1, path2);
+ if (_previous != null) return _previous.fseIdentical(path1, path2);
+ return super.fseIdentical(path1, path2);
+ }
+
+ @override
+ bool fseIdenticalSync(String path1, String path2) {
+ if (_fseIdenticalSync != null) return _fseIdenticalSync(path1, path2);
+ if (_previous != null) return _previous.fseIdenticalSync(path1, path2);
+ return super.fseIdenticalSync(path1, path2);
+ }
+
+ @override
+ Future<FileSystemEntityType> fseGetType(String path, bool followLinks) {
+ if (_fseGetType != null) return _fseGetType(path, followLinks);
+ if (_previous != null) return _previous.fseGetType(path, followLinks);
+ return super.fseGetType(path, followLinks);
+ }
+
+ @override
+ FileSystemEntityType fseGetTypeSync(String path, bool followLinks) {
+ if (_fseGetTypeSync != null) return _fseGetTypeSync(path, followLinks);
+ if (_previous != null) return _previous.fseGetTypeSync(path, followLinks);
+ return super.fseGetTypeSync(path, followLinks);
+ }
+
+ // _FileSystemWatcher
+ @override
+ Stream<FileSystemEvent> fsWatch(String path, int events, bool recursive) {
+ if (_fsWatch != null) return _fsWatch(path, events, recursive);
+ if (_previous != null) return _previous.fsWatch(path, events, recursive);
+ return super.fsWatch(path, events, recursive);
+ }
+
+ @override
+ bool fsWatchIsSupported() {
+ if (_fsWatchIsSupported != null) return _fsWatchIsSupported();
+ if (_previous != null) return _previous.fsWatchIsSupported();
+ return super.fsWatchIsSupported();
+ }
+
+ // Link
+ @override
+ Link createLink(String path) {
+ if (_createLink != null) return _createLink(path);
+ if (_previous != null) return _previous.createLink(path);
+ return super.createLink(path);
+ }
+
+ // Socket
+ @override
+ Future<Socket> socketConnect(host, int port,
+ {sourceAddress, Duration timeout}) {
+ if (_socketConnect != null) {
+ return _socketConnect(host, port,
+ sourceAddress: sourceAddress, timeout: timeout);
+ }
+ if (_previous != null) {
+ return _previous.socketConnect(host, port,
+ sourceAddress: sourceAddress, timeout: timeout);
+ }
+ return super.socketConnect(host, port,
+ sourceAddress: sourceAddress, timeout: timeout);
+ }
+
+ @override
+ Future<ConnectionTask<Socket>> socketStartConnect(host, int port,
+ {sourceAddress}) {
+ if (_socketStartConnect != null) {
+ return _socketStartConnect(host, port, sourceAddress: sourceAddress);
+ }
+ if (_previous != null) {
+ return _previous.socketStartConnect(host, port,
+ sourceAddress: sourceAddress);
+ }
+ return super.socketStartConnect(host, port, sourceAddress: sourceAddress);
+ }
+}
diff --git a/sdk_nnbd/lib/io/platform.dart b/sdk_nnbd/lib/io/platform.dart
new file mode 100644
index 0000000..f7c9053
--- /dev/null
+++ b/sdk_nnbd/lib/io/platform.dart
@@ -0,0 +1,232 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * Information about the environment in which the current program is running.
+ *
+ * Platform provides information such as the operating system,
+ * the hostname of the computer, the value of environment variables,
+ * the path to the running program,
+ * and so on.
+ *
+ * ## Get the URI to the current Dart script
+ *
+ * Use the [script] getter to get the URI to the currently running
+ * Dart script.
+ *
+ * import 'dart:io' show Platform;
+ *
+ * void main() {
+ * // Get the URI of the script being run.
+ * var uri = Platform.script;
+ * // Convert the URI to a path.
+ * var path = uri.toFilePath();
+ * }
+ *
+ * ## Get the value of an environment variable
+ *
+ * The [environment] getter returns a the names and values of environment
+ * variables in a [Map] that contains key-value pairs of strings. The Map is
+ * unmodifiable. This sample shows how to get the value of the `PATH`
+ * environment variable.
+ *
+ * import 'dart:io' show Platform;
+ *
+ * void main() {
+ * Map<String, String> envVars = Platform.environment;
+ * print(envVars['PATH']);
+ * }
+ *
+ * ## Determine the OS
+ *
+ * You can get the name of the operating system as a string with the
+ * [operatingSystem] getter. You can also use one of the static boolean
+ * getters: [isMacOS], [isLinux], and [isWindows].
+ *
+ * import 'dart:io' show Platform, stdout;
+ *
+ * void main() {
+ * // Get the operating system as a string.
+ * String os = Platform.operatingSystem;
+ * // Or, use a predicate getter.
+ * if (Platform.isMacOS) {
+ * print('is a Mac');
+ * } else {
+ * print('is not a Mac');
+ * }
+ * }
+ *
+ * ## Other resources
+ *
+ * [Dart by Example](https://www.dartlang.org/dart-by-example/#dart-io-and-command-line-apps)
+ * provides additional task-oriented code samples that show how to use
+ * various API from the [dart:io] library.
+ */
+class Platform {
+ static final _numberOfProcessors = _Platform.numberOfProcessors;
+ static final _pathSeparator = _Platform.pathSeparator;
+ static final _operatingSystem = _Platform.operatingSystem;
+ static final _operatingSystemVersion = _Platform.operatingSystemVersion;
+ static final _localHostname = _Platform.localHostname;
+ static final _version = _Platform.version;
+
+ /**
+ * The number of individual execution units of the machine.
+ */
+ static int get numberOfProcessors => _numberOfProcessors;
+
+ /**
+ * The path separator used by the operating system to separate
+ * components in file paths.
+ */
+ static String get pathSeparator => _pathSeparator;
+
+ /**
+ * Get the name of the current locale.
+ */
+ static String get localeName => _Platform.localeName();
+
+ /**
+ * A string representing the operating system or platform.
+ */
+ static String get operatingSystem => _operatingSystem;
+
+ /**
+ * A string representing the version of the operating system or platform.
+ */
+ static String get operatingSystemVersion => _operatingSystemVersion;
+
+ /**
+ * The local hostname for the system.
+ */
+ static String get localHostname => _localHostname;
+
+ /**
+ * Whether the operating system is a version of
+ * [Linux](https://en.wikipedia.org/wiki/Linux).
+ *
+ * This value is `false` if the operating system is a specialized
+ * version of Linux that identifies itself by a different name,
+ * for example Android (see [isAndroid]).
+ */
+ static final bool isLinux = (_operatingSystem == "linux");
+
+ /**
+ * Whether the operating system is a version of
+ * [macOS](https://en.wikipedia.org/wiki/MacOS).
+ */
+ static final bool isMacOS = (_operatingSystem == "macos");
+
+ /**
+ * Whether the operating system is a version of
+ * [Microsoft Windows](https://en.wikipedia.org/wiki/Microsoft_Windows).
+ */
+ static final bool isWindows = (_operatingSystem == "windows");
+
+ /**
+ * Whether the operating system is a version of
+ * [Android](https://en.wikipedia.org/wiki/Android_%28operating_system%29).
+ */
+ static final bool isAndroid = (_operatingSystem == "android");
+
+ /**
+ * Whether the operating system is a version of
+ * [iOS](https://en.wikipedia.org/wiki/IOS).
+ */
+ static final bool isIOS = (_operatingSystem == "ios");
+
+ /**
+ * Whether the operating system is a version of
+ * [Fuchsia](https://en.wikipedia.org/wiki/Google_Fuchsia).
+ */
+ static final bool isFuchsia = (_operatingSystem == "fuchsia");
+
+ /**
+ * The environment for this process as a map from string key to string value.
+ *
+ * The map is unmodifiable,
+ * and its content is retrieved from the operating system on its first use.
+ *
+ * Environment variables on Windows are case-insensitive,
+ * so on Windows the map is case-insensitive and will convert
+ * all keys to upper case.
+ * On other platforms, keys can be distinguished by case.
+ */
+ static Map<String, String> get environment => _Platform.environment;
+
+ /**
+ * The path of the executable used to run the script in this isolate.
+ *
+ * The literal path used to identify the script.
+ * This path might be relative or just be a name from which the executable
+ * was found by searching the system path.
+ *
+ * Use [resolvedExecutable] to get an absolute path to the executable.
+ */
+ static String get executable => _Platform.executable;
+
+ /**
+ * The path of the executable used to run the script in this
+ * isolate after it has been resolved by the OS.
+ *
+ * This is the absolute path, with all symlinks resolved, to the
+ * executable used to run the script.
+ */
+ static String get resolvedExecutable => _Platform.resolvedExecutable;
+
+ /**
+ * The absolute URI of the script being run in this isolate.
+ *
+ * If the script argument on the command line is relative,
+ * it is resolved to an absolute URI before fetching the script, and
+ * that absolute URI is returned.
+ *
+ * URI resolution only does string manipulation on the script path, and this
+ * may be different from the file system's path resolution behavior. For
+ * example, a symbolic link immediately followed by '..' will not be
+ * looked up.
+ *
+ * If the executable environment does not support [script],
+ * the URI is empty.
+ */
+ static Uri get script => _Platform.script;
+
+ /**
+ * The flags passed to the executable used to run the script in this isolate.
+ *
+ * These are the command-line flags to the executable that precedes
+ * the script name.
+ * Provides a new list every time the value is read.
+ */
+ static List<String> get executableArguments => _Platform.executableArguments;
+
+ /**
+ * This returns `null`, as `packages/` directories are no longer supported.
+ *
+ */
+ @Deprecated('packages/ directory resolution is not supported in Dart 2')
+ static String get packageRoot => null; // TODO(mfairhurst): remove this
+
+ /**
+ * The `--packages` flag passed to the executable used to run the script
+ * in this isolate.
+ *
+ * If present, it specifies a file describing how Dart packages are looked up.
+ *
+ * Is `null` if there is no `--packages` flag.
+ */
+ static String get packageConfig => _Platform.packageConfig;
+
+ /**
+ * The version of the current Dart runtime.
+ *
+ * The value is a [semantic versioning](http://semver.org)
+ * string representing the version of the current Dart runtime,
+ * possibly followed by whitespace and other version and
+ * build details.
+ */
+ static String get version => _version;
+}
diff --git a/sdk_nnbd/lib/io/platform_impl.dart b/sdk_nnbd/lib/io/platform_impl.dart
new file mode 100644
index 0000000..a350119
--- /dev/null
+++ b/sdk_nnbd/lib/io/platform_impl.dart
@@ -0,0 +1,178 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+class _Platform {
+ external static int _numberOfProcessors();
+ external static String _pathSeparator();
+ external static String _operatingSystem();
+ external static _operatingSystemVersion();
+ external static _localHostname();
+ external static _executable();
+ external static _resolvedExecutable();
+
+ /**
+ * Retrieve the entries of the process environment.
+ *
+ * The result is an [Iterable] of strings, where each string represents
+ * an environment entry.
+ *
+ * Environment entries should be strings containing
+ * a non-empty name and a value separated by a '=' character.
+ * The name does not contain a '=' character,
+ * so the name is everything up to the first '=' character.
+ * Values are everything after the first '=' character.
+ * A value may contain further '=' characters, and it may be empty.
+ *
+ * Returns an [OSError] if retrieving the environment fails.
+ */
+ external static _environment();
+ external static List<String> _executableArguments();
+ external static String _packageRoot(); // TODO(mfairhurst): remove this
+ external static String _packageConfig();
+ external static String _version();
+ external static String _localeName();
+ external static Uri _script();
+
+ static String executable = _executable();
+ static String resolvedExecutable = _resolvedExecutable();
+ static String packageRoot; // TODO(mfairhurst): remove this
+ static String packageConfig = _packageConfig();
+
+ @pragma("vm:entry-point")
+ static String Function() _localeClosure;
+ static String localeName() {
+ final result = (_localeClosure == null) ? _localeName() : _localeClosure();
+ if (result is OSError) {
+ throw result;
+ }
+ return result;
+ }
+
+ // Cache the OS environment. This can be an OSError instance if
+ // retrieving the environment failed.
+ static var /*OSError|Map<String,String>*/ _environmentCache;
+
+ static int get numberOfProcessors => _numberOfProcessors();
+ static String get pathSeparator => _pathSeparator();
+ static String get operatingSystem => _operatingSystem();
+ static Uri get script => _script();
+
+ static String _cachedOSVersion;
+ static String get operatingSystemVersion {
+ if (_cachedOSVersion == null) {
+ var result = _operatingSystemVersion();
+ if (result is OSError) {
+ throw result;
+ }
+ _cachedOSVersion = result;
+ }
+ return _cachedOSVersion;
+ }
+
+ static String get localHostname {
+ var result = _localHostname();
+ if (result is OSError) {
+ throw result;
+ }
+ return result;
+ }
+
+ static List<String> get executableArguments => _executableArguments();
+
+ static Map<String, String> get environment {
+ if (_environmentCache == null) {
+ var env = _environment();
+ if (env is! OSError) {
+ var isWindows = operatingSystem == 'windows';
+ var result = isWindows
+ ? new _CaseInsensitiveStringMap<String>()
+ : new Map<String, String>();
+ for (var str in env) {
+ if (str == null) {
+ continue;
+ }
+ // The Strings returned by [_environment()] are expected to be
+ // valid environment entries, but exceptions have been seen
+ // (e.g., an entry of just '=' has been seen on OS/X).
+ // Invalid entries (lines without a '=' or with an empty name)
+ // are discarded.
+ var equalsIndex = str.indexOf('=');
+ if (equalsIndex > 0) {
+ result[str.substring(0, equalsIndex)] =
+ str.substring(equalsIndex + 1);
+ }
+ }
+ _environmentCache = new UnmodifiableMapView<String, String>(result);
+ } else {
+ _environmentCache = env;
+ }
+ }
+
+ if (_environmentCache is OSError) {
+ throw _environmentCache;
+ } else {
+ return _environmentCache;
+ }
+ }
+
+ static String get version => _version();
+}
+
+// Environment variables are case-insensitive on Windows. In order
+// to reflect that we use a case-insensitive string map on Windows.
+class _CaseInsensitiveStringMap<V> extends MapBase<String, V> {
+ final Map<String, V> _map = new Map<String, V>();
+
+ bool containsKey(Object key) =>
+ key is String && _map.containsKey(key.toUpperCase());
+ bool containsValue(Object value) => _map.containsValue(value);
+ V operator [](Object key) => key is String ? _map[key.toUpperCase()] : null;
+ void operator []=(String key, V value) {
+ _map[key.toUpperCase()] = value;
+ }
+
+ V putIfAbsent(String key, V ifAbsent()) {
+ return _map.putIfAbsent(key.toUpperCase(), ifAbsent);
+ }
+
+ void addAll(Map<String, V> other) {
+ other.forEach((key, value) => this[key.toUpperCase()] = value);
+ }
+
+ V remove(Object key) => key is String ? _map.remove(key.toUpperCase()) : null;
+
+ void clear() {
+ _map.clear();
+ }
+
+ void forEach(void f(String key, V value)) {
+ _map.forEach(f);
+ }
+
+ Iterable<String> get keys => _map.keys;
+ Iterable<V> get values => _map.values;
+ int get length => _map.length;
+ bool get isEmpty => _map.isEmpty;
+ bool get isNotEmpty => _map.isNotEmpty;
+
+ Iterable<MapEntry<String, V>> get entries => _map.entries;
+
+ Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> transform(String key, V value)) =>
+ _map.map(transform);
+
+ V update(String key, V update(V value), {V ifAbsent()}) =>
+ _map.update(key.toUpperCase(), update, ifAbsent: ifAbsent);
+
+ void updateAll(V update(String key, V value)) {
+ _map.updateAll(update);
+ }
+
+ void removeWhere(bool test(String key, V value)) {
+ _map.removeWhere(test);
+ }
+
+ String toString() => _map.toString();
+}
diff --git a/sdk_nnbd/lib/io/process.dart b/sdk_nnbd/lib/io/process.dart
new file mode 100644
index 0000000..4cf78b9
--- /dev/null
+++ b/sdk_nnbd/lib/io/process.dart
@@ -0,0 +1,700 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+// TODO(ager): The only reason for this class is that we
+// cannot patch a top-level at this point.
+class _ProcessUtils {
+ external static void _exit(int status);
+ external static void _setExitCode(int status);
+ external static int _getExitCode();
+ external static void _sleep(int millis);
+ external static int _pid(Process process);
+ external static Stream<ProcessSignal> _watchSignal(ProcessSignal signal);
+}
+
+/**
+ * Exit the Dart VM process immediately with the given exit code.
+ *
+ * This does not wait for any asynchronous operations to terminate. Using
+ * [exit] is therefore very likely to lose data.
+ *
+ * While debugging, the VM will not respect the `--pause-isolates-on-exit`
+ * flag if [exit] is called as invoking this method causes the Dart VM
+ * process to shutdown immediately. To properly break on exit, consider
+ * calling [debugger] from `dart:developer` or [Isolate.pause] from
+ * `dart:isolate` on [Isolate.current] to pause the isolate before
+ * invoking [exit].
+ *
+ * The handling of exit codes is platform specific.
+ *
+ * On Linux and OS X an exit code for normal termination will always
+ * be in the range [0..255]. If an exit code outside this range is
+ * set the actual exit code will be the lower 8 bits masked off and
+ * treated as an unsigned value. E.g. using an exit code of -1 will
+ * result in an actual exit code of 255 being reported.
+ *
+ * On Windows the exit code can be set to any 32-bit value. However
+ * some of these values are reserved for reporting system errors like
+ * crashes.
+ *
+ * Besides this the Dart executable itself uses an exit code of `254`
+ * for reporting compile time errors and an exit code of `255` for
+ * reporting runtime error (unhandled exception).
+ *
+ * Due to these facts it is recommended to only use exit codes in the
+ * range [0..127] for communicating the result of running a Dart
+ * program to the surrounding environment. This will avoid any
+ * cross-platform issues.
+ */
+void exit(int code) {
+ ArgumentError.checkNotNull(code, "code");
+ if (!_EmbedderConfig._mayExit) {
+ throw new UnsupportedError(
+ "This embedder disallows calling dart:io's exit()");
+ }
+ _ProcessUtils._exit(code);
+}
+
+/**
+ * Set the global exit code for the Dart VM.
+ *
+ * The exit code is global for the Dart VM and the last assignment to
+ * exitCode from any isolate determines the exit code of the Dart VM
+ * on normal termination.
+ *
+ * Default value is `0`.
+ *
+ * See [exit] for more information on how to chose a value for the
+ * exit code.
+ */
+void set exitCode(int code) {
+ ArgumentError.checkNotNull(code, "code");
+ _ProcessUtils._setExitCode(code);
+}
+
+/**
+ * Get the global exit code for the Dart VM.
+ *
+ * The exit code is global for the Dart VM and the last assignment to
+ * exitCode from any isolate determines the exit code of the Dart VM
+ * on normal termination.
+ *
+ * See [exit] for more information on how to chose a value for the
+ * exit code.
+ */
+int get exitCode => _ProcessUtils._getExitCode();
+
+/**
+ * Sleep for the duration specified in [duration].
+ *
+ * Use this with care, as no asynchronous operations can be processed
+ * in a isolate while it is blocked in a [sleep] call.
+ */
+void sleep(Duration duration) {
+ int milliseconds = duration.inMilliseconds;
+ if (milliseconds < 0) {
+ throw new ArgumentError("sleep: duration cannot be negative");
+ }
+ if (!_EmbedderConfig._maySleep) {
+ throw new UnsupportedError(
+ "This embedder disallows calling dart:io's sleep()");
+ }
+ _ProcessUtils._sleep(milliseconds);
+}
+
+/**
+ * Returns the PID of the current process.
+ */
+int get pid => _ProcessUtils._pid(null);
+
+/**
+ * [ProcessInfo] provides methods for retrieving information about the
+ * current process.
+ */
+class ProcessInfo {
+ /**
+ * The current resident set size of memory for the process.
+ *
+ * Note that the meaning of this field is platform dependent. For example,
+ * some memory accounted for here may be shared with other processes, or if
+ * the same page is mapped into a process's address space, it may be counted
+ * twice.
+ */
+ external static int get currentRss;
+
+ /**
+ * The high-watermark in bytes for the resident set size of memory for the
+ * process.
+ *
+ * Note that the meaning of this field is platform dependent. For example,
+ * some memory accounted for here may be shared with other processes, or if
+ * the same page is mapped into a process's address space, it may be counted
+ * twice.
+ */
+ external static int get maxRss;
+}
+
+/**
+ * Modes for running a new process.
+ */
+class ProcessStartMode {
+ /// Normal child process.
+ static const normal = const ProcessStartMode._internal(0);
+ @Deprecated("Use normal instead")
+ static const NORMAL = normal;
+
+ /// Stdio handles are inherited by the child process.
+ static const inheritStdio = const ProcessStartMode._internal(1);
+ @Deprecated("Use inheritStdio instead")
+ static const INHERIT_STDIO = inheritStdio;
+
+ /// Detached child process with no open communication channel.
+ static const detached = const ProcessStartMode._internal(2);
+ @Deprecated("Use detached instead")
+ static const DETACHED = detached;
+
+ /// Detached child process with stdin, stdout and stderr still open
+ /// for communication with the child.
+ static const detachedWithStdio = const ProcessStartMode._internal(3);
+ @Deprecated("Use detachedWithStdio instead")
+ static const DETACHED_WITH_STDIO = detachedWithStdio;
+
+ static List<ProcessStartMode> get values => const <ProcessStartMode>[
+ normal,
+ inheritStdio,
+ detached,
+ detachedWithStdio
+ ];
+ String toString() =>
+ const ["normal", "inheritStdio", "detached", "detachedWithStdio"][_mode];
+
+ final int _mode;
+ const ProcessStartMode._internal(this._mode);
+}
+
+/**
+ * The means to execute a program.
+ *
+ * Use the static [start] and [run] methods to start a new process.
+ * The run method executes the process non-interactively to completion.
+ * In contrast, the start method allows your code to interact with the
+ * running process.
+ *
+ * ## Start a process with the run method
+ *
+ * The following code sample uses the run method to create a process
+ * that runs the UNIX command `ls`, which lists the contents of a directory.
+ * The run method completes with a [ProcessResult] object when the process
+ * terminates. This provides access to the output and exit code from the
+ * process. The run method does not return a Process object; this prevents your
+ * code from interacting with the running process.
+ *
+ * import 'dart:io';
+ *
+ * main() {
+ * // List all files in the current directory in UNIX-like systems.
+ * Process.run('ls', ['-l']).then((ProcessResult results) {
+ * print(results.stdout);
+ * });
+ * }
+ *
+ * ## Start a process with the start method
+ *
+ * The following example uses start to create the process.
+ * The start method returns a [Future] for a Process object.
+ * When the future completes the process is started and
+ * your code can interact with the
+ * Process: writing to stdin, listening to stdout, and so on.
+ *
+ * The following sample starts the UNIX `cat` utility, which when given no
+ * command-line arguments, echos its input.
+ * The program writes to the process's standard input stream
+ * and prints data from its standard output stream.
+ *
+ * import 'dart:io';
+ * import 'dart:convert';
+ *
+ * main() {
+ * Process.start('cat', []).then((Process process) {
+ * process.stdout
+ * .transform(utf8.decoder)
+ * .listen((data) { print(data); });
+ * process.stdin.writeln('Hello, world!');
+ * process.stdin.writeln('Hello, galaxy!');
+ * process.stdin.writeln('Hello, universe!');
+ * });
+ * }
+ *
+ * ## Standard I/O streams
+ *
+ * As seen in the previous code sample, you can interact with the Process's
+ * standard output stream through the getter [stdout],
+ * and you can interact with the Process's standard input stream through
+ * the getter [stdin].
+ * In addition, Process provides a getter [stderr] for using the Process's
+ * standard error stream.
+ *
+ * A Process's streams are distinct from the top-level streams
+ * for the current program.
+ *
+ * ## Exit codes
+ *
+ * Call the [exitCode] method to get the exit code of the process.
+ * The exit code indicates whether the program terminated successfully
+ * (usually indicated with an exit code of 0) or with an error.
+ *
+ * If the start method is used, the exitCode is available through a future
+ * on the Process object (as shown in the example below).
+ * If the run method is used, the exitCode is available
+ * through a getter on the ProcessResult instance.
+ *
+ * import 'dart:io';
+ *
+ * main() {
+ * Process.start('ls', ['-l']).then((process) {
+ * // Get the exit code from the new process.
+ * process.exitCode.then((exitCode) {
+ * print('exit code: $exitCode');
+ * });
+ * });
+ * }
+ *
+ * ## Other resources
+ *
+ * [Dart by Example](https://www.dartlang.org/dart-by-example/#dart-io-and-command-line-apps)
+ * provides additional task-oriented code samples that show how to use
+ * various API from the [dart:io] library.
+ */
+abstract class Process {
+ /**
+ * Returns a [:Future:] which completes with the exit code of the process
+ * when the process completes.
+ *
+ * The handling of exit codes is platform specific.
+ *
+ * On Linux and OS X a normal exit code will be a positive value in
+ * the range [0..255]. If the process was terminated due to a signal
+ * the exit code will be a negative value in the range [-255..-1],
+ * where the absolute value of the exit code is the signal
+ * number. For example, if a process crashes due to a segmentation
+ * violation the exit code will be -11, as the signal SIGSEGV has the
+ * number 11.
+ *
+ * On Windows a process can report any 32-bit value as an exit
+ * code. When returning the exit code this exit code is turned into
+ * a signed value. Some special values are used to report
+ * termination due to some system event. E.g. if a process crashes
+ * due to an access violation the 32-bit exit code is `0xc0000005`,
+ * which will be returned as the negative number `-1073741819`. To
+ * get the original 32-bit value use `(0x100000000 + exitCode) &
+ * 0xffffffff`.
+ *
+ * There is no guarantee that [stdout] and [stderr] have finished reporting
+ * the buffered output of the process when the returned future completes.
+ * To be sure that all output is captured,
+ * wait for the done event on the streams.
+ */
+ Future<int> get exitCode;
+
+ /**
+ * Starts a process running the [executable] with the specified
+ * [arguments]. Returns a [:Future<Process>:] that completes with a
+ * Process instance when the process has been successfully
+ * started. That [Process] object can be used to interact with the
+ * process. If the process cannot be started the returned [Future]
+ * completes with an exception.
+ *
+ * Use [workingDirectory] to set the working directory for the process. Note
+ * that the change of directory occurs before executing the process on some
+ * platforms, which may have impact when using relative paths for the
+ * executable and the arguments.
+ *
+ * Use [environment] to set the environment variables for the process. If not
+ * set the environment of the parent process is inherited. Currently, only
+ * US-ASCII environment variables are supported and errors are likely to occur
+ * if an environment variable with code-points outside the US-ASCII range is
+ * passed in.
+ *
+ * If [includeParentEnvironment] is `true`, the process's environment will
+ * include the parent process's environment, with [environment] taking
+ * precedence. Default is `true`.
+ *
+ * If [runInShell] is `true`, the process will be spawned through a system
+ * shell. On Linux and OS X, [:/bin/sh:] is used, while
+ * [:%WINDIR%\system32\cmd.exe:] is used on Windows.
+ *
+ * Users must read all data coming on the [stdout] and [stderr]
+ * streams of processes started with [:Process.start:]. If the user
+ * does not read all data on the streams the underlying system
+ * resources will not be released since there is still pending data.
+ *
+ * The following code uses `Process.start` to grep for `main` in the
+ * file `test.dart` on Linux.
+ *
+ * Process.start('grep', ['-i', 'main', 'test.dart']).then((process) {
+ * stdout.addStream(process.stdout);
+ * stderr.addStream(process.stderr);
+ * });
+ *
+ * If [mode] is [ProcessStartMode.normal] (the default) a child
+ * process will be started with `stdin`, `stdout` and `stderr`
+ * connected.
+ *
+ * If `mode` is [ProcessStartMode.detached] a detached process will
+ * be created. A detached process has no connection to its parent,
+ * and can keep running on its own when the parent dies. The only
+ * information available from a detached process is its `pid`. There
+ * is no connection to its `stdin`, `stdout` or `stderr`, nor will
+ * the process' exit code become available when it terminates.
+ *
+ * If `mode` is [ProcessStartMode.detachedWithStdio] a detached
+ * process will be created where the `stdin`, `stdout` and `stderr`
+ * are connected. The creator can communicate with the child through
+ * these. The detached process will keep running even if these
+ * communication channels are closed. The process' exit code will
+ * not become available when it terminated.
+ *
+ * The default value for `mode` is `ProcessStartMode.normal`.
+ */
+ external static Future<Process> start(
+ String executable, List<String> arguments,
+ {String workingDirectory,
+ Map<String, String> environment,
+ bool includeParentEnvironment: true,
+ bool runInShell: false,
+ ProcessStartMode mode: ProcessStartMode.normal});
+
+ /**
+ * Starts a process and runs it non-interactively to completion. The
+ * process run is [executable] with the specified [arguments].
+ *
+ * Use [workingDirectory] to set the working directory for the process. Note
+ * that the change of directory occurs before executing the process on some
+ * platforms, which may have impact when using relative paths for the
+ * executable and the arguments.
+ *
+ * Use [environment] to set the environment variables for the process. If not
+ * set the environment of the parent process is inherited. Currently, only
+ * US-ASCII environment variables are supported and errors are likely to occur
+ * if an environment variable with code-points outside the US-ASCII range is
+ * passed in.
+ *
+ * If [includeParentEnvironment] is `true`, the process's environment will
+ * include the parent process's environment, with [environment] taking
+ * precedence. Default is `true`.
+ *
+ * If [runInShell] is true, the process will be spawned through a system
+ * shell. On Linux and OS X, `/bin/sh` is used, while
+ * `%WINDIR%\system32\cmd.exe` is used on Windows.
+ *
+ * The encoding used for decoding `stdout` and `stderr` into text is
+ * controlled through [stdoutEncoding] and [stderrEncoding]. The
+ * default encoding is [systemEncoding]. If `null` is used no
+ * decoding will happen and the [ProcessResult] will hold binary
+ * data.
+ *
+ * Returns a `Future<ProcessResult>` that completes with the
+ * result of running the process, i.e., exit code, standard out and
+ * standard in.
+ *
+ * The following code uses `Process.run` to grep for `main` in the
+ * file `test.dart` on Linux.
+ *
+ * Process.run('grep', ['-i', 'main', 'test.dart']).then((result) {
+ * stdout.write(result.stdout);
+ * stderr.write(result.stderr);
+ * });
+ */
+ external static Future<ProcessResult> run(
+ String executable, List<String> arguments,
+ {String workingDirectory,
+ Map<String, String> environment,
+ bool includeParentEnvironment: true,
+ bool runInShell: false,
+ Encoding stdoutEncoding: systemEncoding,
+ Encoding stderrEncoding: systemEncoding});
+
+ /**
+ * Starts a process and runs it to completion. This is a synchronous
+ * call and will block until the child process terminates.
+ *
+ * The arguments are the same as for `Process.run`.
+ *
+ * Returns a `ProcessResult` with the result of running the process,
+ * i.e., exit code, standard out and standard in.
+ */
+ external static ProcessResult runSync(
+ String executable, List<String> arguments,
+ {String workingDirectory,
+ Map<String, String> environment,
+ bool includeParentEnvironment: true,
+ bool runInShell: false,
+ Encoding stdoutEncoding: systemEncoding,
+ Encoding stderrEncoding: systemEncoding});
+
+ /**
+ * Kills the process with id [pid].
+ *
+ * Where possible, sends the [signal] to the process with id
+ * `pid`. This includes Linux and OS X. The default signal is
+ * [ProcessSignal.sigterm] which will normally terminate the
+ * process.
+ *
+ * On platforms without signal support, including Windows, the call
+ * just terminates the process with id `pid` in a platform specific
+ * way, and the `signal` parameter is ignored.
+ *
+ * Returns `true` if the signal is successfully delivered to the
+ * process. Otherwise the signal could not be sent, usually meaning
+ * that the process is already dead.
+ */
+ external static bool killPid(int pid,
+ [ProcessSignal signal = ProcessSignal.sigterm]);
+
+ /**
+ * Returns the standard output stream of the process as a [:Stream:].
+ */
+ Stream<List<int>> get stdout;
+
+ /**
+ * Returns the standard error stream of the process as a [:Stream:].
+ */
+ Stream<List<int>> get stderr;
+
+ /**
+ * Returns the standard input stream of the process as an [IOSink].
+ */
+ IOSink get stdin;
+
+ /**
+ * Returns the process id of the process.
+ */
+ int get pid;
+
+ /**
+ * Kills the process.
+ *
+ * Where possible, sends the [signal] to the process. This includes
+ * Linux and OS X. The default signal is [ProcessSignal.sigterm]
+ * which will normally terminate the process.
+ *
+ * On platforms without signal support, including Windows, the call
+ * just terminates the process in a platform specific way, and the
+ * `signal` parameter is ignored.
+ *
+ * Returns `true` if the signal is successfully delivered to the
+ * process. Otherwise the signal could not be sent, usually meaning
+ * that the process is already dead.
+ */
+ bool kill([ProcessSignal signal = ProcessSignal.sigterm]);
+}
+
+/**
+ * [ProcessResult] represents the result of running a non-interactive
+ * process started with [Process.run] or [Process.runSync].
+ */
+class ProcessResult {
+ /**
+ * Exit code for the process.
+ *
+ * See [Process.exitCode] for more information in the exit code
+ * value.
+ */
+ final int exitCode;
+
+ /**
+ * Standard output from the process. The value used for the
+ * `stdoutEncoding` argument to `Process.run` determines the type. If
+ * `null` was used this value is of type `List<int>` otherwise it is
+ * of type `String`.
+ */
+ final stdout;
+
+ /**
+ * Standard error from the process. The value used for the
+ * `stderrEncoding` argument to `Process.run` determines the type. If
+ * `null` was used this value is of type `List<int>`
+ * otherwise it is of type `String`.
+ */
+ final stderr;
+
+ /**
+ * Process id of the process.
+ */
+ final int pid;
+
+ ProcessResult(this.pid, this.exitCode, this.stdout, this.stderr);
+}
+
+/**
+ * On Posix systems, [ProcessSignal] is used to send a specific signal
+ * to a child process, see [:Process.kill:].
+ *
+ * Some [ProcessSignal]s can also be watched, as a way to intercept the default
+ * signal handler and implement another. See [ProcessSignal.watch] for more
+ * information.
+ */
+class ProcessSignal {
+ static const ProcessSignal sighup = const ProcessSignal._(1, "SIGHUP");
+ static const ProcessSignal sigint = const ProcessSignal._(2, "SIGINT");
+ static const ProcessSignal sigquit = const ProcessSignal._(3, "SIGQUIT");
+ static const ProcessSignal sigill = const ProcessSignal._(4, "SIGILL");
+ static const ProcessSignal sigtrap = const ProcessSignal._(5, "SIGTRAP");
+ static const ProcessSignal sigabrt = const ProcessSignal._(6, "SIGABRT");
+ static const ProcessSignal sigbus = const ProcessSignal._(7, "SIGBUS");
+ static const ProcessSignal sigfpe = const ProcessSignal._(8, "SIGFPE");
+ static const ProcessSignal sigkill = const ProcessSignal._(9, "SIGKILL");
+ static const ProcessSignal sigusr1 = const ProcessSignal._(10, "SIGUSR1");
+ static const ProcessSignal sigsegv = const ProcessSignal._(11, "SIGSEGV");
+ static const ProcessSignal sigusr2 = const ProcessSignal._(12, "SIGUSR2");
+ static const ProcessSignal sigpipe = const ProcessSignal._(13, "SIGPIPE");
+ static const ProcessSignal sigalrm = const ProcessSignal._(14, "SIGALRM");
+ static const ProcessSignal sigterm = const ProcessSignal._(15, "SIGTERM");
+ static const ProcessSignal sigchld = const ProcessSignal._(17, "SIGCHLD");
+ static const ProcessSignal sigcont = const ProcessSignal._(18, "SIGCONT");
+ static const ProcessSignal sigstop = const ProcessSignal._(19, "SIGSTOP");
+ static const ProcessSignal sigtstp = const ProcessSignal._(20, "SIGTSTP");
+ static const ProcessSignal sigttin = const ProcessSignal._(21, "SIGTTIN");
+ static const ProcessSignal sigttou = const ProcessSignal._(22, "SIGTTOU");
+ static const ProcessSignal sigurg = const ProcessSignal._(23, "SIGURG");
+ static const ProcessSignal sigxcpu = const ProcessSignal._(24, "SIGXCPU");
+ static const ProcessSignal sigxfsz = const ProcessSignal._(25, "SIGXFSZ");
+ static const ProcessSignal sigvtalrm = const ProcessSignal._(26, "SIGVTALRM");
+ static const ProcessSignal sigprof = const ProcessSignal._(27, "SIGPROF");
+ static const ProcessSignal sigwinch = const ProcessSignal._(28, "SIGWINCH");
+ static const ProcessSignal sigpoll = const ProcessSignal._(29, "SIGPOLL");
+ static const ProcessSignal sigsys = const ProcessSignal._(31, "SIGSYS");
+
+ @Deprecated("Use sighup instead")
+ static const ProcessSignal SIGHUP = sighup;
+ @Deprecated("Use sigint instead")
+ static const ProcessSignal SIGINT = sigint;
+ @Deprecated("Use sigquit instead")
+ static const ProcessSignal SIGQUIT = sigquit;
+ @Deprecated("Use sigill instead")
+ static const ProcessSignal SIGILL = sigill;
+ @Deprecated("Use sigtrap instead")
+ static const ProcessSignal SIGTRAP = sigtrap;
+ @Deprecated("Use sigabrt instead")
+ static const ProcessSignal SIGABRT = sigabrt;
+ @Deprecated("Use sigbus instead")
+ static const ProcessSignal SIGBUS = sigbus;
+ @Deprecated("Use sigfpe instead")
+ static const ProcessSignal SIGFPE = sigfpe;
+ @Deprecated("Use sigkill instead")
+ static const ProcessSignal SIGKILL = sigkill;
+ @Deprecated("Use sigusr1 instead")
+ static const ProcessSignal SIGUSR1 = sigusr1;
+ @Deprecated("Use sigsegv instead")
+ static const ProcessSignal SIGSEGV = sigsegv;
+ @Deprecated("Use sigusr2 instead")
+ static const ProcessSignal SIGUSR2 = sigusr2;
+ @Deprecated("Use sigpipe instead")
+ static const ProcessSignal SIGPIPE = sigpipe;
+ @Deprecated("Use sigalrm instead")
+ static const ProcessSignal SIGALRM = sigalrm;
+ @Deprecated("Use sigterm instead")
+ static const ProcessSignal SIGTERM = sigterm;
+ @Deprecated("Use sigchld instead")
+ static const ProcessSignal SIGCHLD = sigchld;
+ @Deprecated("Use sigcont instead")
+ static const ProcessSignal SIGCONT = sigcont;
+ @Deprecated("Use sigstop instead")
+ static const ProcessSignal SIGSTOP = sigstop;
+ @Deprecated("Use sigtstp instead")
+ static const ProcessSignal SIGTSTP = sigtstp;
+ @Deprecated("Use sigttin instead")
+ static const ProcessSignal SIGTTIN = sigttin;
+ @Deprecated("Use sigttou instead")
+ static const ProcessSignal SIGTTOU = sigttou;
+ @Deprecated("Use sigurg instead")
+ static const ProcessSignal SIGURG = sigurg;
+ @Deprecated("Use sigxcpu instead")
+ static const ProcessSignal SIGXCPU = sigxcpu;
+ @Deprecated("Use sigxfsz instead")
+ static const ProcessSignal SIGXFSZ = sigxfsz;
+ @Deprecated("Use sigvtalrm instead")
+ static const ProcessSignal SIGVTALRM = sigvtalrm;
+ @Deprecated("Use sigprof instead")
+ static const ProcessSignal SIGPROF = sigprof;
+ @Deprecated("Use sigwinch instead")
+ static const ProcessSignal SIGWINCH = sigwinch;
+ @Deprecated("Use sigpoll instead")
+ static const ProcessSignal SIGPOLL = sigpoll;
+ @Deprecated("Use sigsys instead")
+ static const ProcessSignal SIGSYS = sigsys;
+
+ final int _signalNumber;
+ final String _name;
+
+ const ProcessSignal._(this._signalNumber, this._name);
+
+ String toString() => _name;
+
+ /**
+ * Watch for process signals.
+ *
+ * The following [ProcessSignal]s can be listened to:
+ *
+ * * [ProcessSignal.sighup].
+ * * [ProcessSignal.sigint]. Signal sent by e.g. CTRL-C.
+ * * [ProcessSignal.sigterm]. Not available on Windows.
+ * * [ProcessSignal.sigusr1]. Not available on Windows.
+ * * [ProcessSignal.sigusr2]. Not available on Windows.
+ * * [ProcessSignal.sigwinch]. Not available on Windows.
+ *
+ * Other signals are disallowed, as they may be used by the VM.
+ *
+ * A signal can be watched multiple times, from multiple isolates, where all
+ * callbacks are invoked when signaled, in no specific order.
+ */
+ Stream<ProcessSignal> watch() => _ProcessUtils._watchSignal(this);
+}
+
+class SignalException implements IOException {
+ final String message;
+ final osError;
+
+ const SignalException(this.message, [this.osError]);
+
+ String toString() {
+ var msg = "";
+ if (osError != null) {
+ msg = ", osError: $osError";
+ }
+ return "SignalException: $message$msg";
+ }
+}
+
+class ProcessException implements IOException {
+ /**
+ * Contains the executable provided for the process.
+ */
+ final String executable;
+
+ /**
+ * Contains the arguments provided for the process.
+ */
+ final List<String> arguments;
+
+ /**
+ * Contains the system message for the process exception if any.
+ */
+ final String message;
+
+ /**
+ * Contains the OS error code for the process exception if any.
+ */
+ final int errorCode;
+
+ const ProcessException(this.executable, this.arguments,
+ [this.message = "", this.errorCode = 0]);
+ String toString() {
+ var msg = (message == null) ? 'OS error code: $errorCode' : message;
+ var args = arguments.join(' ');
+ return "ProcessException: $msg\n Command: $executable $args";
+ }
+}
diff --git a/sdk_nnbd/lib/io/secure_server_socket.dart b/sdk_nnbd/lib/io/secure_server_socket.dart
new file mode 100644
index 0000000..b4ca32e
--- /dev/null
+++ b/sdk_nnbd/lib/io/secure_server_socket.dart
@@ -0,0 +1,291 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * The [SecureServerSocket] is a server socket, providing a stream of high-level
+ * [Socket]s.
+ *
+ * See [SecureSocket] for more info.
+ */
+class SecureServerSocket extends Stream<SecureSocket> {
+ final RawSecureServerSocket _socket;
+
+ SecureServerSocket._(this._socket);
+
+ /**
+ * Returns a future for a [SecureServerSocket]. When the future
+ * completes the server socket is bound to the given [address] and
+ * [port] and has started listening on it.
+ *
+ * The [address] can either be a [String] or an
+ * [InternetAddress]. If [address] is a [String], [bind] will
+ * perform a [InternetAddress.lookup] and use the first value in the
+ * list. To listen on the loopback adapter, which will allow only
+ * incoming connections from the local host, use the value
+ * [InternetAddress.loopbackIPv4] or
+ * [InternetAddress.loopbackIPv6]. To allow for incoming
+ * connection from the network use either one of the values
+ * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+ * bind to all interfaces or the IP address of a specific interface.
+ *
+ * If [port] has the value [:0:] an ephemeral port will be chosen by
+ * the system. The actual port used can be retrieved using the
+ * [port] getter.
+ *
+ * The optional argument [backlog] can be used to specify the listen
+ * backlog for the underlying OS listen setup. If [backlog] has the
+ * value of [:0:] (the default) a reasonable value will be chosen by
+ * the system.
+ *
+ * Incoming client connections are promoted to secure connections, using
+ * the server certificate and key set in [context].
+ *
+ * [address] must be given as a numeric address, not a host name.
+ *
+ * To request or require that clients authenticate by providing an SSL (TLS)
+ * client certificate, set the optional parameter [requestClientCertificate]
+ * or [requireClientCertificate] to true. Requiring a certificate implies
+ * requesting a certificate, so setting both is redundant.
+ * To check whether a client certificate was received, check
+ * SecureSocket.peerCertificate after connecting. If no certificate
+ * was received, the result will be null.
+ *
+ * [supportedProtocols] is an optional list of protocols (in decreasing
+ * order of preference) to use during the ALPN protocol negogiation with
+ * clients. Example values are "http/1.1" or "h2". The selected protocol
+ * can be obtained via [SecureSocket.selectedProtocol].
+ *
+ * The optional argument [shared] specifies whether additional
+ * SecureServerSocket objects can bind to the same combination of `address`,
+ * `port` and `v6Only`. If `shared` is `true` and more `SecureServerSocket`s
+ * from this isolate or other isolates are bound to the port, then the
+ * incoming connections will be distributed among all the bound
+ * `SecureServerSocket`s. Connections can be distributed over multiple
+ * isolates this way.
+ */
+ static Future<SecureServerSocket> bind(
+ address, int port, SecurityContext context,
+ {int backlog: 0,
+ bool v6Only: false,
+ bool requestClientCertificate: false,
+ bool requireClientCertificate: false,
+ List<String> supportedProtocols,
+ bool shared: false}) {
+ return RawSecureServerSocket
+ .bind(address, port, context,
+ backlog: backlog,
+ v6Only: v6Only,
+ requestClientCertificate: requestClientCertificate,
+ requireClientCertificate: requireClientCertificate,
+ supportedProtocols: supportedProtocols,
+ shared: shared)
+ .then((serverSocket) => new SecureServerSocket._(serverSocket));
+ }
+
+ StreamSubscription<SecureSocket> listen(void onData(SecureSocket socket),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ return _socket.map((rawSocket) => new SecureSocket._(rawSocket)).listen(
+ onData,
+ onError: onError,
+ onDone: onDone,
+ cancelOnError: cancelOnError);
+ }
+
+ /**
+ * Returns the port used by this socket.
+ */
+ int get port => _socket.port;
+
+ /**
+ * Returns the address used by this socket.
+ */
+ InternetAddress get address => _socket.address;
+
+ /**
+ * Closes the socket. The returned future completes when the socket
+ * is fully closed and is no longer bound.
+ */
+ Future<SecureServerSocket> close() => _socket.close().then((_) => this);
+
+ void set _owner(owner) {
+ _socket._owner = owner;
+ }
+}
+
+/**
+ * The RawSecureServerSocket is a server socket, providing a stream of low-level
+ * [RawSecureSocket]s.
+ *
+ * See [RawSecureSocket] for more info.
+ */
+class RawSecureServerSocket extends Stream<RawSecureSocket> {
+ final RawServerSocket _socket;
+ StreamController<RawSecureSocket> _controller;
+ StreamSubscription<RawSocket> _subscription;
+ final SecurityContext _context;
+ final bool requestClientCertificate;
+ final bool requireClientCertificate;
+ final List<String> supportedProtocols;
+ bool _closed = false;
+
+ RawSecureServerSocket._(
+ this._socket,
+ this._context,
+ this.requestClientCertificate,
+ this.requireClientCertificate,
+ this.supportedProtocols) {
+ _controller = new StreamController<RawSecureSocket>(
+ sync: true,
+ onListen: _onSubscriptionStateChange,
+ onPause: _onPauseStateChange,
+ onResume: _onPauseStateChange,
+ onCancel: _onSubscriptionStateChange);
+ }
+
+ /**
+ * Returns a future for a [RawSecureServerSocket]. When the future
+ * completes the server socket is bound to the given [address] and
+ * [port] and has started listening on it.
+ *
+ * The [address] can either be a [String] or an
+ * [InternetAddress]. If [address] is a [String], [bind] will
+ * perform a [InternetAddress.lookup] and use the first value in the
+ * list. To listen on the loopback adapter, which will allow only
+ * incoming connections from the local host, use the value
+ * [InternetAddress.loopbackIPv4] or
+ * [InternetAddress.loopbackIPv6]. To allow for incoming
+ * connection from the network use either one of the values
+ * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+ * bind to all interfaces or the IP address of a specific interface.
+ *
+ * If [port] has the value [:0:] an ephemeral port will be chosen by
+ * the system. The actual port used can be retrieved using the
+ * [port] getter.
+ *
+ * The optional argument [backlog] can be used to specify the listen
+ * backlog for the underlying OS listen setup. If [backlog] has the
+ * value of [:0:] (the default) a reasonable value will be chosen by
+ * the system.
+ *
+ * Incoming client connections are promoted to secure connections,
+ * using the server certificate and key set in [context].
+ *
+ * [address] must be given as a numeric address, not a host name.
+ *
+ * To request or require that clients authenticate by providing an SSL (TLS)
+ * client certificate, set the optional parameters requestClientCertificate or
+ * requireClientCertificate to true. Require implies request, so one doesn't
+ * need to specify both. To check whether a client certificate was received,
+ * check SecureSocket.peerCertificate after connecting. If no certificate
+ * was received, the result will be null.
+ *
+ * [supportedProtocols] is an optional list of protocols (in decreasing
+ * order of preference) to use during the ALPN protocol negotiation with
+ * clients. Example values are "http/1.1" or "h2". The selected protocol
+ * can be obtained via [RawSecureSocket.selectedProtocol].
+ *
+ * The optional argument [shared] specifies whether additional
+ * RawSecureServerSocket objects can bind to the same combination of
+ * `address`, `port` and `v6Only`. If `shared` is `true` and more
+ * `RawSecureServerSocket`s from this isolate or other isolates are bound to
+ * the port, then the incoming connections will be distributed among all the
+ * bound `RawSecureServerSocket`s. Connections can be distributed over
+ * multiple isolates this way.
+ */
+ static Future<RawSecureServerSocket> bind(
+ address, int port, SecurityContext context,
+ {int backlog: 0,
+ bool v6Only: false,
+ bool requestClientCertificate: false,
+ bool requireClientCertificate: false,
+ List<String> supportedProtocols,
+ bool shared: false}) {
+ return RawServerSocket
+ .bind(address, port, backlog: backlog, v6Only: v6Only, shared: shared)
+ .then((serverSocket) => new RawSecureServerSocket._(
+ serverSocket,
+ context,
+ requestClientCertificate,
+ requireClientCertificate,
+ supportedProtocols));
+ }
+
+ StreamSubscription<RawSecureSocket> listen(void onData(RawSecureSocket s),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ return _controller.stream.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ /**
+ * Returns the port used by this socket.
+ */
+ int get port => _socket.port;
+
+ /**
+ * Returns the address used by this socket.
+ */
+ InternetAddress get address => _socket.address;
+
+ /**
+ * Closes the socket. The returned future completes when the socket
+ * is fully closed and is no longer bound.
+ */
+ Future<RawSecureServerSocket> close() {
+ _closed = true;
+ return _socket.close().then((_) => this);
+ }
+
+ void _onData(RawSocket connection) {
+ var remotePort;
+ try {
+ remotePort = connection.remotePort;
+ } catch (e) {
+ // If connection is already closed, remotePort throws an exception.
+ // Do nothing - connection is closed.
+ return;
+ }
+ _RawSecureSocket
+ .connect(connection.address, remotePort,
+ context: _context,
+ is_server: true,
+ socket: connection,
+ requestClientCertificate: requestClientCertificate,
+ requireClientCertificate: requireClientCertificate,
+ supportedProtocols: supportedProtocols)
+ .then((RawSecureSocket secureConnection) {
+ if (_closed) {
+ secureConnection.close();
+ } else {
+ _controller.add(secureConnection);
+ }
+ }).catchError((e, s) {
+ if (!_closed) {
+ _controller.addError(e, s);
+ }
+ });
+ }
+
+ void _onPauseStateChange() {
+ if (_controller.isPaused) {
+ _subscription.pause();
+ } else {
+ _subscription.resume();
+ }
+ }
+
+ void _onSubscriptionStateChange() {
+ if (_controller.hasListener) {
+ _subscription = _socket.listen(_onData,
+ onError: _controller.addError, onDone: _controller.close);
+ } else {
+ close();
+ }
+ }
+
+ void set _owner(owner) {
+ (_socket as dynamic)._owner = owner;
+ }
+}
diff --git a/sdk_nnbd/lib/io/secure_socket.dart b/sdk_nnbd/lib/io/secure_socket.dart
new file mode 100644
index 0000000..a4751ef
--- /dev/null
+++ b/sdk_nnbd/lib/io/secure_socket.dart
@@ -0,0 +1,1319 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * A high-level class for communicating securely over a TCP socket, using
+ * TLS and SSL. The [SecureSocket] exposes both a [Stream] and an
+ * [IOSink] interface, making it ideal for using together with
+ * other [Stream]s.
+ */
+abstract class SecureSocket implements Socket {
+ external factory SecureSocket._(RawSecureSocket rawSocket);
+
+ /**
+ * Constructs a new secure client socket and connects it to the given
+ * [host] on port [port]. The returned Future will complete with a
+ * [SecureSocket] that is connected and ready for subscription.
+ *
+ * The certificate provided by the server is checked
+ * using the trusted certificates set in the SecurityContext object.
+ * The default SecurityContext object contains a built-in set of trusted
+ * root certificates for well-known certificate authorities.
+ *
+ * [onBadCertificate] is an optional handler for unverifiable certificates.
+ * The handler receives the [X509Certificate], and can inspect it and
+ * decide (or let the user decide) whether to accept
+ * the connection or not. The handler should return true
+ * to continue the [SecureSocket] connection.
+ *
+ * [supportedProtocols] is an optional list of protocols (in decreasing
+ * order of preference) to use during the ALPN protocol negotiation with the
+ * server. Example values are "http/1.1" or "h2". The selected protocol
+ * can be obtained via [SecureSocket.selectedProtocol].
+ *
+ * The argument [timeout] is used to specify the maximum allowed time to wait
+ * for a connection to be established. If [timeout] is longer than the system
+ * level timeout duration, a timeout may occur sooner than specified in
+ * [timeout]. On timeout, a [SocketException] is thrown and all ongoing
+ * connection attempts to [host] are cancelled.
+
+ */
+ static Future<SecureSocket> connect(host, int port,
+ {SecurityContext context,
+ bool onBadCertificate(X509Certificate certificate),
+ List<String> supportedProtocols,
+ Duration timeout}) {
+ return RawSecureSocket.connect(host, port,
+ context: context,
+ onBadCertificate: onBadCertificate,
+ supportedProtocols: supportedProtocols,
+ timeout: timeout)
+ .then((rawSocket) => new SecureSocket._(rawSocket));
+ }
+
+ /// Like [connect], but returns a [Future] that completes with a
+ /// [ConnectionTask] that can be cancelled if the [SecureSocket] is no
+ /// longer needed.
+ static Future<ConnectionTask<SecureSocket>> startConnect(host, int port,
+ {SecurityContext context,
+ bool onBadCertificate(X509Certificate certificate),
+ List<String> supportedProtocols}) {
+ return RawSecureSocket.startConnect(host, port,
+ context: context,
+ onBadCertificate: onBadCertificate,
+ supportedProtocols: supportedProtocols)
+ .then((rawState) {
+ Future<SecureSocket> socket =
+ rawState.socket.then((rawSocket) => new SecureSocket._(rawSocket));
+ return new ConnectionTask<SecureSocket>._(
+ socket: socket, onCancel: rawState._onCancel);
+ });
+ }
+
+ /**
+ * Takes an already connected [socket] and starts client side TLS
+ * handshake to make the communication secure. When the returned
+ * future completes the [SecureSocket] has completed the TLS
+ * handshake. Using this function requires that the other end of the
+ * connection is prepared for TLS handshake.
+ *
+ * If the [socket] already has a subscription, this subscription
+ * will no longer receive and events. In most cases calling
+ * `pause` on this subscription before starting TLS handshake is
+ * the right thing to do.
+ *
+ * The given [socket] is closed and may not be used anymore.
+ *
+ * If the [host] argument is passed it will be used as the host name
+ * for the TLS handshake. If [host] is not passed the host name from
+ * the [socket] will be used. The [host] can be either a [String] or
+ * an [InternetAddress].
+ *
+ * [supportedProtocols] is an optional list of protocols (in decreasing
+ * order of preference) to use during the ALPN protocol negotiation with the
+ * server. Example values are "http/1.1" or "h2". The selected protocol
+ * can be obtained via [SecureSocket.selectedProtocol].
+ *
+ * Calling this function will _not_ cause a DNS host lookup. If the
+ * [host] passed is a [String] the [InternetAddress] for the
+ * resulting [SecureSocket] will have the passed in [host] as its
+ * host value and the internet address of the already connected
+ * socket as its address value.
+ *
+ * See [connect] for more information on the arguments.
+ *
+ */
+ static Future<SecureSocket> secure(Socket socket,
+ {host,
+ SecurityContext context,
+ bool onBadCertificate(X509Certificate certificate),
+ @Since("2.6") List<String> supportedProtocols}) {
+ return ((socket as dynamic /*_Socket*/)._detachRaw() as Future)
+ .then<RawSecureSocket>((detachedRaw) {
+ return RawSecureSocket.secure(detachedRaw[0] as RawSocket,
+ subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>,
+ host: host,
+ context: context,
+ onBadCertificate: onBadCertificate,
+ supportedProtocols: supportedProtocols);
+ }).then<SecureSocket>((raw) => new SecureSocket._(raw));
+ }
+
+ /**
+ * Takes an already connected [socket] and starts server side TLS
+ * handshake to make the communication secure. When the returned
+ * future completes the [SecureSocket] has completed the TLS
+ * handshake. Using this function requires that the other end of the
+ * connection is going to start the TLS handshake.
+ *
+ * If the [socket] already has a subscription, this subscription
+ * will no longer receive and events. In most cases calling
+ * [:pause:] on this subscription before starting TLS handshake is
+ * the right thing to do.
+ *
+ * If some of the data of the TLS handshake has already been read
+ * from the socket this data can be passed in the [bufferedData]
+ * parameter. This data will be processed before any other data
+ * available on the socket.
+ *
+ * See [SecureServerSocket.bind] for more information on the
+ * arguments.
+ *
+ */
+ static Future<SecureSocket> secureServer(
+ Socket socket, SecurityContext context,
+ {List<int> bufferedData,
+ bool requestClientCertificate: false,
+ bool requireClientCertificate: false,
+ List<String> supportedProtocols}) {
+ return ((socket as dynamic /*_Socket*/)._detachRaw() as Future)
+ .then<RawSecureSocket>((detachedRaw) {
+ return RawSecureSocket.secureServer(detachedRaw[0] as RawSocket, context,
+ subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>,
+ bufferedData: bufferedData,
+ requestClientCertificate: requestClientCertificate,
+ requireClientCertificate: requireClientCertificate,
+ supportedProtocols: supportedProtocols);
+ }).then<SecureSocket>((raw) => new SecureSocket._(raw));
+ }
+
+ /**
+ * Get the peer certificate for a connected SecureSocket. If this
+ * SecureSocket is the server end of a secure socket connection,
+ * [peerCertificate] will return the client certificate, or null, if no
+ * client certificate was received. If it is the client end,
+ * [peerCertificate] will return the server's certificate.
+ */
+ X509Certificate get peerCertificate;
+
+ /**
+ * The protocol which was selected during ALPN protocol negotiation.
+ *
+ * Returns null if one of the peers does not have support for ALPN, did not
+ * specify a list of supported ALPN protocols or there was no common
+ * protocol between client and server.
+ */
+ String get selectedProtocol;
+
+ /**
+ * Renegotiate an existing secure connection, renewing the session keys
+ * and possibly changing the connection properties.
+ *
+ * This repeats the SSL or TLS handshake, with options that allow clearing
+ * the session cache and requesting a client certificate.
+ */
+ void renegotiate(
+ {bool useSessionCache: true,
+ bool requestClientCertificate: false,
+ bool requireClientCertificate: false});
+}
+
+/**
+ * RawSecureSocket provides a secure (SSL or TLS) network connection.
+ * Client connections to a server are provided by calling
+ * RawSecureSocket.connect. A secure server, created with
+ * [RawSecureServerSocket], also returns RawSecureSocket objects representing
+ * the server end of a secure connection.
+ * The certificate provided by the server is checked
+ * using the trusted certificates set in the SecurityContext object.
+ * The default [SecurityContext] object contains a built-in set of trusted
+ * root certificates for well-known certificate authorities.
+ */
+abstract class RawSecureSocket implements RawSocket {
+ /**
+ * Constructs a new secure client socket and connect it to the given
+ * host on the given port. The returned [Future] is completed with the
+ * RawSecureSocket when it is connected and ready for subscription.
+ *
+ * The certificate provided by the server is checked using the trusted
+ * certificates set in the SecurityContext object If a certificate and key are
+ * set on the client, using [SecurityContext.useCertificateChain] and
+ * [SecurityContext.usePrivateKey], and the server asks for a client
+ * certificate, then that client certificate is sent to the server.
+ *
+ * [onBadCertificate] is an optional handler for unverifiable certificates.
+ * The handler receives the [X509Certificate], and can inspect it and
+ * decide (or let the user decide) whether to accept
+ * the connection or not. The handler should return true
+ * to continue the [RawSecureSocket] connection.
+ *
+ * [supportedProtocols] is an optional list of protocols (in decreasing
+ * order of preference) to use during the ALPN protocol negotiation with the
+ * server. Example values are "http/1.1" or "h2". The selected protocol
+ * can be obtained via [RawSecureSocket.selectedProtocol].
+ */
+ static Future<RawSecureSocket> connect(host, int port,
+ {SecurityContext context,
+ bool onBadCertificate(X509Certificate certificate),
+ List<String> supportedProtocols,
+ Duration timeout}) {
+ _RawSecureSocket._verifyFields(
+ host, port, false, false, false, onBadCertificate);
+ return RawSocket.connect(host, port, timeout: timeout).then((socket) {
+ return secure(socket,
+ context: context,
+ onBadCertificate: onBadCertificate,
+ supportedProtocols: supportedProtocols);
+ });
+ }
+
+ /// Like [connect], but returns a [Future] that completes with a
+ /// [ConnectionTask] that can be cancelled if the [RawSecureSocket] is no
+ /// longer needed.
+ static Future<ConnectionTask<RawSecureSocket>> startConnect(host, int port,
+ {SecurityContext context,
+ bool onBadCertificate(X509Certificate certificate),
+ List<String> supportedProtocols}) {
+ return RawSocket.startConnect(host, port)
+ .then((ConnectionTask<RawSocket> rawState) {
+ Future<RawSecureSocket> socket = rawState.socket.then((rawSocket) {
+ return secure(rawSocket,
+ context: context,
+ onBadCertificate: onBadCertificate,
+ supportedProtocols: supportedProtocols);
+ });
+ return new ConnectionTask<RawSecureSocket>._(
+ socket: socket, onCancel: rawState._onCancel);
+ });
+ }
+
+ /**
+ * Takes an already connected [socket] and starts client side TLS
+ * handshake to make the communication secure. When the returned
+ * future completes the [RawSecureSocket] has completed the TLS
+ * handshake. Using this function requires that the other end of the
+ * connection is prepared for TLS handshake.
+ *
+ * If the [socket] already has a subscription, pass the existing
+ * subscription in the [subscription] parameter. The [secure]
+ * operation will take over the subscription by replacing the
+ * handlers with it own secure processing. The caller must not touch
+ * this subscription anymore. Passing a paused subscription is an
+ * error.
+ *
+ * If the [host] argument is passed it will be used as the host name
+ * for the TLS handshake. If [host] is not passed the host name from
+ * the [socket] will be used. The [host] can be either a [String] or
+ * an [InternetAddress].
+ *
+ * [supportedProtocols] is an optional list of protocols (in decreasing
+ * order of preference) to use during the ALPN protocol negotiation with the
+ * server. Example values are "http/1.1" or "h2". The selected protocol
+ * can be obtained via [SecureSocket.selectedProtocol].
+ *
+ * Calling this function will _not_ cause a DNS host lookup. If the
+ * [host] passed is a [String] the [InternetAddress] for the
+ * resulting [SecureSocket] will have this passed in [host] as its
+ * host value and the internet address of the already connected
+ * socket as its address value.
+ *
+ * See [connect] for more information on the arguments.
+ *
+ */
+ static Future<RawSecureSocket> secure(RawSocket socket,
+ {StreamSubscription<RawSocketEvent> subscription,
+ host,
+ SecurityContext context,
+ bool onBadCertificate(X509Certificate certificate),
+ List<String> supportedProtocols}) {
+ socket.readEventsEnabled = false;
+ socket.writeEventsEnabled = false;
+ return _RawSecureSocket.connect(
+ host != null ? host : socket.address.host, socket.port,
+ is_server: false,
+ socket: socket,
+ subscription: subscription,
+ context: context,
+ onBadCertificate: onBadCertificate,
+ supportedProtocols: supportedProtocols);
+ }
+
+ /**
+ * Takes an already connected [socket] and starts server side TLS
+ * handshake to make the communication secure. When the returned
+ * future completes the [RawSecureSocket] has completed the TLS
+ * handshake. Using this function requires that the other end of the
+ * connection is going to start the TLS handshake.
+ *
+ * If the [socket] already has a subscription, pass the existing
+ * subscription in the [subscription] parameter. The [secureServer]
+ * operation will take over the subscription by replacing the
+ * handlers with it own secure processing. The caller must not touch
+ * this subscription anymore. Passing a paused subscription is an
+ * error.
+ *
+ * If some of the data of the TLS handshake has already been read
+ * from the socket this data can be passed in the [bufferedData]
+ * parameter. This data will be processed before any other data
+ * available on the socket.
+ *
+ * See [RawSecureServerSocket.bind] for more information on the
+ * arguments.
+ *
+ */
+ static Future<RawSecureSocket> secureServer(
+ RawSocket socket, SecurityContext context,
+ {StreamSubscription<RawSocketEvent> subscription,
+ List<int> bufferedData,
+ bool requestClientCertificate: false,
+ bool requireClientCertificate: false,
+ List<String> supportedProtocols}) {
+ socket.readEventsEnabled = false;
+ socket.writeEventsEnabled = false;
+ return _RawSecureSocket.connect(socket.address, socket.remotePort,
+ context: context,
+ is_server: true,
+ socket: socket,
+ subscription: subscription,
+ bufferedData: bufferedData,
+ requestClientCertificate: requestClientCertificate,
+ requireClientCertificate: requireClientCertificate,
+ supportedProtocols: supportedProtocols);
+ }
+
+ /**
+ * Renegotiate an existing secure connection, renewing the session keys
+ * and possibly changing the connection properties.
+ *
+ * This repeats the SSL or TLS handshake, with options that allow clearing
+ * the session cache and requesting a client certificate.
+ */
+ void renegotiate(
+ {bool useSessionCache: true,
+ bool requestClientCertificate: false,
+ bool requireClientCertificate: false});
+
+ /**
+ * Get the peer certificate for a connected RawSecureSocket. If this
+ * RawSecureSocket is the server end of a secure socket connection,
+ * [peerCertificate] will return the client certificate, or null, if no
+ * client certificate was received. If it is the client end,
+ * [peerCertificate] will return the server's certificate.
+ */
+ X509Certificate get peerCertificate;
+
+ /**
+ * The protocol which was selected during protocol negotiation.
+ *
+ * Returns null if one of the peers does not have support for ALPN, did not
+ * specify a list of supported ALPN protocols or there was no common
+ * protocol between client and server.
+ */
+ String get selectedProtocol;
+}
+
+/**
+ * X509Certificate represents an SSL certificate, with accessors to
+ * get the fields of the certificate.
+ */
+@pragma("vm:entry-point")
+abstract class X509Certificate {
+ @pragma("vm:entry-point")
+ external factory X509Certificate._();
+
+ /// The DER encoded bytes of the certificate.
+ Uint8List get der;
+
+ /// The PEM encoded String of the certificate.
+ String get pem;
+
+ /// The SHA1 hash of the certificate.
+ Uint8List get sha1;
+
+ String get subject;
+ String get issuer;
+ DateTime get startValidity;
+ DateTime get endValidity;
+}
+
+class _FilterStatus {
+ bool progress = false; // The filter read or wrote data to the buffers.
+ bool readEmpty = true; // The read buffers and decryption filter are empty.
+ bool writeEmpty = true; // The write buffers and encryption filter are empty.
+ // These are set if a buffer changes state from empty or full.
+ bool readPlaintextNoLongerEmpty = false;
+ bool writePlaintextNoLongerFull = false;
+ bool readEncryptedNoLongerFull = false;
+ bool writeEncryptedNoLongerEmpty = false;
+
+ _FilterStatus();
+}
+
+class _RawSecureSocket extends Stream<RawSocketEvent>
+ implements RawSecureSocket {
+ // Status states
+ static const int handshakeStatus = 201;
+ static const int connectedStatus = 202;
+ static const int closedStatus = 203;
+
+ // Buffer identifiers.
+ // These must agree with those in the native C++ implementation.
+ static const int readPlaintextId = 0;
+ static const int writePlaintextId = 1;
+ static const int readEncryptedId = 2;
+ static const int writeEncryptedId = 3;
+ static const int bufferCount = 4;
+
+ // Is a buffer identifier for an encrypted buffer?
+ static bool _isBufferEncrypted(int identifier) =>
+ identifier >= readEncryptedId;
+
+ RawSocket _socket;
+ final Completer<_RawSecureSocket> _handshakeComplete =
+ new Completer<_RawSecureSocket>();
+ StreamController<RawSocketEvent> _controller;
+ Stream<RawSocketEvent> _stream;
+ StreamSubscription<RawSocketEvent> _socketSubscription;
+ List<int> _bufferedData;
+ int _bufferedDataIndex = 0;
+ final InternetAddress address;
+ final bool is_server;
+ SecurityContext context;
+ final bool requestClientCertificate;
+ final bool requireClientCertificate;
+ final Function onBadCertificate;
+
+ var _status = handshakeStatus;
+ bool _writeEventsEnabled = true;
+ bool _readEventsEnabled = true;
+ int _pauseCount = 0;
+ bool _pendingReadEvent = false;
+ bool _socketClosedRead = false; // The network socket is closed for reading.
+ bool _socketClosedWrite = false; // The network socket is closed for writing.
+ bool _closedRead = false; // The secure socket has fired an onClosed event.
+ bool _closedWrite = false; // The secure socket has been closed for writing.
+ // The network socket is gone.
+ Completer<RawSecureSocket> _closeCompleter = new Completer<RawSecureSocket>();
+ _FilterStatus _filterStatus = new _FilterStatus();
+ bool _connectPending = true;
+ bool _filterPending = false;
+ bool _filterActive = false;
+
+ _SecureFilter _secureFilter = new _SecureFilter._();
+ String _selectedProtocol;
+
+ static Future<_RawSecureSocket> connect(
+ dynamic /*String|InternetAddress*/ host, int requestedPort,
+ {bool is_server,
+ SecurityContext context,
+ RawSocket socket,
+ StreamSubscription<RawSocketEvent> subscription,
+ List<int> bufferedData,
+ bool requestClientCertificate: false,
+ bool requireClientCertificate: false,
+ bool onBadCertificate(X509Certificate certificate),
+ List<String> supportedProtocols}) {
+ _verifyFields(host, requestedPort, is_server, requestClientCertificate,
+ requireClientCertificate, onBadCertificate);
+ if (host is InternetAddress) host = host.host;
+ InternetAddress address = socket.address;
+ if (host != null) {
+ address = InternetAddress._cloneWithNewHost(address, host);
+ }
+ return new _RawSecureSocket(
+ address,
+ requestedPort,
+ is_server,
+ context,
+ socket,
+ subscription,
+ bufferedData,
+ requestClientCertificate,
+ requireClientCertificate,
+ onBadCertificate,
+ supportedProtocols)
+ ._handshakeComplete
+ .future;
+ }
+
+ _RawSecureSocket(
+ this.address,
+ int requestedPort,
+ this.is_server,
+ this.context,
+ this._socket,
+ this._socketSubscription,
+ this._bufferedData,
+ this.requestClientCertificate,
+ this.requireClientCertificate,
+ this.onBadCertificate,
+ List<String> supportedProtocols) {
+ context ??= SecurityContext.defaultContext;
+ _controller = new StreamController<RawSocketEvent>(
+ sync: true,
+ onListen: _onSubscriptionStateChange,
+ onPause: _onPauseStateChange,
+ onResume: _onPauseStateChange,
+ onCancel: _onSubscriptionStateChange);
+ _stream = _controller.stream;
+ // Throw an ArgumentError if any field is invalid. After this, all
+ // errors will be reported through the future or the stream.
+ _secureFilter.init();
+ _secureFilter
+ .registerHandshakeCompleteCallback(_secureHandshakeCompleteHandler);
+ if (onBadCertificate != null) {
+ _secureFilter.registerBadCertificateCallback(_onBadCertificateWrapper);
+ }
+ _socket.readEventsEnabled = true;
+ _socket.writeEventsEnabled = false;
+ if (_socketSubscription == null) {
+ // If a current subscription is provided use this otherwise
+ // create a new one.
+ _socketSubscription = _socket.listen(_eventDispatcher,
+ onError: _reportError, onDone: _doneHandler);
+ } else {
+ if (_socketSubscription.isPaused) {
+ _socket.close();
+ throw new ArgumentError("Subscription passed to TLS upgrade is paused");
+ }
+ // If we are upgrading a socket that is already closed for read,
+ // report an error as if we received readClosed during the handshake.
+ dynamic s = _socket; // Cast to dynamic to avoid warning.
+ if (s._socket.closedReadEventSent) {
+ _eventDispatcher(RawSocketEvent.readClosed);
+ }
+ _socketSubscription
+ ..onData(_eventDispatcher)
+ ..onError(_reportError)
+ ..onDone(_doneHandler);
+ }
+ try {
+ var encodedProtocols =
+ SecurityContext._protocolsToLengthEncoding(supportedProtocols);
+ _secureFilter.connect(
+ address.host,
+ context,
+ is_server,
+ requestClientCertificate || requireClientCertificate,
+ requireClientCertificate,
+ encodedProtocols);
+ _secureHandshake();
+ } catch (e, s) {
+ _reportError(e, s);
+ }
+ }
+
+ StreamSubscription<RawSocketEvent> listen(void onData(RawSocketEvent data),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ _sendWriteEvent();
+ return _stream.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ static void _verifyFields(
+ host,
+ int requestedPort,
+ bool is_server,
+ bool requestClientCertificate,
+ bool requireClientCertificate,
+ Function onBadCertificate) {
+ if (host is! String && host is! InternetAddress) {
+ throw new ArgumentError("host is not a String or an InternetAddress");
+ }
+ ArgumentError.checkNotNull(requestedPort, "requestedPort");
+ if (requestedPort < 0 || requestedPort > 65535) {
+ throw ArgumentError("requestedPort is not in the range 0..65535");
+ }
+ ArgumentError.checkNotNull(
+ requestClientCertificate, "requestClientCertificate");
+ ArgumentError.checkNotNull(
+ requireClientCertificate, "requireClientCertificate");
+ }
+
+ int get port => _socket.port;
+
+ InternetAddress get remoteAddress => _socket.remoteAddress;
+
+ int get remotePort => _socket.remotePort;
+
+ void set _owner(owner) {
+ (_socket as dynamic)._owner = owner;
+ }
+
+ int available() {
+ return _status != connectedStatus
+ ? 0
+ : _secureFilter.buffers[readPlaintextId].length;
+ }
+
+ Future<RawSecureSocket> close() {
+ shutdown(SocketDirection.both);
+ return _closeCompleter.future;
+ }
+
+ void _completeCloseCompleter([RawSocket dummy]) {
+ if (!_closeCompleter.isCompleted) _closeCompleter.complete(this);
+ }
+
+ void _close() {
+ _closedWrite = true;
+ _closedRead = true;
+ if (_socket != null) {
+ _socket.close().then(_completeCloseCompleter);
+ } else {
+ _completeCloseCompleter();
+ }
+ _socketClosedWrite = true;
+ _socketClosedRead = true;
+ if (!_filterActive && _secureFilter != null) {
+ _secureFilter.destroy();
+ _secureFilter = null;
+ }
+ if (_socketSubscription != null) {
+ _socketSubscription.cancel();
+ }
+ _controller.close();
+ _status = closedStatus;
+ }
+
+ void shutdown(SocketDirection direction) {
+ if (direction == SocketDirection.send ||
+ direction == SocketDirection.both) {
+ _closedWrite = true;
+ if (_filterStatus.writeEmpty) {
+ _socket.shutdown(SocketDirection.send);
+ _socketClosedWrite = true;
+ if (_closedRead) {
+ _close();
+ }
+ }
+ }
+ if (direction == SocketDirection.receive ||
+ direction == SocketDirection.both) {
+ _closedRead = true;
+ _socketClosedRead = true;
+ _socket.shutdown(SocketDirection.receive);
+ if (_socketClosedWrite) {
+ _close();
+ }
+ }
+ }
+
+ bool get writeEventsEnabled => _writeEventsEnabled;
+
+ void set writeEventsEnabled(bool value) {
+ _writeEventsEnabled = value;
+ if (value) {
+ Timer.run(() => _sendWriteEvent());
+ }
+ }
+
+ bool get readEventsEnabled => _readEventsEnabled;
+
+ void set readEventsEnabled(bool value) {
+ _readEventsEnabled = value;
+ _scheduleReadEvent();
+ }
+
+ Uint8List read([int length]) {
+ if (length != null && (length is! int || length < 0)) {
+ throw new ArgumentError(
+ "Invalid length parameter in SecureSocket.read (length: $length)");
+ }
+ if (_closedRead) {
+ throw new SocketException("Reading from a closed socket");
+ }
+ if (_status != connectedStatus) {
+ return null;
+ }
+ var result = _secureFilter.buffers[readPlaintextId].read(length);
+ _scheduleFilter();
+ return result;
+ }
+
+ // Write the data to the socket, and schedule the filter to encrypt it.
+ int write(List<int> data, [int offset, int bytes]) {
+ if (bytes != null && (bytes is! int || bytes < 0)) {
+ throw new ArgumentError(
+ "Invalid bytes parameter in SecureSocket.read (bytes: $bytes)");
+ }
+ if (offset != null && (offset is! int || offset < 0)) {
+ throw new ArgumentError(
+ "Invalid offset parameter in SecureSocket.read (offset: $offset)");
+ }
+ if (_closedWrite) {
+ _controller.addError(new SocketException("Writing to a closed socket"));
+ return 0;
+ }
+ if (_status != connectedStatus) return 0;
+ offset ??= 0;
+ bytes ??= data.length - offset;
+
+ int written =
+ _secureFilter.buffers[writePlaintextId].write(data, offset, bytes);
+ if (written > 0) {
+ _filterStatus.writeEmpty = false;
+ }
+ _scheduleFilter();
+ return written;
+ }
+
+ X509Certificate get peerCertificate => _secureFilter.peerCertificate;
+
+ String get selectedProtocol => _selectedProtocol;
+
+ bool _onBadCertificateWrapper(X509Certificate certificate) {
+ if (onBadCertificate == null) return false;
+ var result = onBadCertificate(certificate);
+ if (result is bool) return result;
+ throw new HandshakeException(
+ "onBadCertificate callback returned non-boolean $result");
+ }
+
+ bool setOption(SocketOption option, bool enabled) {
+ if (_socket == null) return false;
+ return _socket.setOption(option, enabled);
+ }
+
+ Uint8List getRawOption(RawSocketOption option) {
+ return _socket?.getRawOption(option);
+ }
+
+ void setRawOption(RawSocketOption option) {
+ _socket?.setRawOption(option);
+ }
+
+ void _eventDispatcher(RawSocketEvent event) {
+ try {
+ if (event == RawSocketEvent.read) {
+ _readHandler();
+ } else if (event == RawSocketEvent.write) {
+ _writeHandler();
+ } else if (event == RawSocketEvent.readClosed) {
+ _closeHandler();
+ }
+ } catch (e, stackTrace) {
+ _reportError(e, stackTrace);
+ }
+ }
+
+ void _readHandler() {
+ _readSocket();
+ _scheduleFilter();
+ }
+
+ void _writeHandler() {
+ _writeSocket();
+ _scheduleFilter();
+ }
+
+ void _doneHandler() {
+ if (_filterStatus.readEmpty) {
+ _close();
+ }
+ }
+
+ void _reportError(e, [StackTrace stackTrace]) {
+ if (_status == closedStatus) {
+ return;
+ } else if (_connectPending) {
+ // _connectPending is true until the handshake has completed, and the
+ // _handshakeComplete future returned from SecureSocket.connect has
+ // completed. Before this point, we must complete it with an error.
+ _handshakeComplete.completeError(e, stackTrace);
+ } else {
+ _controller.addError(e, stackTrace);
+ }
+ _close();
+ }
+
+ void _closeHandler() {
+ if (_status == connectedStatus) {
+ if (_closedRead) return;
+ _socketClosedRead = true;
+ if (_filterStatus.readEmpty) {
+ _closedRead = true;
+ _controller.add(RawSocketEvent.readClosed);
+ if (_socketClosedWrite) {
+ _close();
+ }
+ } else {
+ _scheduleFilter();
+ }
+ } else if (_status == handshakeStatus) {
+ _socketClosedRead = true;
+ if (_filterStatus.readEmpty) {
+ _reportError(
+ new HandshakeException('Connection terminated during handshake'),
+ null);
+ } else {
+ _secureHandshake();
+ }
+ }
+ }
+
+ void _secureHandshake() {
+ try {
+ _secureFilter.handshake();
+ _filterStatus.writeEmpty = false;
+ _readSocket();
+ _writeSocket();
+ _scheduleFilter();
+ } catch (e, stackTrace) {
+ _reportError(e, stackTrace);
+ }
+ }
+
+ void renegotiate(
+ {bool useSessionCache: true,
+ bool requestClientCertificate: false,
+ bool requireClientCertificate: false}) {
+ if (_status != connectedStatus) {
+ throw new HandshakeException(
+ "Called renegotiate on a non-connected socket");
+ }
+ _secureFilter.renegotiate(
+ useSessionCache, requestClientCertificate, requireClientCertificate);
+ _status = handshakeStatus;
+ _filterStatus.writeEmpty = false;
+ _scheduleFilter();
+ }
+
+ void _secureHandshakeCompleteHandler() {
+ _status = connectedStatus;
+ if (_connectPending) {
+ _connectPending = false;
+ try {
+ _selectedProtocol = _secureFilter.selectedProtocol();
+ // We don't want user code to run synchronously in this callback.
+ Timer.run(() => _handshakeComplete.complete(this));
+ } catch (error, stack) {
+ _handshakeComplete.completeError(error, stack);
+ }
+ }
+ }
+
+ void _onPauseStateChange() {
+ if (_controller.isPaused) {
+ _pauseCount++;
+ } else {
+ _pauseCount--;
+ if (_pauseCount == 0) {
+ _scheduleReadEvent();
+ _sendWriteEvent(); // Can send event synchronously.
+ }
+ }
+
+ if (!_socketClosedRead || !_socketClosedWrite) {
+ if (_controller.isPaused) {
+ _socketSubscription.pause();
+ } else {
+ _socketSubscription.resume();
+ }
+ }
+ }
+
+ void _onSubscriptionStateChange() {
+ if (_controller.hasListener) {
+ // TODO(ajohnsen): Do something here?
+ }
+ }
+
+ void _scheduleFilter() {
+ _filterPending = true;
+ _tryFilter();
+ }
+
+ void _tryFilter() {
+ if (_status == closedStatus) {
+ return;
+ }
+ if (_filterPending && !_filterActive) {
+ _filterActive = true;
+ _filterPending = false;
+ _pushAllFilterStages().then((status) {
+ _filterStatus = status;
+ _filterActive = false;
+ if (_status == closedStatus) {
+ _secureFilter.destroy();
+ _secureFilter = null;
+ return;
+ }
+ _socket.readEventsEnabled = true;
+ if (_filterStatus.writeEmpty && _closedWrite && !_socketClosedWrite) {
+ // Checks for and handles all cases of partially closed sockets.
+ shutdown(SocketDirection.send);
+ if (_status == closedStatus) {
+ return;
+ }
+ }
+ if (_filterStatus.readEmpty && _socketClosedRead && !_closedRead) {
+ if (_status == handshakeStatus) {
+ _secureFilter.handshake();
+ if (_status == handshakeStatus) {
+ throw new HandshakeException(
+ 'Connection terminated during handshake');
+ }
+ }
+ _closeHandler();
+ }
+ if (_status == closedStatus) {
+ return;
+ }
+ if (_filterStatus.progress) {
+ _filterPending = true;
+ if (_filterStatus.writeEncryptedNoLongerEmpty) {
+ _writeSocket();
+ }
+ if (_filterStatus.writePlaintextNoLongerFull) {
+ _sendWriteEvent();
+ }
+ if (_filterStatus.readEncryptedNoLongerFull) {
+ _readSocket();
+ }
+ if (_filterStatus.readPlaintextNoLongerEmpty) {
+ _scheduleReadEvent();
+ }
+ if (_status == handshakeStatus) {
+ _secureHandshake();
+ }
+ }
+ _tryFilter();
+ }).catchError(_reportError);
+ }
+ }
+
+ List<int> _readSocketOrBufferedData(int bytes) {
+ if (_bufferedData != null) {
+ if (bytes > _bufferedData.length - _bufferedDataIndex) {
+ bytes = _bufferedData.length - _bufferedDataIndex;
+ }
+ var result =
+ _bufferedData.sublist(_bufferedDataIndex, _bufferedDataIndex + bytes);
+ _bufferedDataIndex += bytes;
+ if (_bufferedData.length == _bufferedDataIndex) {
+ _bufferedData = null;
+ }
+ return result;
+ } else if (!_socketClosedRead) {
+ return _socket.read(bytes);
+ } else {
+ return null;
+ }
+ }
+
+ void _readSocket() {
+ if (_status == closedStatus) return;
+ var buffer = _secureFilter.buffers[readEncryptedId];
+ if (buffer.writeFromSource(_readSocketOrBufferedData) > 0) {
+ _filterStatus.readEmpty = false;
+ } else {
+ _socket.readEventsEnabled = false;
+ }
+ }
+
+ void _writeSocket() {
+ if (_socketClosedWrite) return;
+ var buffer = _secureFilter.buffers[writeEncryptedId];
+ if (buffer.readToSocket(_socket)) {
+ // Returns true if blocked
+ _socket.writeEventsEnabled = true;
+ }
+ }
+
+ // If a read event should be sent, add it to the controller.
+ _scheduleReadEvent() {
+ if (!_pendingReadEvent &&
+ _readEventsEnabled &&
+ _pauseCount == 0 &&
+ _secureFilter != null &&
+ !_secureFilter.buffers[readPlaintextId].isEmpty) {
+ _pendingReadEvent = true;
+ Timer.run(_sendReadEvent);
+ }
+ }
+
+ _sendReadEvent() {
+ _pendingReadEvent = false;
+ if (_status != closedStatus &&
+ _readEventsEnabled &&
+ _pauseCount == 0 &&
+ _secureFilter != null &&
+ !_secureFilter.buffers[readPlaintextId].isEmpty) {
+ _controller.add(RawSocketEvent.read);
+ _scheduleReadEvent();
+ }
+ }
+
+ // If a write event should be sent, add it to the controller.
+ _sendWriteEvent() {
+ if (!_closedWrite &&
+ _writeEventsEnabled &&
+ _pauseCount == 0 &&
+ _secureFilter != null &&
+ _secureFilter.buffers[writePlaintextId].free > 0) {
+ _writeEventsEnabled = false;
+ _controller.add(RawSocketEvent.write);
+ }
+ }
+
+ Future<_FilterStatus> _pushAllFilterStages() {
+ bool wasInHandshake = _status != connectedStatus;
+ List args = new List(2 + bufferCount * 2);
+ args[0] = _secureFilter._pointer();
+ args[1] = wasInHandshake;
+ var bufs = _secureFilter.buffers;
+ for (var i = 0; i < bufferCount; ++i) {
+ args[2 * i + 2] = bufs[i].start;
+ args[2 * i + 3] = bufs[i].end;
+ }
+
+ return _IOService._dispatch(_IOService.sslProcessFilter, args)
+ .then((response) {
+ if (response.length == 2) {
+ if (wasInHandshake) {
+ // If we're in handshake, throw a handshake error.
+ _reportError(
+ new HandshakeException('${response[1]} error ${response[0]}'),
+ null);
+ } else {
+ // If we're connected, throw a TLS error.
+ _reportError(
+ new TlsException('${response[1]} error ${response[0]}'), null);
+ }
+ }
+ int start(int index) => response[2 * index];
+ int end(int index) => response[2 * index + 1];
+
+ _FilterStatus status = new _FilterStatus();
+ // Compute writeEmpty as "write plaintext buffer and write encrypted
+ // buffer were empty when we started and are empty now".
+ status.writeEmpty = bufs[writePlaintextId].isEmpty &&
+ start(writeEncryptedId) == end(writeEncryptedId);
+ // If we were in handshake when this started, _writeEmpty may be false
+ // because the handshake wrote data after we checked.
+ if (wasInHandshake) status.writeEmpty = false;
+
+ // Compute readEmpty as "both read buffers were empty when we started
+ // and are empty now".
+ status.readEmpty = bufs[readEncryptedId].isEmpty &&
+ start(readPlaintextId) == end(readPlaintextId);
+
+ _ExternalBuffer buffer = bufs[writePlaintextId];
+ int new_start = start(writePlaintextId);
+ if (new_start != buffer.start) {
+ status.progress = true;
+ if (buffer.free == 0) {
+ status.writePlaintextNoLongerFull = true;
+ }
+ buffer.start = new_start;
+ }
+ buffer = bufs[readEncryptedId];
+ new_start = start(readEncryptedId);
+ if (new_start != buffer.start) {
+ status.progress = true;
+ if (buffer.free == 0) {
+ status.readEncryptedNoLongerFull = true;
+ }
+ buffer.start = new_start;
+ }
+ buffer = bufs[writeEncryptedId];
+ int new_end = end(writeEncryptedId);
+ if (new_end != buffer.end) {
+ status.progress = true;
+ if (buffer.length == 0) {
+ status.writeEncryptedNoLongerEmpty = true;
+ }
+ buffer.end = new_end;
+ }
+ buffer = bufs[readPlaintextId];
+ new_end = end(readPlaintextId);
+ if (new_end != buffer.end) {
+ status.progress = true;
+ if (buffer.length == 0) {
+ status.readPlaintextNoLongerEmpty = true;
+ }
+ buffer.end = new_end;
+ }
+ return status;
+ });
+ }
+}
+
+/**
+ * A circular buffer backed by an external byte array. Accessed from
+ * both C++ and Dart code in an unsynchronized way, with one reading
+ * and one writing. All updates to start and end are done by Dart code.
+ */
+class _ExternalBuffer {
+ // This will be an ExternalByteArray, backed by C allocated data.
+ @pragma("vm:entry-point", "set")
+ List<int> data;
+
+ @pragma("vm:entry-point")
+ int start;
+
+ @pragma("vm:entry-point")
+ int end;
+
+ final size;
+
+ _ExternalBuffer(this.size) {
+ start = end = size ~/ 2;
+ }
+
+ void advanceStart(int bytes) {
+ assert(start > end || start + bytes <= end);
+ start += bytes;
+ if (start >= size) {
+ start -= size;
+ assert(start <= end);
+ assert(start < size);
+ }
+ }
+
+ void advanceEnd(int bytes) {
+ assert(start <= end || start > end + bytes);
+ end += bytes;
+ if (end >= size) {
+ end -= size;
+ assert(end < start);
+ assert(end < size);
+ }
+ }
+
+ bool get isEmpty => end == start;
+
+ int get length => start > end ? size + end - start : end - start;
+
+ int get linearLength => start > end ? size - start : end - start;
+
+ int get free => start > end ? start - end - 1 : size + start - end - 1;
+
+ int get linearFree {
+ if (start > end) return start - end - 1;
+ if (start == 0) return size - end - 1;
+ return size - end;
+ }
+
+ Uint8List read(int bytes) {
+ if (bytes == null) {
+ bytes = length;
+ } else {
+ bytes = min(bytes, length);
+ }
+ if (bytes == 0) return null;
+ Uint8List result = new Uint8List(bytes);
+ int bytesRead = 0;
+ // Loop over zero, one, or two linear data ranges.
+ while (bytesRead < bytes) {
+ int toRead = min(bytes - bytesRead, linearLength);
+ result.setRange(bytesRead, bytesRead + toRead, data, start);
+ advanceStart(toRead);
+ bytesRead += toRead;
+ }
+ return result;
+ }
+
+ int write(List<int> inputData, int offset, int bytes) {
+ if (bytes > free) {
+ bytes = free;
+ }
+ int written = 0;
+ int toWrite = min(bytes, linearFree);
+ // Loop over zero, one, or two linear data ranges.
+ while (toWrite > 0) {
+ data.setRange(end, end + toWrite, inputData, offset);
+ advanceEnd(toWrite);
+ offset += toWrite;
+ written += toWrite;
+ toWrite = min(bytes - written, linearFree);
+ }
+ return written;
+ }
+
+ int writeFromSource(List<int> getData(int requested)) {
+ int written = 0;
+ int toWrite = linearFree;
+ // Loop over zero, one, or two linear data ranges.
+ while (toWrite > 0) {
+ // Source returns at most toWrite bytes, and it returns null when empty.
+ var inputData = getData(toWrite);
+ if (inputData == null || inputData.length == 0) break;
+ var len = inputData.length;
+ data.setRange(end, end + len, inputData);
+ advanceEnd(len);
+ written += len;
+ toWrite = linearFree;
+ }
+ return written;
+ }
+
+ bool readToSocket(RawSocket socket) {
+ // Loop over zero, one, or two linear data ranges.
+ while (true) {
+ var toWrite = linearLength;
+ if (toWrite == 0) return false;
+ int bytes = socket.write(data, start, toWrite);
+ advanceStart(bytes);
+ if (bytes < toWrite) {
+ // The socket has blocked while we have data to write.
+ return true;
+ }
+ }
+ }
+}
+
+abstract class _SecureFilter {
+ external factory _SecureFilter._();
+
+ void connect(
+ String hostName,
+ SecurityContext context,
+ bool is_server,
+ bool requestClientCertificate,
+ bool requireClientCertificate,
+ Uint8List protocols);
+ void destroy();
+ void handshake();
+ String selectedProtocol();
+ void rehandshake();
+ void renegotiate(bool useSessionCache, bool requestClientCertificate,
+ bool requireClientCertificate);
+ void init();
+ X509Certificate get peerCertificate;
+ int processBuffer(int bufferIndex);
+ void registerBadCertificateCallback(Function callback);
+ void registerHandshakeCompleteCallback(Function handshakeCompleteHandler);
+
+ // This call may cause a reference counted pointer in the native
+ // implementation to be retained. It should only be called when the resulting
+ // value is passed to the IO service through a call to dispatch().
+ int _pointer();
+
+ List<_ExternalBuffer> get buffers;
+}
+
+/** A secure networking exception caused by a failure in the
+ * TLS/SSL protocol.
+ */
+class TlsException implements IOException {
+ final String type;
+ final String message;
+ final OSError osError;
+
+ @pragma("vm:entry-point")
+ const TlsException([String message = "", OSError osError])
+ : this._("TlsException", message, osError);
+
+ const TlsException._(this.type, this.message, this.osError);
+
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.write(type);
+ if (message.isNotEmpty) {
+ sb.write(": $message");
+ if (osError != null) {
+ sb.write(" ($osError)");
+ }
+ } else if (osError != null) {
+ sb.write(": $osError");
+ }
+ return sb.toString();
+ }
+}
+
+/**
+ * An exception that happens in the handshake phase of establishing
+ * a secure network connection.
+ */
+@pragma("vm:entry-point")
+class HandshakeException extends TlsException {
+ @pragma("vm:entry-point")
+ const HandshakeException([String message = "", OSError osError])
+ : super._("HandshakeException", message, osError);
+}
+
+/**
+ * An exception that happens in the handshake phase of establishing
+ * a secure network connection, when looking up or verifying a
+ * certificate.
+ */
+class CertificateException extends TlsException {
+ @pragma("vm:entry-point")
+ const CertificateException([String message = "", OSError osError])
+ : super._("CertificateException", message, osError);
+}
diff --git a/sdk_nnbd/lib/io/security_context.dart b/sdk_nnbd/lib/io/security_context.dart
new file mode 100644
index 0000000..96da93b
--- /dev/null
+++ b/sdk_nnbd/lib/io/security_context.dart
@@ -0,0 +1,283 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * The object containing the certificates to trust when making
+ * a secure client connection, and the certificate chain and
+ * private key to serve from a secure server.
+ *
+ * The [SecureSocket] and [SecureServerSocket] classes take a SecurityContext
+ * as an argument to their connect and bind methods.
+ *
+ * Certificates and keys can be added to a SecurityContext from either PEM
+ * or PKCS12 containers.
+ *
+ * iOS note: Some methods to add, remove, and inspect certificates are not yet
+ * implemented. However, the platform's built-in trusted certificates can
+ * be used, by way of [SecurityContext.defaultContext].
+ */
+abstract class SecurityContext {
+ /**
+ * Creates a new [SecurityContext].
+ *
+ * By default, the created [SecurityContext] contains no keys or certificates.
+ * These can be added by calling the methods of this class.
+ *
+ * If `withTrustedRoots` is passed as `true`, the [SecurityContext] will be
+ * seeded by the trusted root certificates provided as explained below. To
+ * obtain a [SecurityContext] containing trusted root certificates,
+ * [SecurityContext.defaultContext] is usually sufficient, and should
+ * be used instead. However, if the [SecurityContext] containing the trusted
+ * root certificates must be modified per-connection, then `withTrustedRoots`
+ * should be used.
+ */
+ external factory SecurityContext({bool withTrustedRoots: false});
+
+ /**
+ * Secure networking classes with an optional `context` parameter
+ * use the [defaultContext] object if the parameter is omitted.
+ * This object can also be accessed, and modified, directly.
+ * Each isolate has a different [defaultContext] object.
+ * The [defaultContext] object uses a list of well-known trusted
+ * certificate authorities as its trusted roots. On Linux and Windows, this
+ * list is taken from Mozilla, who maintains it as part of Firefox. On,
+ * MacOS, iOS, and Android, this list comes from the trusted certificates
+ * stores built in to the platforms.
+ */
+ external static SecurityContext get defaultContext;
+
+ /**
+ * Sets the private key for a server certificate or client certificate.
+ *
+ * A secure connection using this SecurityContext will use this key with
+ * the server or client certificate to sign and decrypt messages.
+ * [file] is the path to a PEM or PKCS12 file containing an encrypted
+ * private key, encrypted with [password]. Assuming it is well-formatted, all
+ * other contents of [file] are ignored. An unencrypted file can be used,
+ * but this is not usual.
+ *
+ * NB: This function calls [File.readAsBytesSync], and will block on file IO.
+ * Prefer using [usePrivateKeyBytes].
+ *
+ * iOS note: Only PKCS12 data is supported. It should contain both the private
+ * key and the certificate chain. On iOS one call to [usePrivateKey] with this
+ * data is used instead of two calls to [useCertificateChain] and
+ * [usePrivateKey].
+ */
+ void usePrivateKey(String file, {String password});
+
+ /**
+ * Sets the private key for a server certificate or client certificate.
+ *
+ * Like [usePrivateKey], but takes the contents of the file as a list
+ * of bytes.
+ */
+ void usePrivateKeyBytes(List<int> keyBytes, {String password});
+
+ /**
+ * Sets the set of trusted X509 certificates used by [SecureSocket]
+ * client connections, when connecting to a secure server.
+ *
+ * [file] is the path to a PEM or PKCS12 file containing X509 certificates,
+ * usually root certificates from certificate authorities. For PKCS12 files,
+ * [password] is the password for the file. For PEM files, [password] is
+ * ignored. Assuming it is well-formatted, all other contents of [file] are
+ * ignored.
+ *
+ * NB: This function calls [File.readAsBytesSync], and will block on file IO.
+ * Prefer using [setTrustedCertificatesBytes].
+ *
+ * iOS note: On iOS, this call takes only the bytes for a single DER
+ * encoded X509 certificate. It may be called multiple times to add
+ * multiple trusted certificates to the context. A DER encoded certificate
+ * can be obtained from a PEM encoded certificate by using the openssl tool:
+ *
+ * $ openssl x509 -outform der -in cert.pem -out cert.der
+ */
+ void setTrustedCertificates(String file, {String password});
+
+ /**
+ * Sets the set of trusted X509 certificates used by [SecureSocket]
+ * client connections, when connecting to a secure server.
+ *
+ * Like [setTrustedCertificates] but takes the contents of the file.
+ */
+ void setTrustedCertificatesBytes(List<int> certBytes, {String password});
+
+ /**
+ * Sets the chain of X509 certificates served by [SecureServerSocket]
+ * when making secure connections, including the server certificate.
+ *
+ * [file] is a PEM or PKCS12 file containing X509 certificates, starting with
+ * the root authority and intermediate authorities forming the signed
+ * chain to the server certificate, and ending with the server certificate.
+ * The private key for the server certificate is set by [usePrivateKey]. For
+ * PKCS12 files, [password] is the password for the file. For PEM files,
+ * [password] is ignored. Assuming it is well-formatted, all
+ * other contents of [file] are ignored.
+ *
+ * NB: This function calls [File.readAsBytesSync], and will block on file IO.
+ * Prefer using [useCertificateChainBytes].
+ *
+ * iOS note: As noted above, [usePrivateKey] does the job of both
+ * that call and this one. On iOS, this call is a no-op.
+ */
+ void useCertificateChain(String file, {String password});
+
+ /**
+ * Sets the chain of X509 certificates served by [SecureServerSocket]
+ * when making secure connections, including the server certificate.
+ *
+ * Like [useCertificateChain] but takes the contents of the file.
+ */
+ void useCertificateChainBytes(List<int> chainBytes, {String password});
+
+ /**
+ * Sets the list of authority names that a [SecureServerSocket] will advertise
+ * as accepted when requesting a client certificate from a connecting
+ * client.
+ *
+ * [file] is a PEM or PKCS12 file containing the accepted signing
+ * authority certificates - the authority names are extracted from the
+ * certificates. For PKCS12 files, [password] is the password for the file.
+ * For PEM files, [password] is ignored. Assuming it is well-formatted, all
+ * other contents of [file] are ignored.
+ *
+ * NB: This function calls [File.readAsBytesSync], and will block on file IO.
+ * Prefer using [setClientAuthoritiesBytes].
+ *
+ * iOS note: This call is not supported.
+ */
+ void setClientAuthorities(String file, {String password});
+
+ /**
+ * Sets the list of authority names that a [SecureServerSocket] will advertise
+ * as accepted, when requesting a client certificate from a connecting
+ * client.
+ *
+ * Like [setClientAuthorities] but takes the contents of the file.
+ */
+ void setClientAuthoritiesBytes(List<int> authCertBytes, {String password});
+
+ /**
+ * Whether the platform supports ALPN. This always returns true and will be
+ * removed in a future release.
+ */
+ @deprecated
+ external static bool get alpnSupported;
+
+ /**
+ * Sets the list of application-level protocols supported by a client
+ * connection or server connection. The ALPN (application level protocol
+ * negotiation) extension to TLS allows a client to send a list of
+ * protocols in the TLS client hello message, and the server to pick
+ * one and send the selected one back in its server hello message.
+ *
+ * Separate lists of protocols can be sent for client connections and
+ * for server connections, using the same SecurityContext. The [isServer]
+ * boolean argument specifies whether to set the list for server connections
+ * or client connections.
+ */
+ void setAlpnProtocols(List<String> protocols, bool isServer);
+
+ /// Encodes a set of supported protocols for ALPN/NPN usage.
+ ///
+ /// The `protocols` list is expected to contain protocols in descending order
+ /// of preference.
+ ///
+ /// See RFC 7301 (https://tools.ietf.org/html/rfc7301) for the encoding of
+ /// `List<String> protocols`:
+ /// opaque ProtocolName<1..2^8-1>;
+ ///
+ /// struct {
+ /// ProtocolName protocol_name_list<2..2^16-1>
+ /// } ProtocolNameList;
+ ///
+ /// The encoding of the opaque `ProtocolName<lower..upper>` vector is
+ /// described in RFC 2246: 4.3 Vectors.
+ ///
+ /// Note: Even though this encoding scheme would allow a total
+ /// `ProtocolNameList` length of 65535, this limit cannot be reached. Testing
+ /// showed that more than ~ 2^14 bytes will fail to negotiate a protocol.
+ /// We will be conservative and support only messages up to (1<<13)-1 bytes.
+ static Uint8List _protocolsToLengthEncoding(List<String> protocols) {
+ if (protocols == null || protocols.length == 0) {
+ return new Uint8List(0);
+ }
+ int protocolsLength = protocols.length;
+
+ // Calculate the number of bytes we will need if it is ASCII.
+ int expectedLength = protocolsLength;
+ for (int i = 0; i < protocolsLength; i++) {
+ int length = protocols[i].length;
+ if (length > 0 && length <= 255) {
+ expectedLength += length;
+ } else {
+ throw new ArgumentError(
+ 'Length of protocol must be between 1 and 255 (was: $length).');
+ }
+ }
+
+ if (expectedLength >= (1 << 13)) {
+ throw new ArgumentError(
+ 'The maximum message length supported is 2^13-1.');
+ }
+
+ // Try encoding the `List<String> protocols` array using fast ASCII path.
+ var bytes = new Uint8List(expectedLength);
+ int bytesOffset = 0;
+ for (int i = 0; i < protocolsLength; i++) {
+ String proto = protocols[i];
+
+ // Add length byte.
+ bytes[bytesOffset++] = proto.length;
+ int bits = 0;
+
+ // Add protocol bytes.
+ for (int j = 0; j < proto.length; j++) {
+ var char = proto.codeUnitAt(j);
+ bits |= char;
+ bytes[bytesOffset++] = char & 0xff;
+ }
+
+ // Go slow case if we have encountered anything non-ascii.
+ if (bits > 0x7f) {
+ return _protocolsToLengthEncodingNonAsciiBailout(protocols);
+ }
+ }
+ return bytes;
+ }
+
+ static Uint8List _protocolsToLengthEncodingNonAsciiBailout(
+ List<String> protocols) {
+ void addProtocol(List<int> outBytes, String protocol) {
+ var protocolBytes = utf8.encode(protocol);
+ var len = protocolBytes.length;
+
+ if (len > 255) {
+ throw new ArgumentError(
+ 'Length of protocol must be between 1 and 255 (was: $len)');
+ }
+ // Add length byte.
+ outBytes.add(len);
+
+ // Add protocol bytes.
+ outBytes.addAll(protocolBytes);
+ }
+
+ List<int> bytes = [];
+ for (var i = 0; i < protocols.length; i++) {
+ addProtocol(bytes, protocols[i]);
+ }
+
+ if (bytes.length >= (1 << 13)) {
+ throw new ArgumentError(
+ 'The maximum message length supported is 2^13-1.');
+ }
+
+ return new Uint8List.fromList(bytes);
+ }
+}
diff --git a/sdk_nnbd/lib/io/service_object.dart b/sdk_nnbd/lib/io/service_object.dart
new file mode 100644
index 0000000..e6b1851
--- /dev/null
+++ b/sdk_nnbd/lib/io/service_object.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+int _nextServiceId = 1;
+
+// TODO(ajohnsen): Use other way of getting a unique id.
+abstract class _ServiceObject {
+ int __serviceId = 0;
+ int get _serviceId {
+ if (__serviceId == 0) __serviceId = _nextServiceId++;
+ return __serviceId;
+ }
+
+ Map _toJSON(bool ref);
+
+ String get _servicePath => "$_serviceTypePath/$_serviceId";
+
+ String get _serviceTypePath;
+
+ String get _serviceTypeName;
+
+ String _serviceType(bool ref) {
+ if (ref) return "@$_serviceTypeName";
+ return _serviceTypeName;
+ }
+}
diff --git a/sdk_nnbd/lib/io/socket.dart b/sdk_nnbd/lib/io/socket.dart
new file mode 100644
index 0000000..df60490
--- /dev/null
+++ b/sdk_nnbd/lib/io/socket.dart
@@ -0,0 +1,1013 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * [InternetAddressType] is the type an [InternetAddress]. Currently,
+ * IP version 4 (IPv4) and IP version 6 (IPv6) are supported.
+ */
+class InternetAddressType {
+ static const InternetAddressType IPv4 = const InternetAddressType._(0);
+ static const InternetAddressType IPv6 = const InternetAddressType._(1);
+ static const InternetAddressType any = const InternetAddressType._(-1);
+
+ @Deprecated("Use IPv4 instead")
+ static const InternetAddressType IP_V4 = IPv4;
+ @Deprecated("Use IPv6 instead")
+ static const InternetAddressType IP_V6 = IPv6;
+ @Deprecated("Use any instead")
+ static const InternetAddressType ANY = any;
+
+ final int _value;
+
+ const InternetAddressType._(this._value);
+
+ factory InternetAddressType._from(int value) {
+ if (value == 0) return IPv4;
+ if (value == 1) return IPv6;
+ throw new ArgumentError("Invalid type: $value");
+ }
+
+ /**
+ * Get the name of the type, e.g. "IPv4" or "IPv6".
+ */
+ String get name {
+ switch (_value) {
+ case -1:
+ return "ANY";
+ case 0:
+ return "IPv4";
+ case 1:
+ return "IPv6";
+ default:
+ throw new ArgumentError("Invalid InternetAddress");
+ }
+ }
+
+ String toString() => "InternetAddressType: $name";
+}
+
+/**
+ * An internet address.
+ *
+ * This object holds an internet address. If this internet address
+ * is the result of a DNS lookup, the address also holds the hostname
+ * used to make the lookup.
+ * An Internet address combined with a port number represents an
+ * endpoint to which a socket can connect or a listening socket can
+ * bind.
+ */
+abstract class InternetAddress {
+ /**
+ * IP version 4 loopback address. Use this address when listening on
+ * or connecting to the loopback adapter using IP version 4 (IPv4).
+ */
+ static InternetAddress get loopbackIPv4 => LOOPBACK_IP_V4;
+ @Deprecated("Use loopbackIPv4 instead")
+ external static InternetAddress get LOOPBACK_IP_V4;
+
+ /**
+ * IP version 6 loopback address. Use this address when listening on
+ * or connecting to the loopback adapter using IP version 6 (IPv6).
+ */
+ static InternetAddress get loopbackIPv6 => LOOPBACK_IP_V6;
+ @Deprecated("Use loopbackIPv6 instead")
+ external static InternetAddress get LOOPBACK_IP_V6;
+
+ /**
+ * IP version 4 any address. Use this address when listening on
+ * all adapters IP addresses using IP version 4 (IPv4).
+ */
+ static InternetAddress get anyIPv4 => ANY_IP_V4;
+ @Deprecated("Use anyIPv4 instead")
+ external static InternetAddress get ANY_IP_V4;
+
+ /**
+ * IP version 6 any address. Use this address when listening on
+ * all adapters IP addresses using IP version 6 (IPv6).
+ */
+ static InternetAddress get anyIPv6 => ANY_IP_V6;
+ @Deprecated("Use anyIPv6 instead")
+ external static InternetAddress get ANY_IP_V6;
+
+ /**
+ * The [type] of the [InternetAddress] specified what IP protocol.
+ */
+ InternetAddressType get type;
+
+ /**
+ * The numeric address of the host. For IPv4 addresses this is using
+ * the dotted-decimal notation. For IPv6 it is using the
+ * hexadecimal representation.
+ */
+ String get address;
+
+ /**
+ * The host used to lookup the address. If there is no host
+ * associated with the address this returns the numeric address.
+ */
+ String get host;
+
+ /**
+ * Get the raw address of this [InternetAddress]. The result is either a
+ * 4 or 16 byte long list. The returned list is a copy, making it possible
+ * to change the list without modifying the [InternetAddress].
+ */
+ Uint8List get rawAddress;
+
+ /**
+ * Returns true if the [InternetAddress] is a loopback address.
+ */
+ bool get isLoopback;
+
+ /**
+ * Returns true if the [InternetAddress]s scope is a link-local.
+ */
+ bool get isLinkLocal;
+
+ /**
+ * Returns true if the [InternetAddress]s scope is multicast.
+ */
+ bool get isMulticast;
+
+ /**
+ * Creates a new [InternetAddress] from a numeric address.
+ *
+ * If the address in [address] is not a numeric IPv4
+ * (dotted-decimal notation) or IPv6 (hexadecimal representation).
+ * address [ArgumentError] is thrown.
+ */
+ external factory InternetAddress(String address);
+
+ /**
+ * Perform a reverse dns lookup on the [address], creating a new
+ * [InternetAddress] where the host field set to the result.
+ */
+ Future<InternetAddress> reverse();
+
+ /**
+ * Lookup a host, returning a Future of a list of
+ * [InternetAddress]s. If [type] is [InternetAddressType.ANY], it
+ * will lookup both IP version 4 (IPv4) and IP version 6 (IPv6)
+ * addresses. If [type] is either [InternetAddressType.IPv4] or
+ * [InternetAddressType.IPv6] it will only lookup addresses of the
+ * specified type. The order of the list can, and most likely will,
+ * change over time.
+ */
+ external static Future<List<InternetAddress>> lookup(String host,
+ {InternetAddressType type: InternetAddressType.any});
+
+ /**
+ * Clones the given [address] with the new [host].
+ *
+ * The [address] must be an [InternetAddress] that was created with one
+ * of the static methods of this class.
+ */
+ external static InternetAddress _cloneWithNewHost(
+ InternetAddress address, String host);
+}
+
+/**
+ * A [NetworkInterface] represents an active network interface on the current
+ * system. It contains a list of [InternetAddress]es that are bound to the
+ * interface.
+ */
+abstract class NetworkInterface {
+ /**
+ * Get the name of the [NetworkInterface].
+ */
+ String get name;
+
+ /**
+ * Get the index of the [NetworkInterface].
+ */
+ int get index;
+
+ /**
+ * Get a list of [InternetAddress]es currently bound to this
+ * [NetworkInterface].
+ */
+ List<InternetAddress> get addresses;
+
+ /**
+ * Whether [list] is supported.
+ *
+ * [list] is currently unsupported on Android.
+ */
+ external static bool get listSupported;
+
+ /**
+ * Query the system for [NetworkInterface]s.
+ *
+ * If [includeLoopback] is `true`, the returned list will include the
+ * loopback device. Default is `false`.
+ *
+ * If [includeLinkLocal] is `true`, the list of addresses of the returned
+ * [NetworkInterface]s, may include link local addresses. Default is `false`.
+ *
+ * If [type] is either [InternetAddressType.IPv4] or
+ * [InternetAddressType.IPv6] it will only lookup addresses of the
+ * specified type. Default is [InternetAddressType.any].
+ */
+ external static Future<List<NetworkInterface>> list(
+ {bool includeLoopback: false,
+ bool includeLinkLocal: false,
+ InternetAddressType type: InternetAddressType.any});
+}
+
+/**
+ * A [RawServerSocket] represents a listening socket, and provides a
+ * stream of low-level [RawSocket] objects, one for each connection
+ * made to the listening socket.
+ *
+ * See [RawSocket] for more info.
+ */
+abstract class RawServerSocket implements Stream<RawSocket> {
+ /**
+ * Returns a future for a [:RawServerSocket:]. When the future
+ * completes the server socket is bound to the given [address] and
+ * [port] and has started listening on it.
+ *
+ * The [address] can either be a [String] or an
+ * [InternetAddress]. If [address] is a [String], [bind] will
+ * perform a [InternetAddress.lookup] and use the first value in the
+ * list. To listen on the loopback adapter, which will allow only
+ * incoming connections from the local host, use the value
+ * [InternetAddress.loopbackIPv4] or
+ * [InternetAddress.loopbackIPv6]. To allow for incoming
+ * connection from the network use either one of the values
+ * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+ * bind to all interfaces or the IP address of a specific interface.
+ *
+ * If an IP version 6 (IPv6) address is used, both IP version 6
+ * (IPv6) and version 4 (IPv4) connections will be accepted. To
+ * restrict this to version 6 (IPv6) only, use [v6Only] to set
+ * version 6 only.
+ *
+ * If [port] has the value [:0:] an ephemeral port will
+ * be chosen by the system. The actual port used can be retrieved
+ * using the [:port:] getter.
+ *
+ * The optional argument [backlog] can be used to specify the listen
+ * backlog for the underlying OS listen setup. If [backlog] has the
+ * value of [:0:] (the default) a reasonable value will be chosen by
+ * the system.
+ *
+ * The optional argument [shared] specifies whether additional RawServerSocket
+ * objects can bind to the same combination of `address`, `port` and `v6Only`.
+ * If `shared` is `true` and more `RawServerSocket`s from this isolate or
+ * other isolates are bound to the port, then the incoming connections will be
+ * distributed among all the bound `RawServerSocket`s. Connections can be
+ * distributed over multiple isolates this way.
+ */
+ external static Future<RawServerSocket> bind(address, int port,
+ {int backlog: 0, bool v6Only: false, bool shared: false});
+
+ /**
+ * Returns the port used by this socket.
+ */
+ int get port;
+
+ /**
+ * Returns the address used by this socket.
+ */
+ InternetAddress get address;
+
+ /**
+ * Closes the socket. The returned future completes when the socket
+ * is fully closed and is no longer bound.
+ */
+ Future<RawServerSocket> close();
+}
+
+/**
+ * A [ServerSocket] represents a listening socket, and provides a
+ * stream of [Socket] objects, one for each connection made to the
+ * listening socket.
+ *
+ * See [Socket] for more info.
+ */
+abstract class ServerSocket implements Stream<Socket> {
+ /**
+ * Returns a future for a [:ServerSocket:]. When the future
+ * completes the server socket is bound to the given [address] and
+ * [port] and has started listening on it.
+ *
+ * The [address] can either be a [String] or an
+ * [InternetAddress]. If [address] is a [String], [bind] will
+ * perform a [InternetAddress.lookup] and use the first value in the
+ * list. To listen on the loopback adapter, which will allow only
+ * incoming connections from the local host, use the value
+ * [InternetAddress.loopbackIPv4] or
+ * [InternetAddress.loopbackIPv6]. To allow for incoming
+ * connection from the network use either one of the values
+ * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
+ * bind to all interfaces or the IP address of a specific interface.
+ *
+ * If an IP version 6 (IPv6) address is used, both IP version 6
+ * (IPv6) and version 4 (IPv4) connections will be accepted. To
+ * restrict this to version 6 (IPv6) only, use [v6Only] to set
+ * version 6 only.
+ *
+ * If [port] has the value [:0:] an ephemeral port will be chosen by
+ * the system. The actual port used can be retrieved using the
+ * [port] getter.
+ *
+ * The optional argument [backlog] can be used to specify the listen
+ * backlog for the underlying OS listen setup. If [backlog] has the
+ * value of [:0:] (the default) a reasonable value will be chosen by
+ * the system.
+ *
+ * The optional argument [shared] specifies whether additional ServerSocket
+ * objects can bind to the same combination of `address`, `port` and `v6Only`.
+ * If `shared` is `true` and more `ServerSocket`s from this isolate or other
+ * isolates are bound to the port, then the incoming connections will be
+ * distributed among all the bound `ServerSocket`s. Connections can be
+ * distributed over multiple isolates this way.
+ */
+ external static Future<ServerSocket> bind(address, int port,
+ {int backlog: 0, bool v6Only: false, bool shared: false});
+
+ /**
+ * Returns the port used by this socket.
+ */
+ int get port;
+
+ /**
+ * Returns the address used by this socket.
+ */
+ InternetAddress get address;
+
+ /**
+ * Closes the socket. The returned future completes when the socket
+ * is fully closed and is no longer bound.
+ */
+ Future<ServerSocket> close();
+}
+
+/**
+ * The [SocketDirection] is used as a parameter to [Socket.close] and
+ * [RawSocket.close] to close a socket in the specified direction(s).
+ */
+class SocketDirection {
+ static const SocketDirection receive = const SocketDirection._(0);
+ static const SocketDirection send = const SocketDirection._(1);
+ static const SocketDirection both = const SocketDirection._(2);
+
+ @Deprecated("Use receive instead")
+ static const SocketDirection RECEIVE = receive;
+ @Deprecated("Use send instead")
+ static const SocketDirection SEND = send;
+ @Deprecated("Use both instead")
+ static const SocketDirection BOTH = both;
+
+ final _value;
+
+ const SocketDirection._(this._value);
+}
+
+/**
+ * The [SocketOption] is used as a parameter to [Socket.setOption] and
+ * [RawSocket.setOption] to set customize the behaviour of the underlying
+ * socket.
+ */
+class SocketOption {
+ /**
+ * Enable or disable no-delay on the socket. If tcpNoDelay is enabled, the
+ * socket will not buffer data internally, but instead write each data chunk
+ * as an individual TCP packet.
+ *
+ * tcpNoDelay is disabled by default.
+ */
+ static const SocketOption tcpNoDelay = const SocketOption._(0);
+ @Deprecated("Use tcpNoDelay instead")
+ static const SocketOption TCP_NODELAY = tcpNoDelay;
+
+ static const SocketOption _ipMulticastLoop = const SocketOption._(1);
+ static const SocketOption _ipMulticastHops = const SocketOption._(2);
+ static const SocketOption _ipMulticastIf = const SocketOption._(3);
+ static const SocketOption _ipBroadcast = const SocketOption._(4);
+
+ final _value;
+
+ const SocketOption._(this._value);
+}
+
+// Must be kept in sync with enum in socket.cc
+enum _RawSocketOptions {
+ SOL_SOCKET, // 0
+ IPPROTO_IP, // 1
+ IP_MULTICAST_IF, // 2
+ IPPROTO_IPV6, // 3
+ IPV6_MULTICAST_IF, // 4
+ IPPROTO_TCP, // 5
+ IPPROTO_UDP, // 6
+}
+
+/// The [RawSocketOption] is used as a parameter to [Socket.setRawOption] and
+/// [RawSocket.setRawOption] to set customize the behaviour of the underlying
+/// socket.
+///
+/// It allows for fine grained control of the socket options, and its values will
+/// be passed to the underlying platform's implementation of setsockopt and
+/// getsockopt.
+@Since("2.2")
+class RawSocketOption {
+ /// Creates a RawSocketOption for getRawOption andSetRawOption.
+ ///
+ /// All arguments are required and must not be null.
+ ///
+ /// The level and option arguments correspond to level and optname arguments
+ /// on the get/setsockopt native calls.
+ ///
+ /// The value argument and its length correspond to the optval and length
+ /// arguments on the native call.
+ ///
+ /// For a [getRawOption] call, the value parameter will be updated after a
+ /// successful call (although its length will not be changed).
+ ///
+ /// For a [setRawOption] call, the value parameter will be used set the
+ /// option.
+ const RawSocketOption(this.level, this.option, this.value);
+
+ /// Convenience constructor for creating an int based RawSocketOption.
+ factory RawSocketOption.fromInt(int level, int option, int value) {
+ if (value == null) {
+ value = 0;
+ }
+ final Uint8List list = Uint8List(4);
+ final buffer = ByteData.view(list.buffer);
+ buffer.setInt32(0, value);
+ return RawSocketOption(level, option, list);
+ }
+
+ /// Convenience constructor for creating a bool based RawSocketOption.
+ factory RawSocketOption.fromBool(int level, int option, bool value) =>
+ RawSocketOption.fromInt(level, option, value == true ? 1 : 0);
+
+ /// The level for the option to set or get.
+ ///
+ /// See also:
+ /// * [RawSocketOption.levelSocket]
+ /// * [RawSocketOption.levelIPv4]
+ /// * [RawSocketOption.levelIPv6]
+ /// * [RawSocketOption.levelTcp]
+ /// * [RawSocketOption.levelUdp]
+ final int level;
+
+ /// The option to set or get.
+ final int option;
+
+ /// The raw data to set, or the array to write the current option value into.
+ ///
+ /// This list must be the correct length for the expected option. For most
+ /// options that take int or bool values, the length should be 4. For options
+ /// that expect a struct (such as an in_addr_t), the length should be the
+ /// correct length for that struct.
+ final Uint8List value;
+
+ /// Socket level option for SOL_SOCKET.
+ static int get levelSocket =>
+ _getOptionValue(_RawSocketOptions.SOL_SOCKET.index);
+
+ /// Socket level option for IPPROTO_IP.
+ static int get levelIPv4 =>
+ _getOptionValue(_RawSocketOptions.IPPROTO_IP.index);
+
+ /// Socket option for IP_MULTICAST_IF.
+ static int get IPv4MulticastInterface =>
+ _getOptionValue(_RawSocketOptions.IP_MULTICAST_IF.index);
+
+ /// Socket level option for IPPROTO_IPV6.
+ static int get levelIPv6 =>
+ _getOptionValue(_RawSocketOptions.IPPROTO_IPV6.index);
+
+ /// Socket option for IPV6_MULTICAST_IF.
+ static int get IPv6MulticastInterface =>
+ _getOptionValue(_RawSocketOptions.IPV6_MULTICAST_IF.index);
+
+ /// Socket level option for IPPROTO_TCP.
+ static int get levelTcp =>
+ _getOptionValue(_RawSocketOptions.IPPROTO_TCP.index);
+
+ /// Socket level option for IPPROTO_UDP.
+ static int get levelUdp =>
+ _getOptionValue(_RawSocketOptions.IPPROTO_UDP.index);
+
+ external static int _getOptionValue(int key);
+}
+
+/**
+ * Events for the [RawSocket].
+ */
+class RawSocketEvent {
+ static const RawSocketEvent read = const RawSocketEvent._(0);
+ static const RawSocketEvent write = const RawSocketEvent._(1);
+ static const RawSocketEvent readClosed = const RawSocketEvent._(2);
+ static const RawSocketEvent closed = const RawSocketEvent._(3);
+
+ @Deprecated("Use read instead")
+ static const RawSocketEvent READ = read;
+ @Deprecated("Use write instead")
+ static const RawSocketEvent WRITE = write;
+ @Deprecated("Use readClosed instead")
+ static const RawSocketEvent READ_CLOSED = readClosed;
+ @Deprecated("Use closed instead")
+ static const RawSocketEvent CLOSED = closed;
+
+ final int _value;
+
+ const RawSocketEvent._(this._value);
+ String toString() {
+ return const [
+ 'RawSocketEvent.read',
+ 'RawSocketEvent.write',
+ 'RawSocketEvent.readClosed',
+ 'RawSocketEvent.closed'
+ ][_value];
+ }
+}
+
+/// Returned by the `startConnect` methods on client-side socket types `S`,
+/// `ConnectionTask<S>` allows cancelling an attempt to connect to a host.
+class ConnectionTask<S> {
+ /// A `Future` that completes with value that `S.connect()` would return
+ /// unless [cancel] is called on this [ConnectionTask].
+ ///
+ /// If [cancel] is called, the `Future` completes with a [SocketException]
+ /// error whose message indicates that the connection attempt was cancelled.
+ final Future<S> socket;
+ final void Function() _onCancel;
+
+ ConnectionTask._({Future<S> socket, void Function() onCancel})
+ : assert(socket != null),
+ assert(onCancel != null),
+ this.socket = socket,
+ this._onCancel = onCancel;
+
+ /// Cancels the connection attempt.
+ ///
+ /// This also causes the [socket] `Future` to complete with a
+ /// [SocketException] error.
+ void cancel() {
+ _onCancel();
+ }
+}
+
+/**
+ * A [RawSocket] is an unbuffered interface to a TCP socket.
+ *
+ * The raw socket delivers the data stream in the same chunks as the underlying
+ * operating system.
+ *
+ * It is not the same as a
+ * [POSIX raw socket](http://man7.org/linux/man-pages/man7/raw.7.html).
+ */
+abstract class RawSocket implements Stream<RawSocketEvent> {
+ /**
+ * Set or get, if the [RawSocket] should listen for [RawSocketEvent.read]
+ * events. Default is [:true:].
+ */
+ bool readEventsEnabled;
+
+ /**
+ * Set or get, if the [RawSocket] should listen for [RawSocketEvent.write]
+ * events. Default is [:true:].
+ * This is a one-shot listener, and writeEventsEnabled must be set
+ * to true again to receive another write event.
+ */
+ bool writeEventsEnabled;
+
+ /**
+ * Creates a new socket connection to the host and port and returns a [Future]
+ * that will complete with either a [RawSocket] once connected or an error
+ * if the host-lookup or connection failed.
+ *
+ * [host] can either be a [String] or an [InternetAddress]. If [host] is a
+ * [String], [connect] will perform a [InternetAddress.lookup] and try
+ * all returned [InternetAddress]es, until connected. Unless a
+ * connection was established, the error from the first failing connection is
+ * returned.
+ *
+ * The argument [sourceAddress] can be used to specify the local
+ * address to bind when making the connection. `sourceAddress` can either
+ * be a `String` or an `InternetAddress`. If a `String` is passed it must
+ * hold a numeric IP address.
+ *
+ * The argument [timeout] is used to specify the maximum allowed time to wait
+ * for a connection to be established. If [timeout] is longer than the system
+ * level timeout duration, a timeout may occur sooner than specified in
+ * [timeout]. On timeout, a [SocketException] is thrown and all ongoing
+ * connection attempts to [host] are cancelled.
+ */
+ external static Future<RawSocket> connect(host, int port,
+ {sourceAddress, Duration timeout});
+
+ /// Like [connect], but returns a [Future] that completes with a
+ /// [ConnectionTask] that can be cancelled if the [RawSocket] is no
+ /// longer needed.
+ external static Future<ConnectionTask<RawSocket>> startConnect(host, int port,
+ {sourceAddress});
+
+ /**
+ * Returns the number of received and non-read bytes in the socket that
+ * can be read.
+ */
+ int available();
+
+ /**
+ * Read up to [len] bytes from the socket. This function is
+ * non-blocking and will only return data if data is available. The
+ * number of bytes read can be less then [len] if fewer bytes are
+ * available for immediate reading. If no data is available [:null:]
+ * is returned.
+ */
+ Uint8List read([int len]);
+
+ /**
+ * Writes up to [count] bytes of the buffer from [offset] buffer offset to
+ * the socket. The number of successfully written bytes is returned. This
+ * function is non-blocking and will only write data if buffer space is
+ * available in the socket.
+ *
+ * The default value for [offset] is 0, and the default value for [count] is
+ * [:buffer.length - offset:].
+ */
+ int write(List<int> buffer, [int offset, int count]);
+
+ /**
+ * Returns the port used by this socket.
+ */
+ int get port;
+
+ /**
+ * Returns the remote port connected to by this socket.
+ */
+ int get remotePort;
+
+ /**
+ * Returns the [InternetAddress] used to connect this socket.
+ */
+ InternetAddress get address;
+
+ /**
+ * Returns the remote [InternetAddress] connected to by this socket.
+ */
+ InternetAddress get remoteAddress;
+
+ /**
+ * Closes the socket. Returns a Future that completes with [this] when the
+ * underlying connection is completely destroyed.
+ *
+ * Calling [close] will never throw an exception
+ * and calling it several times is supported. Calling [close] can result in
+ * a [RawSocketEvent.readClosed] event.
+ */
+ Future<RawSocket> close();
+
+ /**
+ * Shutdown the socket in the [direction]. Calling [shutdown] will never
+ * throw an exception and calling it several times is supported. Calling
+ * shutdown with either [SocketDirection.both] or [SocketDirection.receive]
+ * can result in a [RawSocketEvent.readClosed] event.
+ */
+ void shutdown(SocketDirection direction);
+
+ /**
+ * Use [setOption] to customize the [RawSocket]. See [SocketOption] for
+ * available options.
+ *
+ * Returns [:true:] if the option was set successfully, false otherwise.
+ */
+ bool setOption(SocketOption option, bool enabled);
+
+ /**
+ * Use [getRawOption] to get low level information about the [RawSocket]. See
+ * [RawSocketOption] for available options.
+ *
+ * Returns the [RawSocketOption.value] on success.
+ *
+ * Throws an [OSError] on failure.
+ */
+ @Since("2.2")
+ Uint8List getRawOption(RawSocketOption option);
+
+ /**
+ * Use [setRawOption] to customize the [RawSocket]. See [RawSocketOption] for
+ * available options.
+ *
+ * Throws an [OSError] on failure.
+ */
+ @Since("2.2")
+ void setRawOption(RawSocketOption option);
+}
+
+/**
+ * A high-level class for communicating over a TCP socket.
+ *
+ * The [Socket] exposes both a [Stream] and a [IOSink] interface, making it
+ * ideal for using together with other [Stream]s.
+ */
+abstract class Socket implements Stream<Uint8List>, IOSink {
+ /**
+ * Creates a new socket connection to the host and port and returns a [Future]
+ * that will complete with either a [Socket] once connected or an error
+ * if the host-lookup or connection failed.
+ *
+ * [host] can either be a [String] or an [InternetAddress]. If [host] is a
+ * [String], [connect] will perform a [InternetAddress.lookup] and try
+ * all returned [InternetAddress]es, until connected. Unless a
+ * connection was established, the error from the first failing connection is
+ * returned.
+ *
+ * The argument [sourceAddress] can be used to specify the local
+ * address to bind when making the connection. `sourceAddress` can either
+ * be a `String` or an `InternetAddress`. If a `String` is passed it must
+ * hold a numeric IP address.
+ *
+ * The argument [timeout] is used to specify the maximum allowed time to wait
+ * for a connection to be established. If [timeout] is longer than the system
+ * level timeout duration, a timeout may occur sooner than specified in
+ * [timeout]. On timeout, a [SocketException] is thrown and all ongoing
+ * connection attempts to [host] are cancelled.
+ */
+ static Future<Socket> connect(host, int port,
+ {sourceAddress, Duration timeout}) {
+ final IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return Socket._connect(host, port,
+ sourceAddress: sourceAddress, timeout: timeout);
+ }
+ return overrides.socketConnect(host, port,
+ sourceAddress: sourceAddress, timeout: timeout);
+ }
+
+ /// Like [connect], but returns a [Future] that completes with a
+ /// [ConnectionTask] that can be cancelled if the [Socket] is no
+ /// longer needed.
+ static Future<ConnectionTask<Socket>> startConnect(host, int port,
+ {sourceAddress}) {
+ final IOOverrides overrides = IOOverrides.current;
+ if (overrides == null) {
+ return Socket._startConnect(host, port, sourceAddress: sourceAddress);
+ }
+ return overrides.socketStartConnect(host, port,
+ sourceAddress: sourceAddress);
+ }
+
+ external static Future<Socket> _connect(host, int port,
+ {sourceAddress, Duration timeout});
+
+ external static Future<ConnectionTask<Socket>> _startConnect(host, int port,
+ {sourceAddress});
+
+ /**
+ * Destroy the socket in both directions. Calling [destroy] will make the
+ * send a close event on the stream and will no longer react on data being
+ * piped to it.
+ *
+ * Call [close](inherited from [IOSink]) to only close the [Socket]
+ * for sending data.
+ */
+ void destroy();
+
+ /**
+ * Use [setOption] to customize the [RawSocket]. See [SocketOption] for
+ * available options.
+ *
+ * Returns [:true:] if the option was set successfully, false otherwise.
+ */
+ bool setOption(SocketOption option, bool enabled);
+
+ /**
+ * Use [getRawOption] to get low level information about the [RawSocket]. See
+ * [RawSocketOption] for available options.
+ *
+ * Returns the [RawSocketOption.value] on success.
+ *
+ * Throws an [OSError] on failure.
+ */
+ Uint8List getRawOption(RawSocketOption option);
+
+ /**
+ * Use [setRawOption] to customize the [RawSocket]. See [RawSocketOption] for
+ * available options.
+ *
+ * Throws an [OSError] on failure.
+ */
+ void setRawOption(RawSocketOption option);
+
+ /**
+ * Returns the port used by this socket.
+ */
+ int get port;
+
+ /**
+ * Returns the remote port connected to by this socket.
+ */
+ int get remotePort;
+
+ /**
+ * Returns the [InternetAddress] used to connect this socket.
+ */
+ InternetAddress get address;
+
+ /**
+ * Returns the remote [InternetAddress] connected to by this socket.
+ */
+ InternetAddress get remoteAddress;
+
+ Future close();
+
+ Future get done;
+}
+
+/**
+ * Datagram package. Data sent to and received from datagram sockets
+ * contains the internet address and port of the destination or source
+ * togeter with the data.
+ */
+class Datagram {
+ Uint8List data;
+ InternetAddress address;
+ int port;
+
+ Datagram(this.data, this.address, this.port);
+}
+
+/**
+ * A [RawDatagramSocket] is an unbuffered interface to a UDP socket.
+ *
+ * The raw datagram socket delivers the datagrams in the same chunks as the
+ * underlying operating system. It's a [Stream] of [RawSocketEvent]s.
+ *
+ * Note that the event [RawSocketEvent.readClosed] will never be
+ * received as an UDP socket cannot be closed by a remote peer.
+ *
+ * It is not the same as a
+ * [POSIX raw socket](http://man7.org/linux/man-pages/man7/raw.7.html).
+ */
+abstract class RawDatagramSocket extends Stream<RawSocketEvent> {
+ /**
+ * Set or get, if the [RawDatagramSocket] should listen for
+ * [RawSocketEvent.read] events. Default is [:true:].
+ */
+ bool readEventsEnabled;
+
+ /**
+ * Set or get, if the [RawDatagramSocket] should listen for
+ * [RawSocketEvent.write] events. Default is [:true:]. This is a
+ * one-shot listener, and writeEventsEnabled must be set to true
+ * again to receive another write event.
+ */
+ bool writeEventsEnabled;
+
+ /**
+ * Set or get, whether multicast traffic is looped back to the host.
+ *
+ * By default multicast loopback is enabled.
+ */
+ bool multicastLoopback;
+
+ /**
+ * Set or get, the maximum network hops for multicast packages
+ * originating from this socket.
+ *
+ * For IPv4 this is referred to as TTL (time to live).
+ *
+ * By default this value is 1 causing multicast traffic to stay on
+ * the local network.
+ */
+ int multicastHops;
+
+ /**
+ * Set or get, the network interface used for outgoing multicast packages.
+ *
+ * A value of `null`indicate that the system chooses the network
+ * interface to use.
+ *
+ * By default this value is `null`
+ */
+ @Deprecated("This property is not implemented. Use getRawOption and "
+ "setRawOption instead.")
+ NetworkInterface multicastInterface;
+
+ /**
+ * Set or get, whether IPv4 broadcast is enabled.
+ *
+ * IPv4 broadcast needs to be enabled by the sender for sending IPv4
+ * broadcast packages. By default IPv4 broadcast is disabled.
+ *
+ * For IPv6 there is no general broadcast mechanism. Use multicast
+ * instead.
+ */
+ bool broadcastEnabled;
+
+ /**
+ * Creates a new raw datagram socket binding it to an address and
+ * port.
+ */
+ external static Future<RawDatagramSocket> bind(host, int port,
+ {bool reuseAddress: true, bool reusePort: false, int ttl: 1});
+
+ /**
+ * Returns the port used by this socket.
+ */
+ int get port;
+
+ /**
+ * Returns the address used by this socket.
+ */
+ InternetAddress get address;
+
+ /**
+ * Close the datagram socket.
+ */
+ void close();
+
+ /**
+ * Send a datagram.
+ *
+ * Returns the number of bytes written. This will always be either
+ * the size of [buffer] or `0`.
+ */
+ int send(List<int> buffer, InternetAddress address, int port);
+
+ /**
+ * Receive a datagram. If there are no datagrams available `null` is
+ * returned.
+ *
+ * The maximum length of the datagram that can be received is 65503 bytes.
+ */
+ Datagram receive();
+
+ /**
+ * Join a multicast group.
+ *
+ * If an error occur when trying to join the multicast group an
+ * exception is thrown.
+ */
+ void joinMulticast(InternetAddress group, [NetworkInterface interface]);
+
+ /**
+ * Leave a multicast group.
+ *
+ * If an error occur when trying to join the multicase group an
+ * exception is thrown.
+ */
+ void leaveMulticast(InternetAddress group, [NetworkInterface interface]);
+
+ /**
+ * Use [getRawOption] to get low level information about the [RawSocket]. See
+ * [RawSocketOption] for available options.
+ *
+ * Returns [RawSocketOption.value] on success.
+ *
+ * Throws an [OSError] on failure.
+ */
+ Uint8List getRawOption(RawSocketOption option);
+
+ /**
+ * Use [setRawOption] to customize the [RawSocket]. See [RawSocketOption] for
+ * available options.
+ *
+ * Throws an [OSError] on failure.
+ */
+ void setRawOption(RawSocketOption option);
+}
+
+class SocketException implements IOException {
+ final String message;
+ final OSError osError;
+ final InternetAddress address;
+ final int port;
+
+ const SocketException(this.message, {this.osError, this.address, this.port});
+ const SocketException.closed()
+ : message = 'Socket has been closed',
+ osError = null,
+ address = null,
+ port = null;
+
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.write("SocketException");
+ if (message.isNotEmpty) {
+ sb.write(": $message");
+ if (osError != null) {
+ sb.write(" ($osError)");
+ }
+ } else if (osError != null) {
+ sb.write(": $osError");
+ }
+ if (address != null) {
+ sb.write(", address = ${address.host}");
+ }
+ if (port != null) {
+ sb.write(", port = $port");
+ }
+ return sb.toString();
+ }
+}
diff --git a/sdk_nnbd/lib/io/stdio.dart b/sdk_nnbd/lib/io/stdio.dart
new file mode 100644
index 0000000..4086f08
--- /dev/null
+++ b/sdk_nnbd/lib/io/stdio.dart
@@ -0,0 +1,480 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+const int _stdioHandleTypeTerminal = 0;
+const int _stdioHandleTypePipe = 1;
+const int _stdioHandleTypeFile = 2;
+const int _stdioHandleTypeSocket = 3;
+const int _stdioHandleTypeOther = 4;
+
+class _StdStream extends Stream<List<int>> {
+ final Stream<List<int>> _stream;
+
+ _StdStream(this._stream);
+
+ StreamSubscription<List<int>> listen(void onData(List<int> event),
+ {Function onError, void onDone(), bool cancelOnError}) {
+ return _stream.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+}
+
+/**
+ * [Stdin] allows both synchronous and asynchronous reads from the standard
+ * input stream.
+ *
+ * Mixing synchronous and asynchronous reads is undefined.
+ */
+class Stdin extends _StdStream implements Stream<List<int>> {
+ int _fd;
+
+ Stdin._(Stream<List<int>> stream, this._fd) : super(stream);
+
+ /**
+ * Read a line from stdin.
+ *
+ * Blocks until a full line is available.
+ *
+ * Lines my be terminated by either `<CR><LF>` or `<LF>`. On Windows in cases
+ * where the [stdioType] of stdin is [StdioType.termimal] the terminator may
+ * also be a single `<CR>`.
+ *
+ * Input bytes are converted to a string by [encoding].
+ * If [encoding] is omitted, it defaults to [systemEncoding].
+ *
+ * If [retainNewlines] is `false`, the returned String will not include the
+ * final line terminator. If `true`, the returned String will include the line
+ * terminator. Default is `false`.
+ *
+ * If end-of-file is reached after any bytes have been read from stdin,
+ * that data is returned without a line terminator.
+ * Returns `null` if no bytes preceded the end of input.
+ */
+ String readLineSync(
+ {Encoding encoding: systemEncoding, bool retainNewlines: false}) {
+ const CR = 13;
+ const LF = 10;
+ final List<int> line = <int>[];
+ // On Windows, if lineMode is disabled, only CR is received.
+ bool crIsNewline = Platform.isWindows &&
+ (stdioType(stdin) == StdioType.terminal) &&
+ !lineMode;
+ if (retainNewlines) {
+ int byte;
+ do {
+ byte = readByteSync();
+ if (byte < 0) {
+ break;
+ }
+ line.add(byte);
+ } while (byte != LF && !(byte == CR && crIsNewline));
+ if (line.isEmpty) {
+ return null;
+ }
+ } else if (crIsNewline) {
+ // CR and LF are both line terminators, neither is retained.
+ while (true) {
+ int byte = readByteSync();
+ if (byte < 0) {
+ if (line.isEmpty) return null;
+ break;
+ }
+ if (byte == LF || byte == CR) break;
+ line.add(byte);
+ }
+ } else {
+ // Case having to handle CR LF as a single unretained line terminator.
+ outer:
+ while (true) {
+ int byte = readByteSync();
+ if (byte == LF) break;
+ if (byte == CR) {
+ do {
+ byte = readByteSync();
+ if (byte == LF) break outer;
+
+ line.add(CR);
+ } while (byte == CR);
+ // Fall through and handle non-CR character.
+ }
+ if (byte < 0) {
+ if (line.isEmpty) return null;
+ break;
+ }
+ line.add(byte);
+ }
+ }
+ return encoding.decode(line);
+ }
+
+ /**
+ * Check if echo mode is enabled on [stdin].
+ */
+ external bool get echoMode;
+
+ /**
+ * Enable or disable echo mode on [stdin].
+ *
+ * If disabled, input from to console will not be echoed.
+ *
+ * Default depends on the parent process, but usually enabled.
+ *
+ * On Windows this mode can only be enabled if [lineMode] is enabled as well.
+ */
+ external void set echoMode(bool enabled);
+
+ /**
+ * Check if line mode is enabled on [stdin].
+ */
+ external bool get lineMode;
+
+ /**
+ * Enable or disable line mode on [stdin].
+ *
+ * If enabled, characters are delayed until a new-line character is entered.
+ * If disabled, characters will be available as typed.
+ *
+ * Default depends on the parent process, but usually enabled.
+ *
+ * On Windows this mode can only be disabled if [echoMode] is disabled as well.
+ */
+ external void set lineMode(bool enabled);
+
+ /**
+ * Whether connected to a terminal that supports ANSI escape sequences.
+ *
+ * Not all terminals are recognized, and not all recognized terminals can
+ * report whether they support ANSI escape sequences, so this value is a
+ * best-effort attempt at detecting the support.
+ *
+ * The actual escape sequence support may differ between terminals,
+ * with some terminals supporting more escape sequences than others,
+ * and some terminals even differing in behavior for the same escape
+ * sequence.
+ *
+ * The ANSI color selection is generally supported.
+ *
+ * Currently, a `TERM` environment variable containing the string `xterm`
+ * will be taken as evidence that ANSI escape sequences are supported.
+ * On Windows, only versions of Windows 10 after v.1511
+ * ("TH2", OS build 10586) will be detected as supporting the output of
+ * ANSI escape sequences, and only versions after v.1607 ("Anniversary
+ * Update", OS build 14393) will be detected as supporting the input of
+ * ANSI escape sequences.
+ */
+ external bool get supportsAnsiEscapes;
+
+ /**
+ * Synchronously read a byte from stdin. This call will block until a byte is
+ * available.
+ *
+ * If at end of file, -1 is returned.
+ */
+ external int readByteSync();
+
+ /**
+ * Returns true if there is a terminal attached to stdin.
+ */
+ bool get hasTerminal {
+ try {
+ return stdioType(this) == StdioType.terminal;
+ } on FileSystemException catch (_) {
+ // If stdioType throws a FileSystemException, then it is not hooked up to
+ // a terminal, probably because it is closed, but let other exception
+ // types bubble up.
+ return false;
+ }
+ }
+}
+
+/**
+ * [Stdout] represents the [IOSink] for either `stdout` or `stderr`.
+ *
+ * It provides a *blocking* `IOSink`, so using this to write will block until
+ * the output is written.
+ *
+ * In some situations this blocking behavior is undesirable as it does not
+ * provide the same non-blocking behavior as dart:io in general exposes.
+ * Use the property [nonBlocking] to get an `IOSink` which has the non-blocking
+ * behavior.
+ *
+ * This class can also be used to check whether `stdout` or `stderr` is
+ * connected to a terminal and query some terminal properties.
+ *
+ * The [addError] API is inherited from [StreamSink] and calling it will result
+ * in an unhandled asynchronous error unless there is an error handler on
+ * [done].
+ */
+class Stdout extends _StdSink implements IOSink {
+ final int _fd;
+ IOSink _nonBlocking;
+
+ Stdout._(IOSink sink, this._fd) : super(sink);
+
+ /**
+ * Returns true if there is a terminal attached to stdout.
+ */
+ bool get hasTerminal => _hasTerminal(_fd);
+
+ /**
+ * Get the number of columns of the terminal.
+ *
+ * If no terminal is attached to stdout, a [StdoutException] is thrown. See
+ * [hasTerminal] for more info.
+ */
+ int get terminalColumns => _terminalColumns(_fd);
+
+ /**
+ * Get the number of lines of the terminal.
+ *
+ * If no terminal is attached to stdout, a [StdoutException] is thrown. See
+ * [hasTerminal] for more info.
+ */
+ int get terminalLines => _terminalLines(_fd);
+
+ /**
+ * Whether connected to a terminal that supports ANSI escape sequences.
+ *
+ * Not all terminals are recognized, and not all recognized terminals can
+ * report whether they support ANSI escape sequences, so this value is a
+ * best-effort attempt at detecting the support.
+ *
+ * The actual escape sequence support may differ between terminals,
+ * with some terminals supporting more escape sequences than others,
+ * and some terminals even differing in behavior for the same escape
+ * sequence.
+ *
+ * The ANSI color selection is generally supported.
+ *
+ * Currently, a `TERM` environment variable containing the string `xterm`
+ * will be taken as evidence that ANSI escape sequences are supported.
+ * On Windows, only versions of Windows 10 after v.1511
+ * ("TH2", OS build 10586) will be detected as supporting the output of
+ * ANSI escape sequences, and only versions after v.1607 ("Anniversary
+ * Update", OS build 14393) will be detected as supporting the input of
+ * ANSI escape sequences.
+ */
+ bool get supportsAnsiEscapes => _supportsAnsiEscapes(_fd);
+
+ external bool _hasTerminal(int fd);
+ external int _terminalColumns(int fd);
+ external int _terminalLines(int fd);
+ external static bool _supportsAnsiEscapes(int fd);
+
+ /**
+ * Get a non-blocking `IOSink`.
+ */
+ IOSink get nonBlocking {
+ _nonBlocking ??= new IOSink(new _FileStreamConsumer.fromStdio(_fd));
+ return _nonBlocking;
+ }
+}
+
+class StdoutException implements IOException {
+ final String message;
+ final OSError osError;
+
+ const StdoutException(this.message, [this.osError]);
+
+ String toString() {
+ return "StdoutException: $message${osError == null ? "" : ", $osError"}";
+ }
+}
+
+class StdinException implements IOException {
+ final String message;
+ final OSError osError;
+
+ const StdinException(this.message, [this.osError]);
+
+ String toString() {
+ return "StdinException: $message${osError == null ? "" : ", $osError"}";
+ }
+}
+
+class _StdConsumer implements StreamConsumer<List<int>> {
+ final _file;
+
+ _StdConsumer(int fd) : _file = _File._openStdioSync(fd);
+
+ Future addStream(Stream<List<int>> stream) {
+ var completer = new Completer();
+ var sub;
+ sub = stream.listen((data) {
+ try {
+ _file.writeFromSync(data);
+ } catch (e, s) {
+ sub.cancel();
+ completer.completeError(e, s);
+ }
+ },
+ onError: completer.completeError,
+ onDone: completer.complete,
+ cancelOnError: true);
+ return completer.future;
+ }
+
+ Future close() {
+ _file.closeSync();
+ return new Future.value();
+ }
+}
+
+class _StdSink implements IOSink {
+ final IOSink _sink;
+
+ _StdSink(this._sink);
+
+ Encoding get encoding => _sink.encoding;
+ void set encoding(Encoding encoding) {
+ _sink.encoding = encoding;
+ }
+
+ void write(object) {
+ _sink.write(object);
+ }
+
+ void writeln([object = ""]) {
+ _sink.writeln(object);
+ }
+
+ void writeAll(objects, [sep = ""]) {
+ _sink.writeAll(objects, sep);
+ }
+
+ void add(List<int> data) {
+ _sink.add(data);
+ }
+
+ void addError(error, [StackTrace stackTrace]) {
+ _sink.addError(error, stackTrace);
+ }
+
+ void writeCharCode(int charCode) {
+ _sink.writeCharCode(charCode);
+ }
+
+ Future addStream(Stream<List<int>> stream) => _sink.addStream(stream);
+ Future flush() => _sink.flush();
+ Future close() => _sink.close();
+ Future get done => _sink.done;
+}
+
+/// The type of object a standard IO stream is attached to.
+class StdioType {
+ static const StdioType terminal = const StdioType._("terminal");
+ static const StdioType pipe = const StdioType._("pipe");
+ static const StdioType file = const StdioType._("file");
+ static const StdioType other = const StdioType._("other");
+
+ @Deprecated("Use terminal instead")
+ static const StdioType TERMINAL = terminal;
+ @Deprecated("Use pipe instead")
+ static const StdioType PIPE = pipe;
+ @Deprecated("Use file instead")
+ static const StdioType FILE = file;
+ @Deprecated("Use other instead")
+ static const StdioType OTHER = other;
+
+ final String name;
+ const StdioType._(this.name);
+ String toString() => "StdioType: $name";
+}
+
+Stdin _stdin;
+Stdout _stdout;
+Stdout _stderr;
+
+// These may be set to different values by the embedder by calling
+// _setStdioFDs when initializing dart:io.
+int _stdinFD = 0;
+int _stdoutFD = 1;
+int _stderrFD = 2;
+
+@pragma('vm:entry-point', 'call')
+void _setStdioFDs(int stdin, int stdout, int stderr) {
+ _stdinFD = stdin;
+ _stdoutFD = stdout;
+ _stderrFD = stderr;
+}
+
+/// The standard input stream of data read by this program.
+Stdin get stdin {
+ _stdin ??= _StdIOUtils._getStdioInputStream(_stdinFD);
+ return _stdin;
+}
+
+/// The standard output stream of data written by this program.
+///
+/// The `addError` API is inherited from `StreamSink` and calling it will
+/// result in an unhandled asynchronous error unless there is an error handler
+/// on `done`.
+Stdout get stdout {
+ _stdout ??= _StdIOUtils._getStdioOutputStream(_stdoutFD);
+ return _stdout;
+}
+
+/// The standard output stream of errors written by this program.
+///
+/// The `addError` API is inherited from `StreamSink` and calling it will
+/// result in an unhandled asynchronous error unless there is an error handler
+/// on `done`.
+Stdout get stderr {
+ _stderr ??= _StdIOUtils._getStdioOutputStream(_stderrFD);
+ return _stderr;
+}
+
+/// For a stream, returns whether it is attached to a file, pipe, terminal, or
+/// something else.
+StdioType stdioType(object) {
+ if (object is _StdStream) {
+ object = object._stream;
+ } else if (object == stdout || object == stderr) {
+ int stdiofd = object == stdout ? _stdoutFD : _stderrFD;
+ switch (_StdIOUtils._getStdioHandleType(stdiofd)) {
+ case _stdioHandleTypeTerminal:
+ return StdioType.terminal;
+ case _stdioHandleTypePipe:
+ return StdioType.pipe;
+ case _stdioHandleTypeFile:
+ return StdioType.file;
+ }
+ }
+ if (object is _FileStream) {
+ return StdioType.file;
+ }
+ if (object is Socket) {
+ int socketType = _StdIOUtils._socketType(object);
+ if (socketType == null) return StdioType.other;
+ switch (socketType) {
+ case _stdioHandleTypeTerminal:
+ return StdioType.terminal;
+ case _stdioHandleTypePipe:
+ return StdioType.pipe;
+ case _stdioHandleTypeFile:
+ return StdioType.file;
+ }
+ }
+ if (object is _IOSinkImpl) {
+ try {
+ if (object._target is _FileStreamConsumer) {
+ return StdioType.file;
+ }
+ } catch (e) {
+ // Only the interface implemented, _sink not available.
+ }
+ }
+ return StdioType.other;
+}
+
+class _StdIOUtils {
+ external static _getStdioOutputStream(int fd);
+ external static Stdin _getStdioInputStream(int fd);
+
+ /// Returns the socket type or `null` if [socket] is not a builtin socket.
+ external static int _socketType(Socket socket);
+ external static _getStdioHandleType(int fd);
+}
diff --git a/sdk_nnbd/lib/io/string_transformer.dart b/sdk_nnbd/lib/io/string_transformer.dart
new file mode 100644
index 0000000..f31c41e
--- /dev/null
+++ b/sdk_nnbd/lib/io/string_transformer.dart
@@ -0,0 +1,130 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/// The current system encoding.
+///
+/// This is used for converting from bytes to and from Strings when
+/// communicating on stdin, stdout and stderr.
+///
+/// On Windows this will use the currently active code page for the conversion.
+/// On all other systems it will always use UTF-8.
+const SystemEncoding systemEncoding = const SystemEncoding();
+@Deprecated("Use systemEncoding instead")
+const SystemEncoding SYSTEM_ENCODING = const SystemEncoding();
+
+/// The system encoding is the current code page on Windows and UTF-8 on Linux
+/// and Mac.
+class SystemEncoding extends Encoding {
+ /// Creates a const SystemEncoding.
+ ///
+ /// Users should use the top-level constant, [systemEncoding].
+ const SystemEncoding();
+
+ String get name => 'system';
+
+ List<int> encode(String input) => encoder.convert(input);
+ String decode(List<int> encoded) => decoder.convert(encoded);
+
+ Converter<String, List<int>> get encoder {
+ if (Platform.operatingSystem == "windows") {
+ return const _WindowsCodePageEncoder();
+ } else {
+ return const Utf8Encoder();
+ }
+ }
+
+ Converter<List<int>, String> get decoder {
+ if (Platform.operatingSystem == "windows") {
+ return const _WindowsCodePageDecoder();
+ } else {
+ return const Utf8Decoder();
+ }
+ }
+}
+
+class _WindowsCodePageEncoder extends Converter<String, List<int>> {
+ const _WindowsCodePageEncoder();
+
+ List<int> convert(String input) {
+ List<int> encoded = _encodeString(input);
+ if (encoded == null) {
+ throw new FormatException("Invalid character for encoding");
+ }
+ return encoded;
+ }
+
+ /**
+ * Starts a chunked conversion.
+ */
+ StringConversionSink startChunkedConversion(Sink<List<int>> sink) {
+ return new _WindowsCodePageEncoderSink(sink);
+ }
+
+ external static List<int> _encodeString(String string);
+}
+
+class _WindowsCodePageEncoderSink extends StringConversionSinkBase {
+ // TODO(floitsch): provide more efficient conversions when the input is
+ // not a String.
+
+ final Sink<List<int>> _sink;
+
+ _WindowsCodePageEncoderSink(this._sink);
+
+ void close() {
+ _sink.close();
+ }
+
+ void add(String string) {
+ List<int> encoded = _WindowsCodePageEncoder._encodeString(string);
+ if (encoded == null) {
+ throw new FormatException("Invalid character for encoding");
+ }
+ _sink.add(encoded);
+ }
+
+ void addSlice(String source, int start, int end, bool isLast) {
+ if (start != 0 || end != source.length) {
+ source = source.substring(start, end);
+ }
+ add(source);
+ if (isLast) close();
+ }
+}
+
+class _WindowsCodePageDecoder extends Converter<List<int>, String> {
+ const _WindowsCodePageDecoder();
+
+ String convert(List<int> input) {
+ return _decodeBytes(input);
+ }
+
+ /**
+ * Starts a chunked conversion.
+ */
+ ByteConversionSink startChunkedConversion(Sink<String> sink) {
+ return new _WindowsCodePageDecoderSink(sink);
+ }
+
+ external static String _decodeBytes(List<int> bytes);
+}
+
+class _WindowsCodePageDecoderSink extends ByteConversionSinkBase {
+ // TODO(floitsch): provide more efficient conversions when the input is
+ // a slice.
+
+ final Sink<String> _sink;
+
+ _WindowsCodePageDecoderSink(this._sink);
+
+ void close() {
+ _sink.close();
+ }
+
+ void add(List<int> bytes) {
+ _sink.add(_WindowsCodePageDecoder._decodeBytes(bytes));
+ }
+}
diff --git a/sdk_nnbd/lib/io/sync_socket.dart b/sdk_nnbd/lib/io/sync_socket.dart
new file mode 100644
index 0000000..fee259d
--- /dev/null
+++ b/sdk_nnbd/lib/io/sync_socket.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * A low-level class for communicating synchronously over a TCP socket.
+ *
+ * Warning: [RawSynchronousSocket] should probably only be used to connect to
+ * 'localhost'. The operations below will block the calling thread to wait for
+ * a response from the network. The thread can process no other events while
+ * waiting for these operations to complete. [RawSynchronousSocket] is not
+ * suitable for applications that require high performance or asynchronous I/O
+ * such as a server. Instead such applications should use the non-blocking
+ * sockets and asynchronous operations in the Socket or RawSocket classes.
+ */
+abstract class RawSynchronousSocket {
+ /**
+ * Creates a new socket connection and returns a [RawSynchronousSocket].
+ *
+ * [host] can either be a [String] or an [InternetAddress]. If [host] is a
+ * [String], [connectSync] will perform a [InternetAddress.lookup] and try
+ * all returned [InternetAddress]es, until connected. Unless a
+ * connection was established, the error from the first failing connection is
+ * returned.
+ */
+ external static RawSynchronousSocket connectSync(host, int port);
+
+ /**
+ * Returns the number of received and unread bytes in the socket that can be
+ * read.
+ */
+ int available();
+
+ /**
+ * Closes the [RawSynchronousSocket].
+ *
+ * Once [closeSync] has been called, attempting to call [readSync],
+ * [readIntoSync], [writeFromSync], [remoteAddress], and [remotePort] will
+ * cause a [SocketException] to be thrown.
+ */
+ void closeSync();
+
+ /**
+ * Reads into an existing [List<int>] from the socket into the range:
+ * [[start],[end]).
+ *
+ * Reads into an existing [List<int>] from the socket. If [start] is present,
+ * the bytes will be filled into [buffer] from index [start], otherwise index
+ * 0. If [end] is present, [end] - [start] bytes will be read into [buffer],
+ * otherwise up to [buffer.length]. If [end] == [start], no bytes are read.
+ * Returns the number of bytes read.
+ */
+ int readIntoSync(List<int> buffer, [int start = 0, int end]);
+
+ /**
+ * Reads up to [bytes] bytes from the socket.
+ *
+ * Blocks and waits for a response of up to a specified number of bytes
+ * sent by the socket. [bytes] specifies the maximum number of bytes to
+ * be read. Returns the list of bytes read, which could be less than the
+ * value specified by [bytes].
+ */
+ List<int> readSync(int bytes);
+
+ /**
+ * Shutdown a socket in the provided direction.
+ *
+ * Calling shutdown will never throw an exception and calling it several times
+ * is supported. If both [SocketDirection.RECEIVE] and [SocketDirection.SEND]
+ * directions are closed, the socket is closed completely, the same as if
+ * [closeSync] has been called.
+ */
+ void shutdown(SocketDirection direction);
+
+ /**
+ * Writes data from a specified range in a [List<int>] to the socket.
+ *
+ * Writes into the socket from a [List<int>]. If [start] is present, the bytes
+ * will be written to the socket starting from index [start]. If [start] is
+ * not present, the bytes will be written starting from index 0. If [end] is
+ * present, the [end] - [start] bytes will be written into the socket starting
+ * at index [start]. If [end] is not provided, [buffer.length] elements will
+ * be written to the socket starting from index [start]. If [end] == [start],
+ * nothing happens.
+ */
+ void writeFromSync(List<int> buffer, [int start = 0, int end]);
+
+ /**
+ * The port used by this socket.
+ */
+ int get port;
+
+ /**
+ * The remote port connected to by this socket.
+ */
+ int get remotePort;
+
+ /**
+ * The [InternetAddress] used to connect this socket.
+ */
+ InternetAddress get address;
+
+ /**
+ * The remote [InternetAddress] connected to by this socket.
+ */
+ InternetAddress get remoteAddress;
+}
diff --git a/sdk_nnbd/lib/isolate/capability.dart b/sdk_nnbd/lib/isolate/capability.dart
new file mode 100644
index 0000000..a51eec2
--- /dev/null
+++ b/sdk_nnbd/lib/isolate/capability.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.isolate;
+
+/**
+ * An unforgeable object that comes back as equal when passed through other
+ * isolates.
+ *
+ * Sending a capability object to another isolate, and getting it back,
+ * will produce an object that is equal to the original.
+ * There is no other way to create objects equal to a capability object.
+ *
+ * Capabilities can be used as access guards: A remote isolate can send
+ * a request for an operation, but it is only allowed if the request contains
+ * the correct capability object.
+ *
+ * This allows exposing the same interface to multiple clients,
+ * but restricting some operations to only those clients
+ * that have also been given the corresponding capability.
+ *
+ * Capabilities can be used inside a single isolate,
+ * but they have no advantage over
+ * just using `new Object` to create a unique object,
+ * and it offers no real security against other code
+ * running in the same isolate.
+ */
+class Capability {
+ /**
+ * Create a new unforgeable capability object.
+ */
+ external factory Capability();
+}
diff --git a/sdk_nnbd/lib/isolate/isolate.dart b/sdk_nnbd/lib/isolate/isolate.dart
new file mode 100644
index 0000000..a697db4
--- /dev/null
+++ b/sdk_nnbd/lib/isolate/isolate.dart
@@ -0,0 +1,789 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Concurrent programming using _isolates_:
+ * independent workers that are similar to threads
+ * but don't share memory,
+ * communicating only via messages.
+ *
+ * To use this library in your code:
+ *
+ * import 'dart:isolate';
+ *
+ * {@category VM}
+ */
+library dart.isolate;
+
+import "dart:async";
+import "dart:_internal" show Since;
+import "dart:typed_data" show ByteBuffer, TypedData, Uint8List;
+
+part "capability.dart";
+
+/**
+ * Thrown when an isolate cannot be created.
+ */
+class IsolateSpawnException implements Exception {
+ /** Error message reported by the spawn operation. */
+ final String message;
+ @pragma("vm:entry-point")
+ IsolateSpawnException(this.message);
+ String toString() => "IsolateSpawnException: $message";
+}
+
+/**
+ * An isolated Dart execution context.
+ *
+ * All Dart code runs in an isolate, and code can access classes and values
+ * only from the same isolate. Different isolates can communicate by sending
+ * values through ports (see [ReceivePort], [SendPort]).
+ *
+ * An `Isolate` object is a reference to an isolate, usually different from
+ * the current isolate.
+ * It represents, and can be used to control, the other isolate.
+ *
+ * When spawning a new isolate, the spawning isolate receives an `Isolate`
+ * object representing the new isolate when the spawn operation succeeds.
+ *
+ * Isolates run code in its own event loop, and each event may run smaller tasks
+ * in a nested microtask queue.
+ *
+ * An `Isolate` object allows other isolates to control the event loop
+ * of the isolate that it represents, and to inspect the isolate,
+ * for example by pausing the isolate or by getting events when the isolate
+ * has an uncaught error.
+ *
+ * The [controlPort] identifies and gives access to controlling the isolate,
+ * and the [pauseCapability] and [terminateCapability] guard access
+ * to some control operations.
+ * For example, calling [pause] on an `Isolate` object created without a
+ * [pauseCapability], has no effect.
+ *
+ * The `Isolate` object provided by a spawn operation will have the
+ * control port and capabilities needed to control the isolate.
+ * New isolate objects can be created without some of these capabilities
+ * if necessary, using the [Isolate.Isolate] constructor.
+ *
+ * An `Isolate` object cannot be sent over a `SendPort`, but the control port
+ * and capabilities can be sent, and can be used to create a new functioning
+ * `Isolate` object in the receiving port's isolate.
+ */
+class Isolate {
+ /** Argument to `ping` and `kill`: Ask for immediate action. */
+ static const int immediate = 0;
+ /** Argument to `ping` and `kill`: Ask for action before the next event. */
+ static const int beforeNextEvent = 1;
+
+ /**
+ * Control port used to send control messages to the isolate.
+ *
+ * The control port identifies the isolate.
+ *
+ * An `Isolate` object allows sending control messages
+ * through the control port.
+ *
+ * Some control messages require a specific capability to be passed along
+ * with the message (see [pauseCapability] and [terminateCapability]),
+ * otherwise the message is ignored by the isolate.
+ */
+ final SendPort controlPort;
+
+ /**
+ * Capability granting the ability to pause the isolate.
+ *
+ * This capability is required by [pause].
+ * If the capability is `null`, or if it is not the correct pause capability
+ * of the isolate identified by [controlPort],
+ * then calls to [pause] will have no effect.
+ *
+ * If the isolate is spawned in a paused state, use this capability as
+ * argument to the [resume] method in order to resume the paused isolate.
+ */
+ final Capability pauseCapability;
+
+ /**
+ * Capability granting the ability to terminate the isolate.
+ *
+ * This capability is required by [kill] and [setErrorsFatal].
+ * If the capability is `null`, or if it is not the correct termination
+ * capability of the isolate identified by [controlPort],
+ * then calls to those methods will have no effect.
+ */
+ final Capability terminateCapability;
+
+ /**
+ * The name of the [Isolate] displayed for debug purposes.
+ *
+ * This can be set using the `debugName` parameter in [spawn] and [spawnUri].
+ *
+ * This name does not uniquely identify an isolate. Multiple isolates in the
+ * same process may have the same `debugName`.
+ *
+ * For a given isolate, this value will be the same as the values returned by
+ * `Dart_DebugName` in the C embedding API and the `debugName` property in
+ * [IsolateMirror].
+ */
+ @Since("2.3")
+ external String get debugName;
+
+ /**
+ * Create a new [Isolate] object with a restricted set of capabilities.
+ *
+ * The port should be a control port for an isolate, as taken from
+ * another `Isolate` object.
+ *
+ * The capabilities should be the subset of the capabilities that are
+ * available to the original isolate.
+ * Capabilities of an isolate are locked to that isolate, and have no effect
+ * anywhere else, so the capabilities should come from the same isolate as
+ * the control port.
+ *
+ * Can also be used to create an [Isolate] object from a control port, and
+ * any available capabilities, that have been sent through a [SendPort].
+ *
+ * Example:
+ * ```dart
+ * Isolate isolate = findSomeIsolate();
+ * Isolate restrictedIsolate = new Isolate(isolate.controlPort);
+ * untrustedCode(restrictedIsolate);
+ * ```
+ * This example creates a new `Isolate` object that cannot be used to
+ * pause or terminate the isolate. All the untrusted code can do is to
+ * inspect the isolate and see uncaught errors or when it terminates.
+ */
+ Isolate(this.controlPort, {this.pauseCapability, this.terminateCapability});
+
+ /**
+ * Return an [Isolate] object representing the current isolate.
+ *
+ * The current isolate for code using [current]
+ * is the isolate running the code.
+ *
+ * The isolate object provides the capabilities required to inspect,
+ * pause or kill the isolate, and allows granting these capabilities
+ * to others.
+ *
+ * It is possible to pause the current isolate, but doing so *without*
+ * first passing the ability to resume it again to another isolate,
+ * is a sure way to hang your program.
+ */
+ external static Isolate get current;
+
+ /**
+ * The location of the package configuration of the current isolate, if any.
+ *
+ * This getter returns `null`, as the `packages/` directory is not supported
+ * in Dart 2.
+ */
+ @Deprecated('packages/ directory resolution is not supported in Dart 2.')
+ external static Future<Uri> get packageRoot;
+
+ /**
+ * The package root of the current isolate, if any.
+ *
+ * If the isolate is using a [packageRoot] or the isolate has not been
+ * setup for package resolution, this getter returns `null`, otherwise it
+ * returns the package config URI.
+ */
+ external static Future<Uri> get packageConfig;
+
+ /**
+ * Maps a package: URI to a non-package Uri.
+ *
+ * If there is no valid mapping from the package: URI in the current
+ * isolate, then this call returns `null`. Non-package: URIs are
+ * returned unmodified.
+ */
+ external static Future<Uri> resolvePackageUri(Uri packageUri);
+
+ /**
+ * Creates and spawns an isolate that shares the same code as the current
+ * isolate.
+ *
+ * The argument [entryPoint] specifies the initial function to call
+ * in the spawned isolate.
+ * The entry-point function is invoked in the new isolate with [message]
+ * as the only argument.
+ *
+ * The function must be a top-level function or a static method
+ * that can be called with a single argument,
+ * that is, a compile-time constant function value
+ * which accepts at least one positional parameter
+ * and has at most one required positional parameter.
+ * The function may accept any number of optional parameters,
+ * as long as it *can* be called with just a single argument.
+ * The function must not be the value of a function expression
+ * or an instance method tear-off.
+ *
+ * Usually the initial [message] contains a [SendPort] so
+ * that the spawner and spawnee can communicate with each other.
+ *
+ * If the [paused] parameter is set to `true`,
+ * the isolate will start up in a paused state,
+ * just before calling the [entryPoint] function with the [message],
+ * as if by an initial call of `isolate.pause(isolate.pauseCapability)`.
+ * To resume the isolate, call `isolate.resume(isolate.pauseCapability)`.
+ *
+ * If the [errorsAreFatal], [onExit] and/or [onError] parameters are provided,
+ * the isolate will act as if, respectively, [setErrorsFatal],
+ * [addOnExitListener] and [addErrorListener] were called with the
+ * corresponding parameter and was processed before the isolate starts
+ * running.
+ *
+ * If [debugName] is provided, the spawned [Isolate] will be identifiable by
+ * this name in debuggers and logging.
+ *
+ * If [errorsAreFatal] is omitted, the platform may choose a default behavior
+ * or inherit the current isolate's behavior.
+ *
+ * You can also call the [setErrorsFatal], [addOnExitListener] and
+ * [addErrorListener] methods on the returned isolate, but unless the
+ * isolate was started as [paused], it may already have terminated
+ * before those methods can complete.
+ *
+ * Returns a future which will complete with an [Isolate] instance if the
+ * spawning succeeded. It will complete with an error otherwise.
+ */
+ external static Future<Isolate> spawn<T>(
+ void entryPoint(T message), T message,
+ {bool paused: false,
+ bool errorsAreFatal,
+ SendPort onExit,
+ SendPort onError,
+ @Since("2.3") String debugName});
+
+ /**
+ * Creates and spawns an isolate that runs the code from the library with
+ * the specified URI.
+ *
+ * The isolate starts executing the top-level `main` function of the library
+ * with the given URI.
+ *
+ * The target `main` must be callable with zero, one or two arguments.
+ * Examples:
+ *
+ * * `main()`
+ * * `main(args)`
+ * * `main(args, message)`
+ *
+ * When present, the parameter `args` is set to the provided [args] list.
+ * When present, the parameter `message` is set to the initial [message].
+ *
+ * If the [paused] parameter is set to `true`,
+ * the isolate will start up in a paused state,
+ * as if by an initial call of `isolate.pause(isolate.pauseCapability)`.
+ * To resume the isolate, call `isolate.resume(isolate.pauseCapability)`.
+ *
+ * If the [errorsAreFatal], [onExit] and/or [onError] parameters are provided,
+ * the isolate will act as if, respectively, [setErrorsFatal],
+ * [addOnExitListener] and [addErrorListener] were called with the
+ * corresponding parameter and was processed before the isolate starts
+ * running.
+ *
+ * You can also call the [setErrorsFatal], [addOnExitListener] and
+ * [addErrorListener] methods on the returned isolate, but unless the
+ * isolate was started as [paused], it may already have terminated
+ * before those methods can complete.
+ *
+ * If the [checked] parameter is set to `true` or `false`,
+ * the new isolate will run code in checked mode (enabling asserts and type
+ * checks), respectively in production mode (disabling asserts and type
+ * checks), if possible. If the parameter is omitted, the new isolate will
+ * inherit the value from the current isolate.
+ *
+ * In Dart2 strong mode, the `checked` parameter only controls asserts, but
+ * not type checks.
+ *
+ * It may not always be possible to honor the `checked` parameter.
+ * If the isolate code was pre-compiled, it may not be possible to change
+ * the checked mode setting dynamically.
+ * In that case, the `checked` parameter is ignored.
+ *
+ * WARNING: The [checked] parameter is not implemented on all platforms yet.
+ *
+ * If the [packageConfig] parameter is provided, then it is used to find the
+ * location of a package resolution configuration file for the spawned
+ * isolate.
+ *
+ * If the [automaticPackageResolution] parameter is provided, then the
+ * location of the package sources in the spawned isolate is automatically
+ * determined.
+ *
+ * The [environment] is a mapping from strings to strings which the
+ * spawned isolate uses when looking up [String.fromEnvironment] values.
+ * The system may add its own entries to environment as well.
+ * If `environment` is omitted, the spawned isolate has the same environment
+ * declarations as the spawning isolate.
+ *
+ * WARNING: The [environment] parameter is not implemented on all
+ * platforms yet.
+ *
+ * If [debugName] is provided, the spawned [Isolate] will be identifiable by
+ * this name in debuggers and logging.
+ *
+ * Returns a future that will complete with an [Isolate] instance if the
+ * spawning succeeded. It will complete with an error otherwise.
+ */
+ external static Future<Isolate> spawnUri(
+ Uri uri,
+ List<String> args,
+ var message,
+ {bool paused: false,
+ SendPort onExit,
+ SendPort onError,
+ bool errorsAreFatal,
+ bool checked,
+ Map<String, String> environment,
+ @Deprecated('The packages/ dir is not supported in Dart 2')
+ Uri packageRoot,
+ Uri packageConfig,
+ bool automaticPackageResolution: false,
+ @Since("2.3")
+ String debugName});
+
+ /**
+ * Requests the isolate to pause.
+ *
+ * When the isolate receives the pause command, it stops
+ * processing events from the event loop queue.
+ * It may still add new events to the queue in response to, e.g., timers
+ * or receive-port messages. When the isolate is resumed,
+ * it starts handling the already enqueued events.
+ *
+ * The pause request is sent through the isolate's command port,
+ * which bypasses the receiving isolate's event loop.
+ * The pause takes effect when it is received, pausing the event loop
+ * as it is at that time.
+ *
+ * The [resumeCapability] is used to identity the pause,
+ * and must be used again to end the pause using [resume].
+ * If [resumeCapability] is omitted, a new capability object is created
+ * and used instead.
+ *
+ * If an isolate is paused more than once using the same capability,
+ * only one resume with that capability is needed to end the pause.
+ *
+ * If an isolate is paused using more than one capability,
+ * each pause must be individually ended before the isolate resumes.
+ *
+ * Returns the capability that must be used to end the pause.
+ * This is either [resumeCapability], or a new capability when
+ * [resumeCapability] is omitted.
+ *
+ * If [pauseCapability] is `null`, or it's not the pause capability
+ * of the isolate identified by [controlPort],
+ * the pause request is ignored by the receiving isolate.
+ */
+ Capability pause([Capability resumeCapability]) {
+ resumeCapability ??= new Capability();
+ _pause(resumeCapability);
+ return resumeCapability;
+ }
+
+ /** Internal implementation of [pause]. */
+ external void _pause(Capability resumeCapability);
+
+ /**
+ * Resumes a paused isolate.
+ *
+ * Sends a message to an isolate requesting that it ends a pause
+ * that was previously requested.
+ *
+ * When all active pause requests have been cancelled, the isolate
+ * will continue processing events and handling normal messages.
+ *
+ * If the [resumeCapability] is not one that has previously been used
+ * to pause the isolate, or it has already been used to resume from
+ * that pause, the resume call has no effect.
+ */
+ external void resume(Capability resumeCapability);
+
+ /**
+ * Requests an exit message on [responsePort] when the isolate terminates.
+ *
+ * The isolate will send [response] as a message on [responsePort] as the last
+ * thing before it terminates. It will run no further code after the message
+ * has been sent.
+ *
+ * Adding the same port more than once will only cause it to receive one exit
+ * message, using the last response value that was added,
+ * and it only needs to be removed once using [removeOnExitListener].
+ *
+ * If the isolate has terminated before it can receive this request,
+ * no exit message will be sent.
+ *
+ * The [response] object must follow the same restrictions as enforced by
+ * [SendPort.send].
+ * It is recommended to only use simple values that can be sent to all
+ * isolates, like `null`, booleans, numbers or strings.
+ *
+ * Since isolates run concurrently, it's possible for it to exit before the
+ * exit listener is established, and in that case no response will be
+ * sent on [responsePort].
+ * To avoid this, either use the corresponding parameter to the spawn
+ * function, or start the isolate paused, add the listener and
+ * then resume the isolate.
+ */
+ /* TODO(lrn): Can we do better? Can the system recognize this message and
+ * send a reply if the receiving isolate is dead?
+ */
+ external void addOnExitListener(SendPort responsePort, {Object response});
+
+ /**
+ * Stops listening for exit messages from the isolate.
+ *
+ * Requests for the isolate to not send exit messages on [responsePort].
+ * If the isolate isn't expecting to send exit messages on [responsePort],
+ * because the port hasn't been added using [addOnExitListener],
+ * or because it has already been removed, the request is ignored.
+ *
+ * If the same port has been passed via [addOnExitListener] more than once,
+ * only one call to `removeOnExitListener` is needed to stop it from receiving
+ * exit messages.
+ *
+ * Closing the receive port that is associated with the [responsePort] does
+ * not stop the isolate from sending uncaught errors, they are just going to
+ * be lost.
+ *
+ * An exit message may still be sent if the isolate terminates
+ * before this request is received and processed.
+ */
+ external void removeOnExitListener(SendPort responsePort);
+
+ /**
+ * Sets whether uncaught errors will terminate the isolate.
+ *
+ * If errors are fatal, any uncaught error will terminate the isolate
+ * event loop and shut down the isolate.
+ *
+ * This call requires the [terminateCapability] for the isolate.
+ * If the capability is absent or incorrect, no change is made.
+ *
+ * Since isolates run concurrently, it's possible for the receiving isolate
+ * to exit due to an error, before a request, using this method, has been
+ * received and processed.
+ * To avoid this, either use the corresponding parameter to the spawn
+ * function, or start the isolate paused, set errors non-fatal and
+ * then resume the isolate.
+ */
+ external void setErrorsFatal(bool errorsAreFatal);
+
+ /**
+ * Requests the isolate to shut down.
+ *
+ * The isolate is requested to terminate itself.
+ * The [priority] argument specifies when this must happen.
+ *
+ * The [priority], when provided, must be one of [immediate] or
+ * [beforeNextEvent] (the default).
+ * The shutdown is performed at different times depending on the priority:
+ *
+ * * `immediate`: The isolate shuts down as soon as possible.
+ * Control messages are handled in order, so all previously sent control
+ * events from this isolate will all have been processed.
+ * The shutdown should happen no later than if sent with
+ * `beforeNextEvent`.
+ * It may happen earlier if the system has a way to shut down cleanly
+ * at an earlier time, even during the execution of another event.
+ * * `beforeNextEvent`: The shutdown is scheduled for the next time
+ * control returns to the event loop of the receiving isolate,
+ * after the current event, and any already scheduled control events,
+ * are completed.
+ *
+ * If [terminateCapability] is `null`, or it's not the terminate capability
+ * of the isolate identified by [controlPort],
+ * the kill request is ignored by the receiving isolate.
+ */
+ external void kill({int priority: beforeNextEvent});
+
+ /**
+ * Requests that the isolate send [response] on the [responsePort].
+ *
+ * The [response] object must follow the same restrictions as enforced by
+ * [SendPort.send].
+ * It is recommended to only use simple values that can be sent to all
+ * isolates, like `null`, booleans, numbers or strings.
+ *
+ * If the isolate is alive, it will eventually send `response`
+ * (defaulting to `null`) on the response port.
+ *
+ * The [priority] must be one of [immediate] or [beforeNextEvent].
+ * The response is sent at different times depending on the ping type:
+ *
+ * * `immediate`: The isolate responds as soon as it receives the
+ * control message. This is after any previous control message
+ * from the same isolate has been received and processed,
+ * but may be during execution of another event.
+ * * `beforeNextEvent`: The response is scheduled for the next time
+ * control returns to the event loop of the receiving isolate,
+ * after the current event, and any already scheduled control events,
+ * are completed.
+ */
+ external void ping(SendPort responsePort,
+ {Object response, int priority: immediate});
+
+ /**
+ * Requests that uncaught errors of the isolate are sent back to [port].
+ *
+ * The errors are sent back as two elements lists.
+ * The first element is a `String` representation of the error, usually
+ * created by calling `toString` on the error.
+ * The second element is a `String` representation of an accompanying
+ * stack trace, or `null` if no stack trace was provided.
+ * To convert this back to a [StackTrace] object, use [StackTrace.fromString].
+ *
+ * Listening using the same port more than once does nothing.
+ * A port will only receive each error once,
+ * and will only need to be removed once using [removeErrorListener].
+
+ * Closing the receive port that is associated with the port does not stop
+ * the isolate from sending uncaught errors, they are just going to be lost.
+ * Instead use [removeErrorListener] to stop receiving errors on [port].
+ *
+ * Since isolates run concurrently, it's possible for it to exit before the
+ * error listener is established. To avoid this, start the isolate paused,
+ * add the listener and then resume the isolate.
+ */
+ external void addErrorListener(SendPort port);
+
+ /**
+ * Stops listening for uncaught errors from the isolate.
+ *
+ * Requests for the isolate to not send uncaught errors on [port].
+ * If the isolate isn't expecting to send uncaught errors on [port],
+ * because the port hasn't been added using [addErrorListener],
+ * or because it has already been removed, the request is ignored.
+ *
+ * If the same port has been passed via [addErrorListener] more than once,
+ * only one call to `removeErrorListener` is needed to stop it from receiving
+ * uncaught errors.
+ *
+ * Uncaught errors message may still be sent by the isolate
+ * until this request is received and processed.
+ */
+ external void removeErrorListener(SendPort port);
+
+ /**
+ * Returns a broadcast stream of uncaught errors from the isolate.
+ *
+ * Each error is provided as an error event on the stream.
+ *
+ * The actual error object and stackTraces will not necessarily
+ * be the same object types as in the actual isolate, but they will
+ * always have the same [Object.toString] result.
+ *
+ * This stream is based on [addErrorListener] and [removeErrorListener].
+ */
+ Stream get errors {
+ StreamController controller;
+ RawReceivePort port;
+ void handleError(message) {
+ List listMessage = message;
+ String errorDescription = listMessage[0];
+ String stackDescription = listMessage[1];
+ var error = new RemoteError(errorDescription, stackDescription);
+ controller.addError(error, error.stackTrace);
+ }
+
+ controller = new StreamController.broadcast(
+ sync: true,
+ onListen: () {
+ port = new RawReceivePort(handleError);
+ this.addErrorListener(port.sendPort);
+ },
+ onCancel: () {
+ this.removeErrorListener(port.sendPort);
+ port.close();
+ port = null;
+ });
+ return controller.stream;
+ }
+}
+
+/**
+ * Sends messages to its [ReceivePort]s.
+ *
+ * [SendPort]s are created from [ReceivePort]s. Any message sent through
+ * a [SendPort] is delivered to its corresponding [ReceivePort]. There might be
+ * many [SendPort]s for the same [ReceivePort].
+ *
+ * [SendPort]s can be transmitted to other isolates, and they preserve equality
+ * when sent.
+ */
+abstract class SendPort implements Capability {
+ /**
+ * Sends an asynchronous [message] through this send port, to its
+ * corresponding `ReceivePort`.
+ *
+ * The content of [message] can be: primitive values (null, num, bool, double,
+ * String), instances of [SendPort], and lists and maps whose elements are any
+ * of these. List and maps are also allowed to be cyclic.
+ *
+ * In the special circumstances when two isolates share the same code and are
+ * running in the same process (e.g. isolates created via [Isolate.spawn]), it
+ * is also possible to send object instances (which would be copied in the
+ * process). This is currently only supported by the dartvm. For now, the
+ * dart2js compiler only supports the restricted messages described above.
+ *
+ * The send happens immediately and doesn't block. The corresponding receive
+ * port can receive the message as soon as its isolate's event loop is ready
+ * to deliver it, independently of what the sending isolate is doing.
+ */
+ void send(var message);
+
+ /**
+ * Tests whether [other] is a [SendPort] pointing to the same
+ * [ReceivePort] as this one.
+ */
+ bool operator ==(var other);
+
+ /**
+ * Returns an immutable hash code for this send port that is
+ * consistent with the == operator.
+ */
+ int get hashCode;
+}
+
+/**
+ * Together with [SendPort], the only means of communication between isolates.
+ *
+ * [ReceivePort]s have a `sendPort` getter which returns a [SendPort].
+ * Any message that is sent through this [SendPort]
+ * is delivered to the [ReceivePort] it has been created from. There, the
+ * message is dispatched to the `ReceivePort`'s listener.
+ *
+ * A [ReceivePort] is a non-broadcast stream. This means that it buffers
+ * incoming messages until a listener is registered. Only one listener can
+ * receive messages. See [Stream.asBroadcastStream] for transforming the port
+ * to a broadcast stream.
+ *
+ * A [ReceivePort] may have many [SendPort]s.
+ */
+abstract class ReceivePort implements Stream {
+ /**
+ * Opens a long-lived port for receiving messages.
+ *
+ * A [ReceivePort] is a non-broadcast stream. This means that it buffers
+ * incoming messages until a listener is registered. Only one listener can
+ * receive messages. See [Stream.asBroadcastStream] for transforming the port
+ * to a broadcast stream.
+ *
+ * A receive port is closed by canceling its subscription.
+ */
+ external factory ReceivePort();
+
+ /**
+ * Creates a [ReceivePort] from a [RawReceivePort].
+ *
+ * The handler of the given [rawPort] is overwritten during the construction
+ * of the result.
+ */
+ external factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort);
+
+ /**
+ * Inherited from [Stream].
+ *
+ * Note that [onError] and [cancelOnError] are ignored since a ReceivePort
+ * will never receive an error.
+ *
+ * The [onDone] handler will be called when the stream closes.
+ * The stream closes when [close] is called.
+ */
+ StreamSubscription listen(void onData(var message),
+ {Function onError, void onDone(), bool cancelOnError});
+
+ /**
+ * Closes `this`.
+ *
+ * If the stream has not been canceled yet, adds a close-event to the event
+ * queue and discards any further incoming messages.
+ *
+ * If the stream has already been canceled this method has no effect.
+ */
+ void close();
+
+ /**
+ * Returns a [SendPort] that sends to this receive port.
+ */
+ SendPort get sendPort;
+}
+
+abstract class RawReceivePort {
+ /**
+ * Opens a long-lived port for receiving messages.
+ *
+ * A [RawReceivePort] is low level and does not work with [Zone]s. It
+ * can not be paused. The data-handler must be set before the first
+ * event is received.
+ */
+ external factory RawReceivePort([Function handler]);
+
+ /**
+ * Sets the handler that is invoked for every incoming message.
+ *
+ * The handler is invoked in the root-zone ([Zone.root]).
+ */
+ void set handler(Function newHandler);
+
+ /**
+ * Closes the port.
+ *
+ * After a call to this method any incoming message is silently dropped.
+ */
+ void close();
+
+ /**
+ * Returns a [SendPort] that sends to this raw receive port.
+ */
+ SendPort get sendPort;
+}
+
+/**
+ * Description of an error from another isolate.
+ *
+ * This error has the same `toString()` and `stackTrace.toString()` behavior
+ * as the original error, but has no other features of the original error.
+ */
+class RemoteError implements Error {
+ final String _description;
+ final StackTrace stackTrace;
+ RemoteError(String description, String stackDescription)
+ : _description = description,
+ stackTrace = new StackTrace.fromString(stackDescription);
+ String toString() => _description;
+}
+
+/**
+ * An efficiently transferable sequence of byte values.
+ *
+ * A [TransferableTypedData] is created from a number of bytes.
+ * This will take time proportional to the number of bytes.
+ *
+ * The [TransferableTypedData] can be moved between isolates, so
+ * sending it through a send port will only take constant time.
+ *
+ * When sent this way, the local transferable can no longer be materialized,
+ * and the received object is now the only way to materialize the data.
+ */
+@Since("2.3.2")
+abstract class TransferableTypedData {
+ /**
+ * Creates a new [TransferableTypedData] containing the bytes of [list].
+ *
+ * It must be possible to create a single [Uint8List] containing the
+ * bytes, so if there are more bytes than what the platform allows in
+ * a single [Uint8List], then creation fails.
+ */
+ external factory TransferableTypedData.fromList(List<TypedData> list);
+
+ /**
+ * Creates a new [ByteBuffer] containing the bytes stored in this [TransferableTypedData].
+ *
+ * The [TransferableTypedData] is a cross-isolate single-use resource.
+ * This method must not be called more than once on the same underlying
+ * transferable bytes, even if the calls occur in different isolates.
+ */
+ ByteBuffer materialize();
+}
diff --git a/sdk_nnbd/lib/isolate/isolate_sources.gni b/sdk_nnbd/lib/isolate/isolate_sources.gni
new file mode 100644
index 0000000..8af8ba1
--- /dev/null
+++ b/sdk_nnbd/lib/isolate/isolate_sources.gni
@@ -0,0 +1,10 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+isolate_sdk_sources = [
+ "isolate.dart",
+
+ # The above file needs to be first as it lists the parts below.
+ "capability.dart",
+]
diff --git a/sdk_nnbd/lib/js/_js.dart b/sdk_nnbd/lib/js/_js.dart
new file mode 100644
index 0000000..aef7ef9
--- /dev/null
+++ b/sdk_nnbd/lib/js/_js.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Helper library used by `dart:js`.
+///
+/// This library hides any logic that is specific to the web, and allows us to
+/// support `dart:js` for compiling to javascript on the server (e.g. to target
+/// nodejs).
+library dart._js;
+
+/// Whether `o` is a browser object such as `Blob`, `Event`, `KeyRange`,
+/// `ImageData`, `Node`, and `Window`.
+///
+/// On non-web targets, this function always returns false.
+external bool isBrowserObject(dynamic o);
+
+/// Convert a browser object to it's Dart counterpart. None of these types are
+/// wrapped, but this function is needed to inform dart2js about the possible
+/// types that are used and that therefore cannot be tree-shaken.
+external Object convertFromBrowserObject(dynamic o);
diff --git a/sdk_nnbd/lib/js/_js_client.dart b/sdk_nnbd/lib/js/_js_client.dart
new file mode 100644
index 0000000..de25540
--- /dev/null
+++ b/sdk_nnbd/lib/js/_js_client.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html' show Blob, Event, ImageData, Node, Window, WorkerGlobalScope;
+import 'dart:indexed_db' show KeyRange;
+import 'dart:_js_helper' show patch;
+import 'dart:_foreign_helper' show JS;
+
+@patch
+bool isBrowserObject(dynamic o) =>
+ o is Blob ||
+ o is Event ||
+ o is KeyRange ||
+ o is ImageData ||
+ o is Node ||
+ o is Window ||
+ o is WorkerGlobalScope;
+
+@patch
+Object convertFromBrowserObject(dynamic o) =>
+ JS('Blob|Event|KeyRange|ImageData|Node|Window|WorkerGlobalScope', '#', o);
diff --git a/sdk_nnbd/lib/js/_js_server.dart b/sdk_nnbd/lib/js/_js_server.dart
new file mode 100644
index 0000000..b941d77
--- /dev/null
+++ b/sdk_nnbd/lib/js/_js_server.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:_js_helper' show patch;
+
+@patch
+bool isBrowserObject(dynamic o) => false;
+
+@patch
+Object convertFromBrowserObject(dynamic o) => o;
diff --git a/sdk_nnbd/lib/js/dart2js/js_dart2js.dart b/sdk_nnbd/lib/js/dart2js/js_dart2js.dart
new file mode 100644
index 0000000..535227b
--- /dev/null
+++ b/sdk_nnbd/lib/js/dart2js/js_dart2js.dart
@@ -0,0 +1,719 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Support for interoperating with JavaScript.
+ *
+ * This library provides access to JavaScript objects from Dart, allowing
+ * Dart code to get and set properties, and call methods of JavaScript objects
+ * and invoke JavaScript functions. The library takes care of converting
+ * between Dart and JavaScript objects where possible, or providing proxies if
+ * conversion isn't possible.
+ *
+ * This library does not yet make Dart objects usable from JavaScript, their
+ * methods and proeprties are not accessible, though it does allow Dart
+ * functions to be passed into and called from JavaScript.
+ *
+ * [JsObject] is the core type and represents a proxy of a JavaScript object.
+ * JsObject gives access to the underlying JavaScript objects properties and
+ * methods. `JsObject`s can be acquired by calls to JavaScript, or they can be
+ * created from proxies to JavaScript constructors.
+ *
+ * The top-level getter [context] provides a [JsObject] that represents the
+ * global object in JavaScript, usually `window`.
+ *
+ * The following example shows an alert dialog via a JavaScript call to the
+ * global function `alert()`:
+ *
+ * import 'dart:js';
+ *
+ * main() => context.callMethod('alert', ['Hello from Dart!']);
+ *
+ * This example shows how to create a [JsObject] from a JavaScript constructor
+ * and access its properties:
+ *
+ * import 'dart:js';
+ *
+ * main() {
+ * var object = new JsObject(context['Object']);
+ * object['greeting'] = 'Hello';
+ * object['greet'] = (name) => "${object['greeting']} $name";
+ * var message = object.callMethod('greet', ['JavaScript']);
+ * context['console'].callMethod('log', [message]);
+ * }
+ *
+ * ## Proxying and automatic conversion
+ *
+ * When setting properties on a JsObject or passing arguments to a Javascript
+ * method or function, Dart objects are automatically converted or proxied to
+ * JavaScript objects. When accessing JavaScript properties, or when a Dart
+ * closure is invoked from JavaScript, the JavaScript objects are also
+ * converted to Dart.
+ *
+ * Functions and closures are proxied in such a way that they are callable. A
+ * Dart closure assigned to a JavaScript property is proxied by a function in
+ * JavaScript. A JavaScript function accessed from Dart is proxied by a
+ * [JsFunction], which has a [apply] method to invoke it.
+ *
+ * The following types are transferred directly and not proxied:
+ *
+ * * Basic types: `null`, `bool`, `num`, `String`, `DateTime`
+ * * `TypedData`, including its subclasses like `Int32List`, but _not_
+ * `ByteBuffer`
+ * * When compiling for the web, also: `Blob`, `Event`, `ImageData`,
+ * `KeyRange`, `Node`, and `Window`.
+ *
+ * ## Converting collections with JsObject.jsify()
+ *
+ * To create a JavaScript collection from a Dart collection use the
+ * [JsObject.jsify] constructor, which converts Dart [Map]s and [Iterable]s
+ * into JavaScript Objects and Arrays.
+ *
+ * The following expression creates a new JavaScript object with the properties
+ * `a` and `b` defined:
+ *
+ * var jsMap = new JsObject.jsify({'a': 1, 'b': 2});
+ *
+ * This expression creates a JavaScript array:
+ *
+ * var jsArray = new JsObject.jsify([1, 2, 3]);
+ *
+ * {@category Web}
+ */
+library dart.js;
+
+import 'dart:collection' show HashMap, ListMixin;
+import 'dart:typed_data' show TypedData;
+
+import 'dart:_foreign_helper' show JS, JS_CONST, DART_CLOSURE_TO_JS;
+import 'dart:_interceptors'
+ show
+ JavaScriptFunction,
+ JavaScriptObject,
+ UnknownJavaScriptObject,
+ DART_CLOSURE_PROPERTY_NAME;
+import 'dart:_js_helper'
+ show Primitives, convertDartClosureToJS, getIsolateAffinityTag;
+import 'dart:_js' show isBrowserObject, convertFromBrowserObject;
+
+export 'dart:_interceptors' show JavaScriptObject;
+
+final JsObject context = _wrapToDart(JS('', 'self'));
+
+_convertDartFunction(Function f, {bool captureThis: false}) {
+ return JS(
+ 'JavaScriptFunction',
+ '''
+ function(_call, f, captureThis) {
+ return function() {
+ return _call(f, captureThis, this,
+ Array.prototype.slice.apply(arguments));
+ }
+ }(#, #, #)
+ ''',
+ DART_CLOSURE_TO_JS(_callDartFunction),
+ f,
+ captureThis);
+}
+
+_callDartFunction(callback, bool captureThis, self, List arguments) {
+ if (captureThis) {
+ arguments = [self]..addAll(arguments);
+ }
+ var dartArgs = new List.from(arguments.map(_convertToDart));
+ return _convertToJS(Function.apply(callback, dartArgs));
+}
+
+/**
+ * Proxies a JavaScript object to Dart.
+ *
+ * The properties of the JavaScript object are accessible via the `[]` and
+ * `[]=` operators. Methods are callable via [callMethod].
+ */
+class JsObject {
+ // The wrapped JS object.
+ final dynamic _jsObject;
+
+ // This shoud only be called from _wrapToDart
+ JsObject._fromJs(this._jsObject) {
+ assert(_jsObject != null);
+ }
+
+ /**
+ * Constructs a new JavaScript object from [constructor] and returns a proxy
+ * to it.
+ */
+ factory JsObject(JsFunction constructor, [List arguments]) {
+ var constr = _convertToJS(constructor);
+ if (arguments == null) {
+ return _wrapToDart(JS('', 'new #()', constr));
+ }
+
+ if (JS('bool', '# instanceof Array', arguments)) {
+ int argumentCount = JS('int', '#.length', arguments);
+ switch (argumentCount) {
+ case 0:
+ return _wrapToDart(JS('', 'new #()', constr));
+
+ case 1:
+ var arg0 = _convertToJS(JS('', '#[0]', arguments));
+ return _wrapToDart(JS('', 'new #(#)', constr, arg0));
+
+ case 2:
+ var arg0 = _convertToJS(JS('', '#[0]', arguments));
+ var arg1 = _convertToJS(JS('', '#[1]', arguments));
+ return _wrapToDart(JS('', 'new #(#, #)', constr, arg0, arg1));
+
+ case 3:
+ var arg0 = _convertToJS(JS('', '#[0]', arguments));
+ var arg1 = _convertToJS(JS('', '#[1]', arguments));
+ var arg2 = _convertToJS(JS('', '#[2]', arguments));
+ return _wrapToDart(
+ JS('', 'new #(#, #, #)', constr, arg0, arg1, arg2));
+
+ case 4:
+ var arg0 = _convertToJS(JS('', '#[0]', arguments));
+ var arg1 = _convertToJS(JS('', '#[1]', arguments));
+ var arg2 = _convertToJS(JS('', '#[2]', arguments));
+ var arg3 = _convertToJS(JS('', '#[3]', arguments));
+ return _wrapToDart(
+ JS('', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg3));
+ }
+ }
+
+ // The following code solves the problem of invoking a JavaScript
+ // constructor with an unknown number arguments.
+ // First bind the constructor to the argument list using bind.apply().
+ // The first argument to bind() is the binding of 'this', so add 'null' to
+ // the arguments list passed to apply().
+ // After that, use the JavaScript 'new' operator which overrides any binding
+ // of 'this' with the new instance.
+ var args = <dynamic>[null]..addAll(arguments.map(_convertToJS));
+ var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args);
+ // Without this line, calling factoryFunction as a constructor throws
+ JS('String', 'String(#)', factoryFunction);
+ // This could return an UnknownJavaScriptObject, or a native
+ // object for which there is an interceptor
+ var jsObj = JS('', 'new #()', factoryFunction);
+
+ return _wrapToDart(jsObj);
+
+ // TODO(sra): Investigate:
+ //
+ // var jsObj = JS('', 'Object.create(#.prototype)', constr);
+ // JS('', '#.apply(#, #)', constr, jsObj,
+ // []..addAll(arguments.map(_convertToJS)));
+ // return _wrapToDart(jsObj);
+ }
+
+ /**
+ * Constructs a [JsObject] that proxies a native Dart object; _for expert use
+ * only_.
+ *
+ * Use this constructor only if you wish to get access to JavaScript
+ * properties attached to a browser host object, such as a Node or Blob, that
+ * is normally automatically converted into a native Dart object.
+ *
+ * An exception will be thrown if [object] either is `null` or has the type
+ * `bool`, `num`, or `String`.
+ */
+ factory JsObject.fromBrowserObject(object) {
+ if (object is num || object is String || object is bool || object == null) {
+ throw new ArgumentError("object cannot be a num, string, bool, or null");
+ }
+ return _wrapToDart(_convertToJS(object));
+ }
+
+ /**
+ * Recursively converts a JSON-like collection of Dart objects to a
+ * collection of JavaScript objects and returns a [JsObject] proxy to it.
+ *
+ * [object] must be a [Map] or [Iterable], the contents of which are also
+ * converted. Maps and Iterables are copied to a new JavaScript object.
+ * Primitives and other transferrable values are directly converted to their
+ * JavaScript type, and all other objects are proxied.
+ */
+ factory JsObject.jsify(object) {
+ if ((object is! Map) && (object is! Iterable)) {
+ throw new ArgumentError("object must be a Map or Iterable");
+ }
+ return _wrapToDart(_convertDataTree(object));
+ }
+
+ static _convertDataTree(data) {
+ var _convertedObjects = new HashMap.identity();
+
+ _convert(o) {
+ if (_convertedObjects.containsKey(o)) {
+ return _convertedObjects[o];
+ }
+ if (o is Map) {
+ final convertedMap = JS('=Object', '{}');
+ _convertedObjects[o] = convertedMap;
+ for (var key in o.keys) {
+ JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key]));
+ }
+ return convertedMap;
+ } else if (o is Iterable) {
+ var convertedList = [];
+ _convertedObjects[o] = convertedList;
+ convertedList.addAll(o.map(_convert));
+ return convertedList;
+ } else {
+ return _convertToJS(o);
+ }
+ }
+
+ return _convert(data);
+ }
+
+ /**
+ * Returns the value associated with [property] from the proxied JavaScript
+ * object.
+ *
+ * The type of [property] must be either [String] or [num].
+ */
+ dynamic operator [](property) {
+ if (property is! String && property is! num) {
+ throw new ArgumentError("property is not a String or num");
+ }
+ return _convertToDart(JS('', '#[#]', _jsObject, property));
+ }
+
+ /**
+ * Sets the value associated with [property] on the proxied JavaScript
+ * object.
+ *
+ * The type of [property] must be either [String] or [num].
+ */
+ operator []=(property, value) {
+ if (property is! String && property is! num) {
+ throw new ArgumentError("property is not a String or num");
+ }
+ JS('', '#[#]=#', _jsObject, property, _convertToJS(value));
+ }
+
+ int get hashCode => 0;
+
+ bool operator ==(other) =>
+ other is JsObject && JS('bool', '# === #', _jsObject, other._jsObject);
+
+ /**
+ * Returns `true` if the JavaScript object contains the specified property
+ * either directly or though its prototype chain.
+ *
+ * This is the equivalent of the `in` operator in JavaScript.
+ */
+ bool hasProperty(property) {
+ if (property is! String && property is! num) {
+ throw new ArgumentError("property is not a String or num");
+ }
+ return JS('bool', '# in #', property, _jsObject);
+ }
+
+ /**
+ * Removes [property] from the JavaScript object.
+ *
+ * This is the equivalent of the `delete` operator in JavaScript.
+ */
+ void deleteProperty(property) {
+ if (property is! String && property is! num) {
+ throw new ArgumentError("property is not a String or num");
+ }
+ JS('bool', 'delete #[#]', _jsObject, property);
+ }
+
+ /**
+ * Returns `true` if the JavaScript object has [type] in its prototype chain.
+ *
+ * This is the equivalent of the `instanceof` operator in JavaScript.
+ */
+ bool instanceof(JsFunction type) {
+ return JS('bool', '# instanceof #', _jsObject, _convertToJS(type));
+ }
+
+ /**
+ * Returns the result of the JavaScript objects `toString` method.
+ */
+ String toString() {
+ try {
+ return JS('String', 'String(#)', _jsObject);
+ } catch (e) {
+ return super.toString();
+ }
+ }
+
+ /**
+ * Calls [method] on the JavaScript object with the arguments [args] and
+ * returns the result.
+ *
+ * The type of [method] must be either [String] or [num].
+ */
+ dynamic callMethod(method, [List args]) {
+ if (method is! String && method is! num) {
+ throw new ArgumentError("method is not a String or num");
+ }
+ return _convertToDart(JS(
+ '',
+ '#[#].apply(#, #)',
+ _jsObject,
+ method,
+ _jsObject,
+ args == null ? null : new List.from(args.map(_convertToJS))));
+ }
+}
+
+/**
+ * Proxies a JavaScript Function object.
+ */
+class JsFunction extends JsObject {
+ /**
+ * Returns a [JsFunction] that captures its 'this' binding and calls [f]
+ * with the value of this passed as the first argument.
+ */
+ factory JsFunction.withThis(Function f) {
+ var jsFunc = _convertDartFunction(f, captureThis: true);
+ return new JsFunction._fromJs(jsFunc);
+ }
+
+ JsFunction._fromJs(jsObject) : super._fromJs(jsObject);
+
+ /**
+ * Invokes the JavaScript function with arguments [args]. If [thisArg] is
+ * supplied it is the value of `this` for the invocation.
+ */
+ dynamic apply(List args, {thisArg}) => _convertToDart(JS(
+ '',
+ '#.apply(#, #)',
+ _jsObject,
+ _convertToJS(thisArg),
+ args == null ? null : new List.from(args.map(_convertToJS))));
+}
+
+/**
+ * A [List] that proxies a JavaScript array.
+ */
+class JsArray<E> extends JsObject with ListMixin<E> {
+ /**
+ * Creates a new JavaScript array.
+ */
+ JsArray() : super._fromJs([]);
+
+ /**
+ * Creates a new JavaScript array and initializes it to the contents of
+ * [other].
+ */
+ JsArray.from(Iterable<E> other)
+ : super._fromJs([]..addAll(other.map(_convertToJS)));
+
+ JsArray._fromJs(jsObject) : super._fromJs(jsObject);
+
+ _checkIndex(int index) {
+ if (index is int && (index < 0 || index >= length)) {
+ throw new RangeError.range(index, 0, length);
+ }
+ }
+
+ _checkInsertIndex(int index) {
+ if (index is int && (index < 0 || index >= length + 1)) {
+ throw new RangeError.range(index, 0, length);
+ }
+ }
+
+ static _checkRange(int start, int end, int length) {
+ if (start < 0 || start > length) {
+ throw new RangeError.range(start, 0, length);
+ }
+ if (end < start || end > length) {
+ throw new RangeError.range(end, start, length);
+ }
+ }
+
+ // Methods required by ListMixin
+
+ E operator [](dynamic index) {
+ // TODO(justinfagnani): fix the semantics for non-ints
+ // dartbug.com/14605
+ if (index is num && index == index.toInt()) {
+ _checkIndex(index);
+ }
+ return super[index];
+ }
+
+ void operator []=(dynamic index, E value) {
+ // TODO(justinfagnani): fix the semantics for non-ints
+ // dartbug.com/14605
+ if (index is num && index == index.toInt()) {
+ _checkIndex(index);
+ }
+ super[index] = value;
+ }
+
+ int get length {
+ // Check the length honours the List contract.
+ var len = JS('', '#.length', _jsObject);
+ // JavaScript arrays have lengths which are unsigned 32-bit integers.
+ if (JS('bool', 'typeof # === "number" && (# >>> 0) === #', len, len, len)) {
+ return JS('int', '#', len);
+ }
+ throw new StateError('Bad JsArray length');
+ }
+
+ void set length(int length) {
+ super['length'] = length;
+ }
+
+ // Methods overridden for better performance
+
+ void add(E value) {
+ callMethod('push', [value]);
+ }
+
+ void addAll(Iterable<E> iterable) {
+ var list = (JS('bool', '# instanceof Array', iterable))
+ ? iterable
+ : new List.from(iterable);
+ callMethod('push', list);
+ }
+
+ void insert(int index, E element) {
+ _checkInsertIndex(index);
+ callMethod('splice', [index, 0, element]);
+ }
+
+ E removeAt(int index) {
+ _checkIndex(index);
+ return callMethod('splice', [index, 1])[0];
+ }
+
+ E removeLast() {
+ if (length == 0) throw new RangeError(-1);
+ return callMethod('pop');
+ }
+
+ void removeRange(int start, int end) {
+ _checkRange(start, end, length);
+ callMethod('splice', [start, end - start]);
+ }
+
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+ _checkRange(start, end, this.length);
+ int length = end - start;
+ if (length == 0) return;
+ if (skipCount < 0) throw new ArgumentError(skipCount);
+ var args = <dynamic>[start, length]
+ ..addAll(iterable.skip(skipCount).take(length));
+ callMethod('splice', args);
+ }
+
+ void sort([int compare(E a, E b)]) {
+ // Note: arr.sort(null) is a type error in FF
+ callMethod('sort', compare == null ? [] : [compare]);
+ }
+}
+
+// property added to a Dart object referencing its JS-side DartObject proxy
+final String _DART_OBJECT_PROPERTY_NAME =
+ getIsolateAffinityTag(r'_$dart_dartObject');
+
+// property added to a JS object referencing its Dart-side JsObject proxy
+const _JS_OBJECT_PROPERTY_NAME = r'_$dart_jsObject';
+const _JS_FUNCTION_PROPERTY_NAME = r'$dart_jsFunction';
+const _JS_FUNCTION_PROPERTY_NAME_CAPTURE_THIS = r'_$dart_jsFunctionCaptureThis';
+
+bool _defineProperty(o, String name, value) {
+ try {
+ if (_isExtensible(o) &&
+ // TODO(ahe): Calling _hasOwnProperty to work around
+ // https://code.google.com/p/dart/issues/detail?id=21331.
+ !_hasOwnProperty(o, name)) {
+ JS('void', 'Object.defineProperty(#, #, { value: #})', o, name, value);
+ return true;
+ }
+ } catch (e) {
+ // object is native and lies about being extensible
+ // see https://bugzilla.mozilla.org/show_bug.cgi?id=775185
+ // Or, isExtensible throws for this object.
+ }
+ return false;
+}
+
+bool _hasOwnProperty(o, String name) {
+ return JS('bool', 'Object.prototype.hasOwnProperty.call(#, #)', o, name);
+}
+
+bool _isExtensible(o) => JS('bool', 'Object.isExtensible(#)', o);
+
+Object _getOwnProperty(o, String name) {
+ if (_hasOwnProperty(o, name)) {
+ return JS('', '#[#]', o, name);
+ }
+ return null;
+}
+
+bool _isLocalObject(o) => JS('bool', '# instanceof Object', o);
+
+// The shared constructor function for proxies to Dart objects in JavaScript.
+final _dartProxyCtor = JS('', 'function DartObject(o) { this.o = o; }');
+
+dynamic _convertToJS(dynamic o) {
+ // Note: we don't write `if (o == null) return null;` to make sure dart2js
+ // doesn't convert `return null;` into `return;` (which would make `null` be
+ // `undefined` in Javascprit). See dartbug.com/20305 for details.
+ if (o == null || o is String || o is num || o is bool) {
+ return o;
+ }
+ if (o is JsObject) {
+ return o._jsObject;
+ }
+ if (isBrowserObject(o)) {
+ return o;
+ }
+ if (o is TypedData) {
+ return o;
+ }
+ if (o is DateTime) {
+ return Primitives.lazyAsJsDate(o);
+ }
+ if (o is Function) {
+ return _getJsProxy(o, _JS_FUNCTION_PROPERTY_NAME, (o) {
+ var jsFunction = _convertDartFunction(o);
+ // set a property on the JS closure referencing the Dart closure
+ _defineProperty(jsFunction, DART_CLOSURE_PROPERTY_NAME, o);
+ return jsFunction;
+ });
+ }
+ var ctor = _dartProxyCtor;
+ return _getJsProxy(
+ o, _JS_OBJECT_PROPERTY_NAME, (o) => JS('', 'new #(#)', ctor, o));
+}
+
+Object _getJsProxy(o, String propertyName, createProxy(o)) {
+ var jsProxy = _getOwnProperty(o, propertyName);
+ if (jsProxy == null) {
+ jsProxy = createProxy(o);
+ _defineProperty(o, propertyName, jsProxy);
+ }
+ return jsProxy;
+}
+
+// converts a Dart object to a reference to a native JS object
+// which might be a DartObject JS->Dart proxy
+Object _convertToDart(o) {
+ if (JS('bool', '# == null', o) ||
+ JS('bool', 'typeof # == "string"', o) ||
+ JS('bool', 'typeof # == "number"', o) ||
+ JS('bool', 'typeof # == "boolean"', o)) {
+ return o;
+ } else if (_isLocalObject(o) && isBrowserObject(o)) {
+ return convertFromBrowserObject(o);
+ } else if (_isLocalObject(o) && o is TypedData) {
+ return JS('TypedData', '#', o);
+ } else if (JS('bool', '# instanceof Date', o)) {
+ var ms = JS('num', '#.getTime()', o);
+ return new DateTime.fromMillisecondsSinceEpoch(ms);
+ } else if (JS('bool', '#.constructor === #', o, _dartProxyCtor)) {
+ return JS('', '#.o', o);
+ } else {
+ return _wrapToDart(o);
+ }
+}
+
+Object _wrapToDart(o) {
+ if (JS('bool', 'typeof # == "function"', o)) {
+ return _getDartProxy(
+ o, DART_CLOSURE_PROPERTY_NAME, (o) => new JsFunction._fromJs(o));
+ }
+ if (JS('bool', '# instanceof Array', o)) {
+ return _getDartProxy(
+ o, _DART_OBJECT_PROPERTY_NAME, (o) => new JsArray._fromJs(o));
+ }
+ return _getDartProxy(
+ o, _DART_OBJECT_PROPERTY_NAME, (o) => new JsObject._fromJs(o));
+}
+
+Object _getDartProxy(o, String propertyName, createProxy(o)) {
+ var dartProxy = _getOwnProperty(o, propertyName);
+ // Temporary fix for dartbug.com/15193
+ // In some cases it's possible to see a JavaScript object that
+ // came from a different context and was previously proxied to
+ // Dart in that context. The JS object will have a cached proxy
+ // but it won't be a valid Dart object in this context.
+ // For now we throw away the cached proxy, but we should be able
+ // to cache proxies from multiple JS contexts and Dart isolates.
+ if (dartProxy == null || !_isLocalObject(o)) {
+ dartProxy = createProxy(o);
+ _defineProperty(o, propertyName, dartProxy);
+ }
+ return dartProxy;
+}
+
+// ---------------------------------------------------------------------------
+// Start of methods for new style Dart-JS interop.
+
+_convertDartFunctionFast(Function f) {
+ var existing = JS('', '#.#', f, _JS_FUNCTION_PROPERTY_NAME);
+ if (existing != null) return existing;
+ var ret = JS(
+ 'JavaScriptFunction',
+ '''
+ function(_call, f) {
+ return function() {
+ return _call(f, Array.prototype.slice.apply(arguments));
+ }
+ }(#, #)
+ ''',
+ DART_CLOSURE_TO_JS(_callDartFunctionFast),
+ f);
+ JS('', '#.# = #', ret, DART_CLOSURE_PROPERTY_NAME, f);
+ JS('', '#.# = #', f, _JS_FUNCTION_PROPERTY_NAME, ret);
+ return ret;
+}
+
+_convertDartFunctionFastCaptureThis(Function f) {
+ var existing = JS('', '#.#', f, _JS_FUNCTION_PROPERTY_NAME_CAPTURE_THIS);
+ if (existing != null) return existing;
+ var ret = JS(
+ 'JavaScriptFunction',
+ '''
+ function(_call, f) {
+ return function() {
+ return _call(f, this,Array.prototype.slice.apply(arguments));
+ }
+ }(#, #)
+ ''',
+ DART_CLOSURE_TO_JS(_callDartFunctionFastCaptureThis),
+ f);
+ JS('', '#.# = #', ret, DART_CLOSURE_PROPERTY_NAME, f);
+ JS('', '#.# = #', f, _JS_FUNCTION_PROPERTY_NAME_CAPTURE_THIS, ret);
+ return ret;
+}
+
+_callDartFunctionFast(callback, List arguments) {
+ return Function.apply(callback, arguments);
+}
+
+_callDartFunctionFastCaptureThis(callback, self, List arguments) {
+ return Function.apply(callback, [self]..addAll(arguments));
+}
+
+F allowInterop<F extends Function>(F f) {
+ if (JS('bool', 'typeof(#) == "function"', f)) {
+ // Already supports interop, just use the existing function.
+ return f;
+ } else {
+ return _convertDartFunctionFast(f);
+ }
+}
+
+Function allowInteropCaptureThis(Function f) {
+ if (JS('bool', 'typeof(#) == "function"', f)) {
+ // Behavior when the function is already a JS function is unspecified.
+ throw new ArgumentError(
+ "Function is already a JS function so cannot capture this.");
+ return f;
+ } else {
+ return _convertDartFunctionFastCaptureThis(f);
+ }
+}
diff --git a/sdk_nnbd/lib/js_util/dart2js/js_util_dart2js.dart b/sdk_nnbd/lib/js_util/dart2js/js_util_dart2js.dart
new file mode 100644
index 0000000..6b605fb
--- /dev/null
+++ b/sdk_nnbd/lib/js_util/dart2js/js_util_dart2js.dart
@@ -0,0 +1,128 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Utility methods to efficiently manipulate typed JSInterop objects in cases
+/// where the name to call is not known at runtime. You should only use these
+/// methods when the same effect cannot be achieved with @JS annotations.
+/// These methods would be extension methods on JSObject if Dart supported
+/// extension methods.
+///
+/// {@category Web}
+library dart.js_util;
+
+import 'dart:_foreign_helper' show JS;
+import 'dart:collection' show HashMap;
+
+/// WARNING: performance of this method is much worse than other util
+/// methods in this library. Only use this method as a last resort.
+///
+/// Recursively converts a JSON-like collection of Dart objects to a
+/// collection of JavaScript objects and returns a [JsObject] proxy to it.
+///
+/// [object] must be a [Map] or [Iterable], the contents of which are also
+/// converted. Maps and Iterables are copied to a new JavaScript object.
+/// Primitives and other transferable values are directly converted to their
+/// JavaScript type, and all other objects are proxied.
+jsify(object) {
+ if ((object is! Map) && (object is! Iterable)) {
+ throw new ArgumentError("object must be a Map or Iterable");
+ }
+ return _convertDataTree(object);
+}
+
+_convertDataTree(data) {
+ var _convertedObjects = new HashMap.identity();
+
+ _convert(o) {
+ if (_convertedObjects.containsKey(o)) {
+ return _convertedObjects[o];
+ }
+ if (o is Map) {
+ final convertedMap = JS('=Object', '{}');
+ _convertedObjects[o] = convertedMap;
+ for (var key in o.keys) {
+ JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key]));
+ }
+ return convertedMap;
+ } else if (o is Iterable) {
+ var convertedList = [];
+ _convertedObjects[o] = convertedList;
+ convertedList.addAll(o.map(_convert));
+ return convertedList;
+ } else {
+ return o;
+ }
+ }
+
+ return _convert(data);
+}
+
+newObject() => JS('=Object', '{}');
+
+bool hasProperty(o, name) => JS('bool', '# in #', name, o);
+getProperty(o, name) => JS('Object|Null', '#[#]', o, name);
+setProperty(o, name, value) => JS('', '#[#]=#', o, name, value);
+
+callMethod(o, String method, List args) =>
+ JS('Object|Null', '#[#].apply(#, #)', o, method, o, args);
+
+bool instanceof(o, Function type) => JS('bool', '# instanceof #', o, type);
+callConstructor(Function constr, List arguments) {
+ if (arguments == null) {
+ return JS('Object', 'new #()', constr);
+ }
+
+ if (JS('bool', '# instanceof Array', arguments)) {
+ int argumentCount = JS('int', '#.length', arguments);
+ switch (argumentCount) {
+ case 0:
+ return JS('Object', 'new #()', constr);
+
+ case 1:
+ var arg0 = JS('', '#[0]', arguments);
+ return JS('Object', 'new #(#)', constr, arg0);
+
+ case 2:
+ var arg0 = JS('', '#[0]', arguments);
+ var arg1 = JS('', '#[1]', arguments);
+ return JS('Object', 'new #(#, #)', constr, arg0, arg1);
+
+ case 3:
+ var arg0 = JS('', '#[0]', arguments);
+ var arg1 = JS('', '#[1]', arguments);
+ var arg2 = JS('', '#[2]', arguments);
+ return JS('Object', 'new #(#, #, #)', constr, arg0, arg1, arg2);
+
+ case 4:
+ var arg0 = JS('', '#[0]', arguments);
+ var arg1 = JS('', '#[1]', arguments);
+ var arg2 = JS('', '#[2]', arguments);
+ var arg3 = JS('', '#[3]', arguments);
+ return JS(
+ 'Object', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg3);
+ }
+ }
+
+ // The following code solves the problem of invoking a JavaScript
+ // constructor with an unknown number arguments.
+ // First bind the constructor to the argument list using bind.apply().
+ // The first argument to bind() is the binding of 't', so add 'null' to
+ // the arguments list passed to apply().
+ // After that, use the JavaScript 'new' operator which overrides any binding
+ // of 'this' with the new instance.
+ var args = <dynamic>[null]..addAll(arguments);
+ var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args);
+ // Without this line, calling factoryFunction as a constructor throws
+ JS('String', 'String(#)', factoryFunction);
+ // This could return an UnknownJavaScriptObject, or a native
+ // object for which there is an interceptor
+ return JS('Object', 'new #()', factoryFunction);
+
+ // TODO(sra): Investigate:
+ //
+ // var jsObj = JS('', 'Object.create(#.prototype)', constr);
+ // JS('', '#.apply(#, #)', constr, jsObj,
+ // []..addAll(arguments.map(_convertToJS)));
+ // return _wrapToDart(jsObj);
+}
diff --git a/sdk_nnbd/lib/libraries.json b/sdk_nnbd/lib/libraries.json
new file mode 100644
index 0000000..663991f
--- /dev/null
+++ b/sdk_nnbd/lib/libraries.json
@@ -0,0 +1,490 @@
+{
+ "comment:0": "NOTE: THIS FILE IS GENERATED. DO NOT EDIT.",
+ "comment:1": "Instead modify 'sdk/lib/libraries.yaml' and follow the instructions therein.",
+ "vm": {
+ "libraries": {
+ "_builtin": {
+ "uri": "../../runtime/bin/builtin.dart"
+ },
+ "cli": {
+ "patches": [
+ "../../runtime/bin/cli_patch.dart"
+ ],
+ "uri": "cli/cli.dart"
+ },
+ "core": {
+ "patches": [
+ "../../runtime/lib/core_patch.dart",
+ "../../runtime/lib/array.dart",
+ "../../runtime/lib/array_patch.dart",
+ "../../runtime/lib/bigint_patch.dart",
+ "../../runtime/lib/bool_patch.dart",
+ "../../runtime/lib/date_patch.dart",
+ "../../runtime/lib/double.dart",
+ "../../runtime/lib/double_patch.dart",
+ "../../runtime/lib/errors_patch.dart",
+ "../../runtime/lib/expando_patch.dart",
+ "../../runtime/lib/function.dart",
+ "../../runtime/lib/function_patch.dart",
+ "../../runtime/lib/growable_array.dart",
+ "../../runtime/lib/identical_patch.dart",
+ "../../runtime/lib/immutable_map.dart",
+ "../../runtime/lib/integers.dart",
+ "../../runtime/lib/integers_patch.dart",
+ "../../runtime/lib/invocation_mirror_patch.dart",
+ "../../runtime/lib/lib_prefix.dart",
+ "../../runtime/lib/map_patch.dart",
+ "../../runtime/lib/null_patch.dart",
+ "../../runtime/lib/object_patch.dart",
+ "../../runtime/lib/regexp_patch.dart",
+ "../../runtime/lib/stacktrace.dart",
+ "../../runtime/lib/stopwatch_patch.dart",
+ "../../runtime/lib/string_buffer_patch.dart",
+ "../../runtime/lib/string_patch.dart",
+ "../../runtime/lib/type_patch.dart",
+ "../../runtime/lib/uri_patch.dart",
+ "../../runtime/lib/weak_property.dart"
+ ],
+ "uri": "core/core.dart"
+ },
+ "async": {
+ "patches": [
+ "../../runtime/lib/async_patch.dart",
+ "../../runtime/lib/deferred_load_patch.dart",
+ "../../runtime/lib/schedule_microtask_patch.dart",
+ "../../runtime/lib/timer_patch.dart"
+ ],
+ "uri": "async/async.dart"
+ },
+ "collection": {
+ "patches": [
+ "../../runtime/lib/collection_patch.dart",
+ "../../runtime/lib/compact_hash.dart"
+ ],
+ "uri": "collection/collection.dart"
+ },
+ "ffi": {
+ "patches": [
+ "../../runtime/lib/ffi_patch.dart",
+ "../../runtime/lib/ffi_dynamic_library_patch.dart",
+ "../../runtime/lib/ffi_native_type_patch.dart"
+ ],
+ "uri": "ffi/ffi.dart"
+ },
+ "wasm": {
+ "patches": [
+ "../../runtime/lib/wasm_patch.dart"
+ ],
+ "uri": "wasm/wasm.dart"
+ },
+ "typed_data": {
+ "patches": "../../runtime/lib/typed_data_patch.dart",
+ "uri": "typed_data/typed_data.dart"
+ },
+ "nativewrappers": {
+ "uri": "html/dartium/nativewrappers.dart"
+ },
+ "developer": {
+ "patches": [
+ "../../runtime/lib/developer.dart",
+ "../../runtime/lib/profiler.dart",
+ "../../runtime/lib/timeline.dart"
+ ],
+ "uri": "developer/developer.dart"
+ },
+ "isolate": {
+ "patches": [
+ "../../runtime/lib/isolate_patch.dart",
+ "../../runtime/lib/timer_impl.dart"
+ ],
+ "uri": "isolate/isolate.dart"
+ },
+ "mirrors": {
+ "patches": [
+ "../../runtime/lib/mirrors_patch.dart",
+ "../../runtime/lib/mirrors_impl.dart",
+ "../../runtime/lib/mirror_reference.dart"
+ ],
+ "uri": "mirrors/mirrors.dart"
+ },
+ "_vmservice": {
+ "uri": "vmservice/vmservice.dart"
+ },
+ "io": {
+ "patches": [
+ "../../runtime/bin/common_patch.dart",
+ "../../runtime/bin/directory_patch.dart",
+ "../../runtime/bin/eventhandler_patch.dart",
+ "../../runtime/bin/file_patch.dart",
+ "../../runtime/bin/file_system_entity_patch.dart",
+ "../../runtime/bin/filter_patch.dart",
+ "../../runtime/bin/io_service_patch.dart",
+ "../../runtime/bin/namespace_patch.dart",
+ "../../runtime/bin/platform_patch.dart",
+ "../../runtime/bin/process_patch.dart",
+ "../../runtime/bin/socket_patch.dart",
+ "../../runtime/bin/stdio_patch.dart",
+ "../../runtime/bin/secure_socket_patch.dart",
+ "../../runtime/bin/sync_socket_patch.dart"
+ ],
+ "uri": "io/io.dart"
+ },
+ "_internal": {
+ "patches": [
+ "../../runtime/lib/internal_patch.dart",
+ "../../runtime/lib/class_id_fasta.dart",
+ "../../runtime/lib/print_patch.dart",
+ "../../runtime/lib/symbol_patch.dart",
+ "internal/patch.dart"
+ ],
+ "uri": "internal/internal.dart"
+ },
+ "convert": {
+ "patches": "../../runtime/lib/convert_patch.dart",
+ "uri": "convert/convert.dart"
+ },
+ "profiler": {
+ "uri": "profiler/profiler.dart"
+ },
+ "math": {
+ "patches": "../../runtime/lib/math_patch.dart",
+ "uri": "math/math.dart"
+ },
+ "_http": {
+ "uri": "_http/http.dart"
+ },
+ "vmservice_io": {
+ "uri": "../../runtime/bin/vmservice/vmservice_io.dart"
+ }
+ }
+ },
+ "none": {
+ "libraries": {}
+ },
+ "dart2js": {
+ "libraries": {
+ "async": {
+ "patches": "_internal/js_runtime/lib/async_patch.dart",
+ "uri": "async/async.dart"
+ },
+ "_interceptors": {
+ "uri": "_internal/js_runtime/lib/interceptors.dart"
+ },
+ "mirrors": {
+ "patches": "_internal/js_runtime/lib/mirrors_patch_cfe.dart",
+ "supported": false,
+ "uri": "mirrors/mirrors.dart"
+ },
+ "_js_embedded_names": {
+ "uri": "_internal/js_runtime/lib/shared/embedded_names.dart"
+ },
+ "io": {
+ "patches": "_internal/js_runtime/lib/io_patch.dart",
+ "supported": false,
+ "uri": "io/io.dart"
+ },
+ "_internal": {
+ "patches": "_internal/js_runtime/lib/internal_patch.dart",
+ "uri": "internal/internal.dart"
+ },
+ "_metadata": {
+ "uri": "html/html_common/metadata.dart"
+ },
+ "_async_await_error_codes": {
+ "uri": "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+ },
+ "_http": {
+ "uri": "_http/http.dart"
+ },
+ "_js_primitives": {
+ "uri": "_internal/js_runtime/lib/js_primitives.dart"
+ },
+ "_js_helper": {
+ "uri": "_internal/js_runtime/lib/js_helper.dart"
+ },
+ "_chrome": {
+ "uri": "_chrome/dart2js/chrome_dart2js.dart"
+ },
+ "js": {
+ "uri": "js/dart2js/js_dart2js.dart"
+ },
+ "html_common": {
+ "uri": "html/html_common/html_common_dart2js.dart"
+ },
+ "_recipe_syntax": {
+ "uri": "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+ },
+ "_native_typed_data": {
+ "uri": "_internal/js_runtime/lib/native_typed_data.dart"
+ },
+ "_js_names": {
+ "uri": "_internal/js_runtime/lib/js_names.dart"
+ },
+ "core": {
+ "patches": "_internal/js_runtime/lib/core_patch.dart",
+ "uri": "core/core.dart"
+ },
+ "collection": {
+ "patches": "_internal/js_runtime/lib/collection_patch.dart",
+ "uri": "collection/collection.dart"
+ },
+ "js_util": {
+ "uri": "js_util/dart2js/js_util_dart2js.dart"
+ },
+ "typed_data": {
+ "patches": "_internal/js_runtime/lib/typed_data_patch.dart",
+ "uri": "typed_data/typed_data.dart"
+ },
+ "web_audio": {
+ "uri": "web_audio/dart2js/web_audio_dart2js.dart"
+ },
+ "html": {
+ "uri": "html/dart2js/html_dart2js.dart"
+ },
+ "isolate": {
+ "patches": "_internal/js_runtime/lib/isolate_patch.dart",
+ "supported": false,
+ "uri": "isolate/isolate.dart"
+ },
+ "developer": {
+ "patches": "_internal/js_runtime/lib/developer_patch.dart",
+ "uri": "developer/developer.dart"
+ },
+ "web_gl": {
+ "uri": "web_gl/dart2js/web_gl_dart2js.dart"
+ },
+ "indexed_db": {
+ "uri": "indexed_db/dart2js/indexed_db_dart2js.dart"
+ },
+ "_js": {
+ "patches": "js/_js_client.dart",
+ "uri": "js/_js.dart"
+ },
+ "convert": {
+ "patches": "_internal/js_runtime/lib/convert_patch.dart",
+ "uri": "convert/convert.dart"
+ },
+ "math": {
+ "patches": "_internal/js_runtime/lib/math_patch.dart",
+ "uri": "math/math.dart"
+ },
+ "_foreign_helper": {
+ "uri": "_internal/js_runtime/lib/foreign_helper.dart"
+ },
+ "web_sql": {
+ "uri": "web_sql/dart2js/web_sql_dart2js.dart"
+ },
+ "_rti": {
+ "uri": "_internal/js_runtime/lib/rti.dart"
+ },
+ "svg": {
+ "uri": "svg/dart2js/svg_dart2js.dart"
+ }
+ }
+ },
+ "dartdevc": {
+ "libraries": {
+ "async": {
+ "patches": "_internal/js_dev_runtime/patch/async_patch.dart",
+ "uri": "async/async.dart"
+ },
+ "_runtime": {
+ "uri": "_internal/js_dev_runtime/private/ddc_runtime/runtime.dart"
+ },
+ "_interceptors": {
+ "uri": "_internal/js_dev_runtime/private/interceptors.dart"
+ },
+ "mirrors": {
+ "patches": "_internal/js_dev_runtime/patch/mirrors_patch.dart",
+ "supported": false,
+ "uri": "mirrors/mirrors.dart"
+ },
+ "_debugger": {
+ "uri": "_internal/js_dev_runtime/private/debugger.dart"
+ },
+ "io": {
+ "patches": "_internal/js_dev_runtime/patch/io_patch.dart",
+ "supported": false,
+ "uri": "io/io.dart"
+ },
+ "_internal": {
+ "patches": "_internal/js_dev_runtime/patch/internal_patch.dart",
+ "uri": "internal/internal.dart"
+ },
+ "_metadata": {
+ "uri": "html/html_common/metadata.dart"
+ },
+ "_http": {
+ "uri": "_http/http.dart"
+ },
+ "_js_primitives": {
+ "uri": "_internal/js_dev_runtime/private/js_primitives.dart"
+ },
+ "_js_helper": {
+ "uri": "_internal/js_dev_runtime/private/js_helper.dart"
+ },
+ "js": {
+ "uri": "_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart"
+ },
+ "_js_mirrors": {
+ "uri": "_internal/js_dev_runtime/private/js_mirrors.dart"
+ },
+ "html_common": {
+ "uri": "html/html_common/html_common_dart2js.dart"
+ },
+ "_native_typed_data": {
+ "uri": "_internal/js_dev_runtime/private/native_typed_data.dart"
+ },
+ "core": {
+ "patches": "_internal/js_dev_runtime/patch/core_patch.dart",
+ "uri": "core/core.dart"
+ },
+ "js_util": {
+ "uri": "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
+ },
+ "collection": {
+ "patches": "_internal/js_dev_runtime/patch/collection_patch.dart",
+ "uri": "collection/collection.dart"
+ },
+ "typed_data": {
+ "patches": "_internal/js_dev_runtime/patch/typed_data_patch.dart",
+ "uri": "typed_data/typed_data.dart"
+ },
+ "web_audio": {
+ "uri": "web_audio/dart2js/web_audio_dart2js.dart"
+ },
+ "html": {
+ "uri": "html/dart2js/html_dart2js.dart"
+ },
+ "developer": {
+ "patches": "_internal/js_dev_runtime/patch/developer_patch.dart",
+ "uri": "developer/developer.dart"
+ },
+ "isolate": {
+ "patches": "_internal/js_dev_runtime/patch/isolate_patch.dart",
+ "supported": false,
+ "uri": "isolate/isolate.dart"
+ },
+ "web_gl": {
+ "uri": "web_gl/dart2js/web_gl_dart2js.dart"
+ },
+ "indexed_db": {
+ "uri": "indexed_db/dart2js/indexed_db_dart2js.dart"
+ },
+ "convert": {
+ "patches": "_internal/js_dev_runtime/patch/convert_patch.dart",
+ "uri": "convert/convert.dart"
+ },
+ "_isolate_helper": {
+ "uri": "_internal/js_dev_runtime/private/isolate_helper.dart"
+ },
+ "math": {
+ "patches": "_internal/js_dev_runtime/patch/math_patch.dart",
+ "uri": "math/math.dart"
+ },
+ "_foreign_helper": {
+ "uri": "_internal/js_dev_runtime/private/foreign_helper.dart"
+ },
+ "web_sql": {
+ "uri": "web_sql/dart2js/web_sql_dart2js.dart"
+ },
+ "svg": {
+ "uri": "svg/dart2js/svg_dart2js.dart"
+ }
+ }
+ },
+ "dart2js_server": {
+ "libraries": {
+ "async": {
+ "patches": "_internal/js_runtime/lib/async_patch.dart",
+ "uri": "async/async.dart"
+ },
+ "mirrors": {
+ "patches": "_internal/js_runtime/lib/mirrors_patch_cfe.dart",
+ "supported": false,
+ "uri": "mirrors/mirrors.dart"
+ },
+ "_interceptors": {
+ "uri": "_internal/js_runtime/lib/interceptors.dart"
+ },
+ "_js_embedded_names": {
+ "uri": "_internal/js_runtime/lib/shared/embedded_names.dart"
+ },
+ "io": {
+ "patches": "_internal/js_runtime/lib/io_patch.dart",
+ "supported": false,
+ "uri": "io/io.dart"
+ },
+ "_internal": {
+ "patches": "_internal/js_runtime/lib/internal_patch.dart",
+ "uri": "internal/internal.dart"
+ },
+ "_async_await_error_codes": {
+ "uri": "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+ },
+ "_http": {
+ "uri": "_http/http.dart"
+ },
+ "_js_helper": {
+ "uri": "_internal/js_runtime/lib/js_helper.dart"
+ },
+ "_js_primitives": {
+ "uri": "_internal/js_runtime/lib/js_primitives.dart"
+ },
+ "js": {
+ "uri": "js/dart2js/js_dart2js.dart"
+ },
+ "_recipe_syntax": {
+ "uri": "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+ },
+ "_native_typed_data": {
+ "uri": "_internal/js_runtime/lib/native_typed_data.dart"
+ },
+ "core": {
+ "patches": "_internal/js_runtime/lib/core_patch.dart",
+ "uri": "core/core.dart"
+ },
+ "_js_names": {
+ "uri": "_internal/js_runtime/lib/js_names.dart"
+ },
+ "js_util": {
+ "uri": "js_util/dart2js/js_util_dart2js.dart"
+ },
+ "collection": {
+ "patches": "_internal/js_runtime/lib/collection_patch.dart",
+ "uri": "collection/collection.dart"
+ },
+ "typed_data": {
+ "patches": "_internal/js_runtime/lib/typed_data_patch.dart",
+ "uri": "typed_data/typed_data.dart"
+ },
+ "isolate": {
+ "patches": "_internal/js_runtime/lib/isolate_patch.dart",
+ "supported": false,
+ "uri": "isolate/isolate.dart"
+ },
+ "developer": {
+ "patches": "_internal/js_runtime/lib/developer_patch.dart",
+ "uri": "developer/developer.dart"
+ },
+ "_js": {
+ "patches": "js/_js_server.dart",
+ "uri": "js/_js.dart"
+ },
+ "convert": {
+ "patches": "_internal/js_runtime/lib/convert_patch.dart",
+ "uri": "convert/convert.dart"
+ },
+ "math": {
+ "patches": "_internal/js_runtime/lib/math_patch.dart",
+ "uri": "math/math.dart"
+ },
+ "_foreign_helper": {
+ "uri": "_internal/js_runtime/lib/foreign_helper.dart"
+ },
+ "_rti": {
+ "uri": "_internal/js_runtime/lib/rti.dart"
+ }
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/libraries.yaml b/sdk_nnbd/lib/libraries.yaml
new file mode 100644
index 0000000..f33a42b
--- /dev/null
+++ b/sdk_nnbd/lib/libraries.yaml
@@ -0,0 +1,479 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Note: if you edit this file, you must also edit libraries.json in this
+# directory:
+#
+# python ./tools/yaml2json.py sdk/lib/libraries.yaml sdk/lib/libraries.json
+#
+# We currently have several different files that needs to be updated when
+# changing libraries, sources, and patch files. See
+# https://github.com/dart-lang/sdk/issues/28836.
+
+none:
+ libraries: {}
+
+vm:
+ libraries:
+ _builtin:
+ uri: "../../runtime/bin/builtin.dart"
+
+ _internal:
+ uri: "internal/internal.dart"
+ patches:
+ - "../../runtime/lib/internal_patch.dart"
+ - "../../runtime/lib/class_id_fasta.dart"
+ - "../../runtime/lib/print_patch.dart"
+ - "../../runtime/lib/symbol_patch.dart"
+ - "internal/patch.dart"
+
+ async:
+ uri: "async/async.dart"
+ patches:
+ - "../../runtime/lib/async_patch.dart"
+ - "../../runtime/lib/deferred_load_patch.dart"
+ - "../../runtime/lib/schedule_microtask_patch.dart"
+ - "../../runtime/lib/timer_patch.dart"
+
+ collection:
+ uri: "collection/collection.dart"
+ patches:
+ - "../../runtime/lib/collection_patch.dart"
+ - "../../runtime/lib/compact_hash.dart"
+
+ convert:
+ uri: "convert/convert.dart"
+ patches: "../../runtime/lib/convert_patch.dart"
+
+ core:
+ uri: "core/core.dart"
+ patches:
+ - "../../runtime/lib/core_patch.dart"
+ - "../../runtime/lib/array.dart"
+ - "../../runtime/lib/array_patch.dart"
+ - "../../runtime/lib/bigint_patch.dart"
+ - "../../runtime/lib/bool_patch.dart"
+ - "../../runtime/lib/date_patch.dart"
+ - "../../runtime/lib/double.dart"
+ - "../../runtime/lib/double_patch.dart"
+ - "../../runtime/lib/errors_patch.dart"
+ - "../../runtime/lib/expando_patch.dart"
+ - "../../runtime/lib/function.dart"
+ - "../../runtime/lib/function_patch.dart"
+ - "../../runtime/lib/growable_array.dart"
+ - "../../runtime/lib/identical_patch.dart"
+ - "../../runtime/lib/immutable_map.dart"
+ - "../../runtime/lib/integers.dart"
+ - "../../runtime/lib/integers_patch.dart"
+ - "../../runtime/lib/invocation_mirror_patch.dart"
+ - "../../runtime/lib/lib_prefix.dart"
+ - "../../runtime/lib/map_patch.dart"
+ - "../../runtime/lib/null_patch.dart"
+ - "../../runtime/lib/object_patch.dart"
+ - "../../runtime/lib/regexp_patch.dart"
+ - "../../runtime/lib/stacktrace.dart"
+ - "../../runtime/lib/stopwatch_patch.dart"
+ - "../../runtime/lib/string_buffer_patch.dart"
+ - "../../runtime/lib/string_patch.dart"
+ - "../../runtime/lib/type_patch.dart"
+ - "../../runtime/lib/uri_patch.dart"
+ - "../../runtime/lib/weak_property.dart"
+
+ developer:
+ uri: "developer/developer.dart"
+ patches:
+ - "../../runtime/lib/developer.dart"
+ - "../../runtime/lib/profiler.dart"
+ - "../../runtime/lib/timeline.dart"
+
+ ffi:
+ uri: "ffi/ffi.dart"
+ patches:
+ - "../../runtime/lib/ffi_patch.dart"
+ - "../../runtime/lib/ffi_dynamic_library_patch.dart"
+ - "../../runtime/lib/ffi_native_type_patch.dart"
+
+ wasm:
+ uri: "wasm/wasm.dart"
+ patches:
+ - "../../runtime/lib/wasm_patch.dart"
+
+ _http:
+ uri: "_http/http.dart"
+
+ io:
+ uri: "io/io.dart"
+ patches:
+ - "../../runtime/bin/common_patch.dart"
+ - "../../runtime/bin/directory_patch.dart"
+ - "../../runtime/bin/eventhandler_patch.dart"
+ - "../../runtime/bin/file_patch.dart"
+ - "../../runtime/bin/file_system_entity_patch.dart"
+ - "../../runtime/bin/filter_patch.dart"
+ - "../../runtime/bin/io_service_patch.dart"
+ - "../../runtime/bin/namespace_patch.dart"
+ - "../../runtime/bin/platform_patch.dart"
+ - "../../runtime/bin/process_patch.dart"
+ - "../../runtime/bin/socket_patch.dart"
+ - "../../runtime/bin/stdio_patch.dart"
+ - "../../runtime/bin/secure_socket_patch.dart"
+ - "../../runtime/bin/sync_socket_patch.dart"
+
+ isolate:
+ uri: "isolate/isolate.dart"
+ patches:
+ - "../../runtime/lib/isolate_patch.dart"
+ - "../../runtime/lib/timer_impl.dart"
+
+ math:
+ uri: "math/math.dart"
+ patches: "../../runtime/lib/math_patch.dart"
+
+ mirrors:
+ uri: "mirrors/mirrors.dart"
+ patches:
+ - "../../runtime/lib/mirrors_patch.dart"
+ - "../../runtime/lib/mirrors_impl.dart"
+ - "../../runtime/lib/mirror_reference.dart"
+
+ nativewrappers:
+ uri: "html/dartium/nativewrappers.dart"
+
+ profiler:
+ uri: "profiler/profiler.dart"
+
+ cli:
+ uri: "cli/cli.dart"
+ patches:
+ - "../../runtime/bin/cli_patch.dart"
+
+ typed_data:
+ uri: "typed_data/typed_data.dart"
+ patches: "../../runtime/lib/typed_data_patch.dart"
+
+ _vmservice:
+ uri: "vmservice/vmservice.dart"
+
+ vmservice_io:
+ uri: "../../runtime/bin/vmservice/vmservice_io.dart"
+
+dart2js:
+ libraries:
+ async:
+ uri: "async/async.dart"
+ patches: "_internal/js_runtime/lib/async_patch.dart"
+
+ _chrome:
+ uri: "_chrome/dart2js/chrome_dart2js.dart"
+
+ collection:
+ uri: "collection/collection.dart"
+ patches: "_internal/js_runtime/lib/collection_patch.dart"
+
+ convert:
+ uri: "convert/convert.dart"
+ patches: "_internal/js_runtime/lib/convert_patch.dart"
+
+ core:
+ uri: "core/core.dart"
+ patches: "_internal/js_runtime/lib/core_patch.dart"
+
+ developer:
+ uri: "developer/developer.dart"
+ patches: "_internal/js_runtime/lib/developer_patch.dart"
+
+ html:
+ uri: "html/dart2js/html_dart2js.dart"
+
+ html_common:
+ uri: "html/html_common/html_common_dart2js.dart"
+
+ indexed_db:
+ uri: "indexed_db/dart2js/indexed_db_dart2js.dart"
+
+ _http:
+ uri: "_http/http.dart"
+
+ io:
+ uri: "io/io.dart"
+ patches: "_internal/js_runtime/lib/io_patch.dart"
+ supported: false
+
+ isolate:
+ uri: "isolate/isolate.dart"
+ patches: "_internal/js_runtime/lib/isolate_patch.dart"
+ supported: false
+
+ js:
+ uri: "js/dart2js/js_dart2js.dart"
+
+ _js:
+ uri: "js/_js.dart"
+ patches: "js/_js_client.dart"
+
+ js_util:
+ uri: "js_util/dart2js/js_util_dart2js.dart"
+
+ math:
+ uri: "math/math.dart"
+ patches: "_internal/js_runtime/lib/math_patch.dart"
+
+ mirrors:
+ uri: "mirrors/mirrors.dart"
+ patches: "_internal/js_runtime/lib/mirrors_patch_cfe.dart"
+ supported: false
+
+ typed_data:
+ uri: "typed_data/typed_data.dart"
+ patches: "_internal/js_runtime/lib/typed_data_patch.dart"
+
+ _native_typed_data:
+ uri: "_internal/js_runtime/lib/native_typed_data.dart"
+
+ svg:
+ uri: "svg/dart2js/svg_dart2js.dart"
+
+ web_audio:
+ uri: "web_audio/dart2js/web_audio_dart2js.dart"
+
+ web_gl:
+ uri: "web_gl/dart2js/web_gl_dart2js.dart"
+
+ web_sql:
+ uri: "web_sql/dart2js/web_sql_dart2js.dart"
+
+ _internal:
+ uri: "internal/internal.dart"
+ patches: "_internal/js_runtime/lib/internal_patch.dart"
+
+ _js_helper:
+ uri: "_internal/js_runtime/lib/js_helper.dart"
+
+ _rti:
+ uri: "_internal/js_runtime/lib/rti.dart"
+
+ _interceptors:
+ uri: "_internal/js_runtime/lib/interceptors.dart"
+
+ _foreign_helper:
+ uri: "_internal/js_runtime/lib/foreign_helper.dart"
+
+ _js_names:
+ uri: "_internal/js_runtime/lib/js_names.dart"
+
+ _js_primitives:
+ uri: "_internal/js_runtime/lib/js_primitives.dart"
+
+ _js_embedded_names:
+ uri: "_internal/js_runtime/lib/shared/embedded_names.dart"
+
+ _async_await_error_codes:
+ uri: "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+
+ _recipe_syntax:
+ uri: "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+
+ _metadata:
+ uri: "html/html_common/metadata.dart"
+
+dart2js_server:
+ libraries:
+ async:
+ uri: "async/async.dart"
+ patches: "_internal/js_runtime/lib/async_patch.dart"
+
+ collection:
+ uri: "collection/collection.dart"
+ patches: "_internal/js_runtime/lib/collection_patch.dart"
+
+ convert:
+ uri: "convert/convert.dart"
+ patches: "_internal/js_runtime/lib/convert_patch.dart"
+
+ core:
+ uri: "core/core.dart"
+ patches: "_internal/js_runtime/lib/core_patch.dart"
+
+ developer:
+ uri: "developer/developer.dart"
+ patches: "_internal/js_runtime/lib/developer_patch.dart"
+
+ _http:
+ uri: "_http/http.dart"
+
+ io:
+ uri: "io/io.dart"
+ patches: "_internal/js_runtime/lib/io_patch.dart"
+ supported: false
+
+ isolate:
+ uri: "isolate/isolate.dart"
+ patches: "_internal/js_runtime/lib/isolate_patch.dart"
+ supported: false
+
+ js:
+ uri: "js/dart2js/js_dart2js.dart"
+
+ _js:
+ uri: "js/_js.dart"
+ patches: "js/_js_server.dart"
+
+ js_util:
+ uri: "js_util/dart2js/js_util_dart2js.dart"
+
+ math:
+ uri: "math/math.dart"
+ patches: "_internal/js_runtime/lib/math_patch.dart"
+
+ mirrors:
+ uri: "mirrors/mirrors.dart"
+ patches: "_internal/js_runtime/lib/mirrors_patch_cfe.dart"
+ supported: false
+
+ typed_data:
+ uri: "typed_data/typed_data.dart"
+ patches: "_internal/js_runtime/lib/typed_data_patch.dart"
+
+ _native_typed_data:
+ uri: "_internal/js_runtime/lib/native_typed_data.dart"
+
+ _internal:
+ uri: "internal/internal.dart"
+ patches: "_internal/js_runtime/lib/internal_patch.dart"
+
+ _js_helper:
+ uri: "_internal/js_runtime/lib/js_helper.dart"
+
+ _rti:
+ uri: "_internal/js_runtime/lib/rti.dart"
+
+ _interceptors:
+ uri: "_internal/js_runtime/lib/interceptors.dart"
+
+ _foreign_helper:
+ uri: "_internal/js_runtime/lib/foreign_helper.dart"
+
+ _js_names:
+ uri: "_internal/js_runtime/lib/js_names.dart"
+
+ _js_primitives:
+ uri: "_internal/js_runtime/lib/js_primitives.dart"
+
+ _js_embedded_names:
+ uri: "_internal/js_runtime/lib/shared/embedded_names.dart"
+
+ _async_await_error_codes:
+ uri: "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+
+ _recipe_syntax:
+ uri: "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+
+dartdevc:
+ libraries:
+ _runtime:
+ uri: "_internal/js_dev_runtime/private/ddc_runtime/runtime.dart"
+
+ _debugger:
+ uri: "_internal/js_dev_runtime/private/debugger.dart"
+
+ _foreign_helper:
+ uri: "_internal/js_dev_runtime/private/foreign_helper.dart"
+
+ _http:
+ uri: "_http/http.dart"
+
+ _interceptors:
+ uri: "_internal/js_dev_runtime/private/interceptors.dart"
+
+ _internal:
+ uri: "internal/internal.dart"
+ patches: "_internal/js_dev_runtime/patch/internal_patch.dart"
+
+ _isolate_helper:
+ uri: "_internal/js_dev_runtime/private/isolate_helper.dart"
+
+ _js_helper:
+ uri: "_internal/js_dev_runtime/private/js_helper.dart"
+
+ _js_mirrors:
+ uri: "_internal/js_dev_runtime/private/js_mirrors.dart"
+
+ _js_primitives:
+ uri: "_internal/js_dev_runtime/private/js_primitives.dart"
+
+ _metadata:
+ uri: "html/html_common/metadata.dart"
+
+ _native_typed_data:
+ uri: "_internal/js_dev_runtime/private/native_typed_data.dart"
+
+ async:
+ uri: "async/async.dart"
+ patches: "_internal/js_dev_runtime/patch/async_patch.dart"
+
+ collection:
+ uri: "collection/collection.dart"
+ patches: "_internal/js_dev_runtime/patch/collection_patch.dart"
+
+ convert:
+ uri: "convert/convert.dart"
+ patches: "_internal/js_dev_runtime/patch/convert_patch.dart"
+
+ core:
+ uri: "core/core.dart"
+ patches: "_internal/js_dev_runtime/patch/core_patch.dart"
+
+ developer:
+ uri: "developer/developer.dart"
+ patches: "_internal/js_dev_runtime/patch/developer_patch.dart"
+
+ io:
+ uri: "io/io.dart"
+ patches: "_internal/js_dev_runtime/patch/io_patch.dart"
+ supported: false
+
+ isolate:
+ uri: "isolate/isolate.dart"
+ patches: "_internal/js_dev_runtime/patch/isolate_patch.dart"
+ supported: false
+
+ mirrors:
+ uri: "mirrors/mirrors.dart"
+ patches: "_internal/js_dev_runtime/patch/mirrors_patch.dart"
+ supported: false
+
+ math:
+ uri: "math/math.dart"
+ patches: "_internal/js_dev_runtime/patch/math_patch.dart"
+
+ typed_data:
+ uri: "typed_data/typed_data.dart"
+ patches: "_internal/js_dev_runtime/patch/typed_data_patch.dart"
+
+ html:
+ uri: "html/dart2js/html_dart2js.dart"
+
+ html_common:
+ uri: "html/html_common/html_common_dart2js.dart"
+
+ indexed_db:
+ uri: "indexed_db/dart2js/indexed_db_dart2js.dart"
+
+ js:
+ uri: "_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart"
+
+ js_util:
+ uri: "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
+
+ svg:
+ uri: "svg/dart2js/svg_dart2js.dart"
+
+ web_audio:
+ uri: "web_audio/dart2js/web_audio_dart2js.dart"
+
+ web_gl:
+ uri: "web_gl/dart2js/web_gl_dart2js.dart"
+
+ web_sql:
+ uri: "web_sql/dart2js/web_sql_dart2js.dart"
diff --git a/sdk_nnbd/lib/math/jenkins_smi_hash.dart b/sdk_nnbd/lib/math/jenkins_smi_hash.dart
new file mode 100644
index 0000000..d756b37
--- /dev/null
+++ b/sdk_nnbd/lib/math/jenkins_smi_hash.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+part of dart.math;
+
+/// This is the [Jenkins hash function][1] but using masking to keep
+/// values in SMI range.
+///
+/// [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+///
+/// Use:
+/// Hash each value with the hash of the previous value, then get the final
+/// hash by calling finish.
+///
+/// var hash = 0;
+/// for (var value in values) {
+/// hash = JenkinsSmiHash.combine(hash, value.hashCode);
+/// }
+/// hash = JenkinsSmiHash.finish(hash);
+class _JenkinsSmiHash {
+ // TODO(11617): This class should be optimized and standardized elsewhere.
+
+ static int combine(int hash, int value) {
+ hash = 0x1fffffff & (hash + value);
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+ return hash ^ (hash >> 6);
+ }
+
+ static int finish(int hash) {
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+ hash = hash ^ (hash >> 11);
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+ }
+
+ static int hash2(a, b) => finish(combine(combine(0, a), b));
+
+ static int hash4(a, b, c, d) =>
+ finish(combine(combine(combine(combine(0, a), b), c), d));
+}
diff --git a/sdk_nnbd/lib/math/math.dart b/sdk_nnbd/lib/math/math.dart
new file mode 100644
index 0000000..548fb59
--- /dev/null
+++ b/sdk_nnbd/lib/math/math.dart
@@ -0,0 +1,179 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Mathematical constants and functions, plus a random number generator.
+///
+/// To use this library in your code:
+///
+/// import 'dart:math';
+///
+/// {@category Core}
+library dart.math;
+
+part "jenkins_smi_hash.dart";
+part "point.dart";
+part "random.dart";
+part "rectangle.dart";
+
+/// Base of the natural logarithms.
+///
+/// Typically written as "e".
+const double e = 2.718281828459045;
+
+/// Natural logarithm of 10.
+///
+/// The natural logarithm of 10 is the number such that `pow(E, LN10) == 10`.
+/// This value is not exact, but it is the closest representable double to the
+/// exact mathematical value.
+const double ln10 = 2.302585092994046;
+
+/// Natural logarithm of 2.
+///
+/// The natural logarithm of 2 is the number such that `pow(E, LN2) == 2`.
+/// This value is not exact, but it is the closest representable double to the
+/// exact mathematical value.
+const double ln2 = 0.6931471805599453;
+
+/// Base-2 logarithm of [e].
+const double log2e = 1.4426950408889634;
+
+/// Base-10 logarithm of [e].
+const double log10e = 0.4342944819032518;
+
+/// The PI constant.
+const double pi = 3.1415926535897932;
+
+/// Square root of 1/2.
+const double sqrt1_2 = 0.7071067811865476;
+
+/// Square root of 2.
+const double sqrt2 = 1.4142135623730951;
+
+/// Returns the lesser of two numbers.
+///
+/// Returns NaN if either argument is NaN.
+/// The lesser of `-0.0` and `0.0` is `-0.0`.
+/// If the arguments are otherwise equal (including int and doubles with the
+/// same mathematical value) then it is unspecified which of the two arguments
+/// is returned.
+external T min<T extends num>(T a, T b);
+
+/// Returns the larger of two numbers.
+///
+/// Returns NaN if either argument is NaN.
+/// The larger of `-0.0` and `0.0` is `0.0`. If the arguments are
+/// otherwise equal (including int and doubles with the same mathematical value)
+/// then it is unspecified which of the two arguments is returned.
+external T max<T extends num>(T a, T b);
+
+/// A variant of [atan].
+///
+/// Converts both arguments to [double]s.
+///
+/// Returns the angle in radians between the positive x-axis
+/// and the vector ([b],[a]).
+/// The result is in the range -PI..PI.
+///
+/// If [b] is positive, this is the same as `atan(b/a)`.
+///
+/// The result is negative when [a] is negative (including when [a] is the
+/// double -0.0).
+///
+/// If [a] is equal to zero, the vector ([b],[a]) is considered parallel to
+/// the x-axis, even if [b] is also equal to zero. The sign of [b] determines
+/// the direction of the vector along the x-axis.
+///
+/// Returns NaN if either argument is NaN.
+external double atan2(num a, num b);
+
+/// Returns [x] to the power of [exponent].
+///
+/// If [x] is an [int] and [exponent] is a non-negative [int], the result is
+/// an [int], otherwise both arguments are converted to doubles first, and the
+/// result is a [double].
+///
+/// For integers, the power is always equal to the mathematical result of `x` to
+/// the power `exponent`, only limited by the available memory.
+///
+/// For doubles, `pow(x, y)` handles edge cases as follows:
+///
+/// - if `y` is zero (0.0 or -0.0), the result is always 1.0.
+/// - if `x` is 1.0, the result is always 1.0.
+/// - otherwise, if either `x` or `y` is NaN then the result is NaN.
+/// - if `x` is negative (but not -0.0) and `y` is a finite non-integer, the
+/// result is NaN.
+/// - if `x` is Infinity and `y` is negative, the result is 0.0.
+/// - if `x` is Infinity and `y` is positive, the result is Infinity.
+/// - if `x` is 0.0 and `y` is negative, the result is Infinity.
+/// - if `x` is 0.0 and `y` is positive, the result is 0.0.
+/// - if `x` is -Infinity or -0.0 and `y` is an odd integer, then the result is
+/// `-pow(-x ,y)`.
+/// - if `x` is -Infinity or -0.0 and `y` is not an odd integer, then the result
+/// is the same as `pow(-x , y)`.
+/// - if `y` is Infinity and the absolute value of `x` is less than 1, the
+/// result is 0.0.
+/// - if `y` is Infinity and `x` is -1, the result is 1.0.
+/// - if `y` is Infinity and the absolute value of `x` is greater than 1,
+/// the result is Infinity.
+/// - if `y` is -Infinity, the result is `1/pow(x, Infinity)`.
+///
+/// This corresponds to the `pow` function defined in the IEEE Standard
+/// 754-2008.
+///
+/// Notice that the result may overflow. If integers are represented as 64-bit
+/// numbers, an integer result may be truncated, and a double result may
+/// overflow to positive or negative [double.infinity].
+external num pow(num x, num exponent);
+
+/// Converts [radians] to a [double] and returns the sine of the value.
+///
+/// If [radians] is not a finite number, the result is NaN.
+external double sin(num radians);
+
+/// Converts [radians] to a [double] and returns the cosine of the value.
+///
+/// If [radians] is not a finite number, the result is NaN.
+external double cos(num radians);
+
+/// Converts [radians] to a [double] and returns the tangent of the value.
+///
+/// The tangent function is equivalent to `sin(radians)/cos(radians)` and may be
+/// infinite (positive or negative) when `cos(radians)` is equal to zero.
+/// If [radians] is not a finite number, the result is NaN.
+external double tan(num radians);
+
+/// Converts [x] to a [double] and returns its arc cosine in radians.
+///
+/// Returns a value in the range 0..PI, or NaN if [x] is outside
+/// the range -1..1.
+external double acos(num x);
+
+/// Converts [x] to a [double] and returns its arc sine in radians.
+///
+/// Returns a value in the range -PI/2..PI/2, or NaN if [x] is outside
+/// the range -1..1.
+external double asin(num x);
+
+/// Converts [x] to a [double] and returns its arc tangent in radians.
+///
+/// Returns a value in the range -PI/2..PI/2, or NaN if [x] is NaN.
+external double atan(num x);
+
+/// Converts [x] to a [double] and returns the positive square root of the
+/// value.
+///
+/// Returns -0.0 if [x] is -0.0, and NaN if [x] is otherwise negative or NaN.
+external double sqrt(num x);
+
+/// Converts [x] to a [double] and returns the natural exponent, [e],
+/// to the power [x].
+///
+/// Returns NaN if [x] is NaN.
+external double exp(num x);
+
+/// Converts [x] to a [double] and returns the natural logarithm of the value.
+///
+/// Returns negative infinity if [x] is equal to zero.
+/// Returns NaN if [x] is NaN or less than zero.
+external double log(num x);
diff --git a/sdk_nnbd/lib/math/math_sources.gni b/sdk_nnbd/lib/math/math_sources.gni
new file mode 100644
index 0000000..ff8f3fa
--- /dev/null
+++ b/sdk_nnbd/lib/math/math_sources.gni
@@ -0,0 +1,13 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+math_sdk_sources = [
+ "math.dart",
+
+ # The above file needs to be first as it lists the parts below.
+ "jenkins_smi_hash.dart",
+ "point.dart",
+ "random.dart",
+ "rectangle.dart",
+]
diff --git a/sdk_nnbd/lib/math/point.dart b/sdk_nnbd/lib/math/point.dart
new file mode 100644
index 0000000..1015e7b
--- /dev/null
+++ b/sdk_nnbd/lib/math/point.dart
@@ -0,0 +1,74 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+part of dart.math;
+
+/// A utility class for representing two-dimensional positions.
+class Point<T extends num> {
+ final T x;
+ final T y;
+
+ const Point(T x, T y)
+ : this.x = x,
+ this.y = y;
+
+ String toString() => 'Point($x, $y)';
+
+ /// A `Point` is only equal to another `Point` with the same coordinates.
+ ///
+ /// This point is equal to `other` if, and only if,
+ /// `other` is a `Point` with
+ /// [x] equal to `other.x` and [y] equal to `other.y`.
+ bool operator ==(dynamic other) =>
+ // Cannot change parameter type to `Object` in case some class
+ // inherits the type and uses their argument dynamically.
+ other is Point && x == other.x && y == other.y;
+
+ int get hashCode => _JenkinsSmiHash.hash2(x.hashCode, y.hashCode);
+
+ /// Add [other] to `this`, as if both points were vectors.
+ ///
+ /// Returns the resulting "vector" as a Point.
+ Point<T> operator +(Point<T> other) {
+ return Point<T>(x + other.x, y + other.y);
+ }
+
+ /// Subtract [other] from `this`, as if both points were vectors.
+ ///
+ /// Returns the resulting "vector" as a Point.
+ Point<T> operator -(Point<T> other) {
+ return Point<T>(x - other.x, y - other.y);
+ }
+
+ /// Scale this point by [factor] as if it were a vector.
+ ///
+ /// *Important* *Note*: This function accepts a `num` as its argument only so
+ /// that you can scale Point<double> objects by an `int` factor. Because the
+ /// star operator always returns the same type of Point that originally called
+ /// it, passing in a double [factor] on a `Point<int>` _causes_ _a_
+ /// _runtime_ _error_ in checked mode.
+ Point<T> operator *(num /*T|int*/ factor) {
+ return Point<T>((x * factor), (y * factor));
+ }
+
+ /// Get the straight line (Euclidean) distance between the origin (0, 0) and
+ /// this point.
+ double get magnitude => sqrt(x * x + y * y);
+
+ /// Returns the distance between `this` and [other].
+ double distanceTo(Point<T> other) {
+ var dx = x - other.x;
+ var dy = y - other.y;
+ return sqrt(dx * dx + dy * dy);
+ }
+
+ /// Returns the squared distance between `this` and [other].
+ ///
+ /// Squared distances can be used for comparisons when the actual value is not
+ /// required.
+ T squaredDistanceTo(Point<T> other) {
+ var dx = x - other.x;
+ var dy = y - other.y;
+ return dx * dx + dy * dy;
+ }
+}
diff --git a/sdk_nnbd/lib/math/random.dart b/sdk_nnbd/lib/math/random.dart
new file mode 100644
index 0000000..80e588b
--- /dev/null
+++ b/sdk_nnbd/lib/math/random.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.math;
+
+/// A generator of random bool, int, or double values.
+///
+/// The default implementation supplies a stream of pseudo-random bits that are
+/// not suitable for cryptographic purposes.
+///
+/// Use the [Random.secure]() constructor for cryptographic purposes.
+abstract class Random {
+ /// Creates a random number generator.
+ ///
+ /// The optional parameter [seed] is used to initialize the
+ /// internal state of the generator. The implementation of the
+ /// random stream can change between releases of the library.
+ external factory Random([int seed]);
+
+ /// Creates a cryptographically secure random number generator.
+ ///
+ /// If the program cannot provide a cryptographically secure
+ /// source of random numbers, it throws an [UnsupportedError].
+ external factory Random.secure();
+
+ /// Generates a non-negative random integer uniformly distributed in the range
+ /// from 0, inclusive, to [max], exclusive.
+ ///
+ /// Implementation note: The default implementation supports [max] values
+ /// between 1 and (1<<32) inclusive.
+ int nextInt(int max);
+
+ /// Generates a non-negative random floating point value uniformly distributed
+ /// in the range from 0.0, inclusive, to 1.0, exclusive.
+ double nextDouble();
+
+ /// Generates a random boolean value.
+ bool nextBool();
+}
diff --git a/sdk_nnbd/lib/math/rectangle.dart b/sdk_nnbd/lib/math/rectangle.dart
new file mode 100644
index 0000000..6e72036
--- /dev/null
+++ b/sdk_nnbd/lib/math/rectangle.dart
@@ -0,0 +1,247 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+part of dart.math;
+
+/// A base class for representing two-dimensional axis-aligned rectangles.
+///
+/// This rectangle uses a left-handed Cartesian coordinate system, with x
+/// directed to the right and y directed down, as per the convention in 2D
+/// computer graphics.
+///
+/// See also:
+/// [W3C Coordinate Systems Specification](http://www.w3.org/TR/SVG/coords.html#InitialCoordinateSystem).
+///
+/// The rectangle is the set of points with representable coordinates greater
+/// than or equal to left/top, and with distance to left/top no greater than
+/// width/height (to the limit of the precision of the coordinates).
+abstract class _RectangleBase<T extends num> {
+ const _RectangleBase();
+
+ /// The x-coordinate of the left edge.
+ T get left;
+
+ /// The y-coordinate of the top edge.
+ T get top;
+
+ /// The width of the rectangle.
+ T get width;
+
+ /// The height of the rectangle.
+ T get height;
+
+ /// The x-coordinate of the right edge.
+ T get right => left + width;
+
+ /// The y-coordinate of the bottom edge.
+ T get bottom => top + height;
+
+ String toString() {
+ return 'Rectangle ($left, $top) $width x $height';
+ }
+
+ bool operator ==(dynamic other) =>
+ // Can't change argument type to `Object` since subclasses inherit it
+ // and uses their argument dynamically.
+ other is Rectangle &&
+ left == other.left &&
+ top == other.top &&
+ right == other.right &&
+ bottom == other.bottom;
+
+ int get hashCode => _JenkinsSmiHash.hash4(
+ left.hashCode, top.hashCode, right.hashCode, bottom.hashCode);
+
+ /// Computes the intersection of `this` and [other].
+ ///
+ /// The intersection of two axis-aligned rectangles, if any, is always another
+ /// axis-aligned rectangle.
+ ///
+ /// Returns the intersection of this and `other`, or `null` if they don't
+ /// intersect.
+ Rectangle<T> intersection(Rectangle<T> other) {
+ var x0 = max(left, other.left);
+ var x1 = min(left + width, other.left + other.width);
+
+ if (x0 <= x1) {
+ var y0 = max(top, other.top);
+ var y1 = min(top + height, other.top + other.height);
+
+ if (y0 <= y1) {
+ return Rectangle<T>(x0, y0, x1 - x0, y1 - y0);
+ }
+ }
+ return null;
+ }
+
+ /// Returns true if `this` intersects [other].
+ bool intersects(Rectangle<num> other) {
+ return (left <= other.left + other.width &&
+ other.left <= left + width &&
+ top <= other.top + other.height &&
+ other.top <= top + height);
+ }
+
+ /// Returns a new rectangle which completely contains `this` and [other].
+ Rectangle<T> boundingBox(Rectangle<T> other) {
+ var right = max(this.left + this.width, other.left + other.width);
+ var bottom = max(this.top + this.height, other.top + other.height);
+
+ var left = min(this.left, other.left);
+ var top = min(this.top, other.top);
+
+ return Rectangle<T>(left, top, right - left, bottom - top);
+ }
+
+ /// Tests whether `this` entirely contains [another].
+ bool containsRectangle(Rectangle<num> another) {
+ return left <= another.left &&
+ left + width >= another.left + another.width &&
+ top <= another.top &&
+ top + height >= another.top + another.height;
+ }
+
+ /// Tests whether [another] is inside or along the edges of `this`.
+ bool containsPoint(Point<num> another) {
+ return another.x >= left &&
+ another.x <= left + width &&
+ another.y >= top &&
+ another.y <= top + height;
+ }
+
+ Point<T> get topLeft => Point<T>(this.left, this.top);
+ Point<T> get topRight => Point<T>(this.left + this.width, this.top);
+ Point<T> get bottomRight =>
+ Point<T>(this.left + this.width, this.top + this.height);
+ Point<T> get bottomLeft => Point<T>(this.left, this.top + this.height);
+}
+
+/// A class for representing two-dimensional rectangles whose properties are
+/// immutable.
+class Rectangle<T extends num> extends _RectangleBase<T> {
+ final T left;
+ final T top;
+ final T width;
+ final T height;
+
+ /// Create a rectangle spanned by `(left, top)` and
+ /// `(left+width, top+height)`.
+ ///
+ /// The rectangle contains the points
+ /// with x-coordinate between `left` and `left + width`, and
+ /// with y-coordinate between `top` and `top + height`, both inclusive.
+ ///
+ /// The `width` and `height` should be non-negative.
+ /// If `width` or `height` are negative, they are clamped to zero.
+ ///
+ /// If `width` and `height` are zero, the "rectangle" comprises only the
+ /// single point `(left, top)`.
+ const Rectangle(this.left, this.top, T width, T height)
+ : this.width = (width < 0) ? -width * 0 : width, // Inline _clampToZero.
+ this.height = (height < 0) ? -height * 0 : height;
+
+ /// Create a rectangle spanned by the points [a] and [b];
+ ///
+ /// The rectangle contains the points
+ /// with x-coordinate between `a.x` and `b.x`, and
+ /// with y-coordinate between `a.y` and `b.y`, both inclusive.
+ ///
+ /// If the distance between `a.x` and `b.x` is not representable
+ /// (which can happen if one or both is a double),
+ /// the actual right edge might be slightly off from `max(a.x, b.x)`.
+ /// Similar for the y-coordinates and the bottom edge.
+ factory Rectangle.fromPoints(Point<T> a, Point<T> b) {
+ T left = min(a.x, b.x);
+ T width = max(a.x, b.x) - left;
+ T top = min(a.y, b.y);
+ T height = max(a.y, b.y) - top;
+ return Rectangle<T>(left, top, width, height);
+ }
+}
+
+/// A class for representing two-dimensional axis-aligned rectangles with
+/// mutable properties.
+class MutableRectangle<T extends num> extends _RectangleBase<T>
+ implements Rectangle<T> {
+ /// The x-coordinate of the left edge.
+ ///
+ /// Setting the value will move the rectangle without changing its width.
+ T left;
+
+ /// The y-coordinate of the left edge.
+ ///
+ /// Setting the value will move the rectangle without changing its height.
+ T top;
+ T _width;
+ T _height;
+
+ /// Create a mutable rectangle spanned by `(left, top)` and
+ /// `(left+width, top+height)`.
+ ///
+ /// The rectangle contains the points
+ /// with x-coordinate between `left` and `left + width`, and
+ /// with y-coordinate between `top` and `top + height`, both inclusive.
+ ///
+ /// The `width` and `height` should be non-negative.
+ /// If `width` or `height` are negative, they are clamped to zero.
+ ///
+ /// If `width` and `height` are zero, the "rectangle" comprises only the
+ /// single point `(left, top)`.
+ MutableRectangle(this.left, this.top, T width, T height)
+ : this._width = (width < 0) ? _clampToZero<T>(width) : width,
+ this._height = (height < 0) ? _clampToZero<T>(height) : height;
+
+ /// Create a mutable rectangle spanned by the points [a] and [b];
+ ///
+ /// The rectangle contains the points
+ /// with x-coordinate between `a.x` and `b.x`, and
+ /// with y-coordinate between `a.y` and `b.y`, both inclusive.
+ ///
+ /// If the distance between `a.x` and `b.x` is not representable
+ /// (which can happen if one or both is a double),
+ /// the actual right edge might be slightly off from `max(a.x, b.x)`.
+ /// Similar for the y-coordinates and the bottom edge.
+ factory MutableRectangle.fromPoints(Point<T> a, Point<T> b) {
+ T left = min(a.x, b.x);
+ T width = max(a.x, b.x) - left;
+ T top = min(a.y, b.y);
+ T height = max(a.y, b.y) - top;
+ return MutableRectangle<T>(left, top, width, height);
+ }
+
+ T get width => _width;
+
+ /// Sets the width of the rectangle.
+ ///
+ /// The width must be non-negative.
+ /// If a negative width is supplied, it is clamped to zero.
+ ///
+ /// Setting the value will change the right edge of the rectangle,
+ /// but will not change [left].
+ set width(T width) {
+ if (width < 0) width = _clampToZero<T>(width);
+ _width = width;
+ }
+
+ T get height => _height;
+
+ /// Sets the height of the rectangle.
+ ///
+ /// The height must be non-negative.
+ /// If a negative height is supplied, it is clamped to zero.
+ ///
+ /// Setting the value will change the bottom edge of the rectangle,
+ /// but will not change [top].
+ set height(T height) {
+ if (height < 0) height = _clampToZero<T>(height);
+ _height = height;
+ }
+}
+
+/// Converts a negative [int] or [double] to a zero-value of the same type.
+///
+/// Returns `0` if value is int, `0.0` if value is double.
+T _clampToZero<T extends num>(T value) {
+ assert(value < 0);
+ return -value * 0;
+}
diff --git a/sdk_nnbd/lib/mirrors/mirrors.dart b/sdk_nnbd/lib/mirrors/mirrors.dart
new file mode 100644
index 0000000..64f88a2
--- /dev/null
+++ b/sdk_nnbd/lib/mirrors/mirrors.dart
@@ -0,0 +1,1467 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// For the purposes of the mirrors library, we adopt a naming
+// convention with respect to getters and setters. Specifically, for
+// some variable or field...
+//
+// var myField;
+//
+// ...the getter is named 'myField' and the setter is named
+// 'myField='. This allows us to assign unique names to getters and
+// setters for the purposes of member lookup.
+
+/**
+ * Basic reflection in Dart,
+ * with support for introspection and dynamic invocation.
+ *
+ * *Introspection* is that subset of reflection by which a running
+ * program can examine its own structure. For example, a function
+ * that prints out the names of all the members of an arbitrary object.
+ *
+ * *Dynamic invocation* refers the ability to evaluate code that
+ * has not been literally specified at compile time, such as calling a method
+ * whose name is provided as an argument (because it is looked up
+ * in a database, or provided interactively by the user).
+ *
+ * ## How to interpret this library's documentation
+ *
+ * As a rule, the names of Dart declarations are represented using
+ * instances of class [Symbol]. Whenever the doc speaks of an object *s*
+ * of class [Symbol] denoting a name, it means the string that
+ * was used to construct *s*.
+ *
+ * The documentation frequently abuses notation with
+ * Dart pseudo-code such as [:o.x(a):], where
+ * o and a are defined to be objects; what is actually meant in these
+ * cases is [:o'.x(a'):] where *o'* and *a'* are Dart variables
+ * bound to *o* and *a* respectively. Furthermore, *o'* and *a'*
+ * are assumed to be fresh variables (meaning that they are
+ * distinct from any other variables in the program).
+ *
+ * Sometimes the documentation refers to *serializable* objects.
+ * An object is serializable across isolates if and only if it is an instance of
+ * num, bool, String, a list of objects that are serializable
+ * across isolates, or a map with keys and values that are all serializable across
+ * isolates.
+ *
+ * ## Status: Unstable
+ *
+ * The dart:mirrors library is unstable and its API might change slightly as a
+ * result of user feedback. This library is platform dependent and therefore it
+ * has implementations for both dart2js and the Dart VM. Both are under
+ * development and may not support all operations yet.
+ *
+ * {@category VM}
+ */
+library dart.mirrors;
+
+import 'dart:async' show Future;
+
+/**
+ * A [MirrorSystem] is the main interface used to reflect on a set of
+ * associated libraries.
+ *
+ * At runtime each running isolate has a distinct [MirrorSystem].
+ *
+ * It is also possible to have a [MirrorSystem] which represents a set
+ * of libraries which are not running -- perhaps at compile-time. In
+ * this case, all available reflective functionality would be
+ * supported, but runtime functionality (such as invoking a function
+ * or inspecting the contents of a variable) would fail dynamically.
+ */
+abstract class MirrorSystem {
+ /**
+ * All libraries known to the mirror system, indexed by their URI.
+ *
+ * Returns an unmodifiable map of the libraries with [LibraryMirror.uri] as
+ * keys.
+ *
+ * For a runtime mirror system, only libraries which are currently loaded
+ * are included, and repeated calls of this method may return different maps
+ * as libraries are loaded.
+ */
+ Map<Uri, LibraryMirror> get libraries;
+
+ /**
+ * Returns the unique library named [libraryName] if it exists.
+ *
+ * If no unique library exists, an error is thrown.
+ */
+ external LibraryMirror findLibrary(Symbol libraryName);
+
+ /**
+ * A mirror on the isolate associated with this [MirrorSystem].
+ *
+ * This may be null if this mirror system is not running.
+ */
+ IsolateMirror get isolate;
+
+ /**
+ * A mirror on the [:dynamic:] type.
+ */
+ TypeMirror get dynamicType;
+
+ /**
+ * A mirror on the [:void:] type.
+ */
+ TypeMirror get voidType;
+
+ /**
+ * Returns the name of [symbol].
+ *
+ * The following text is non-normative:
+ *
+ * Using this method may result in larger output. If possible, use
+ * [MirrorsUsed] to specify which symbols must be retained in clear text.
+ */
+ external static String getName(Symbol symbol);
+
+ /**
+ * Returns a symbol for [name].
+ *
+ * If [library] is not a [LibraryMirror] or if [name] is a private identifier
+ * and [library] is `null`, throws an [ArgumentError]. If [name] is a private
+ * identifier, the symbol returned is with respect to [library].
+ *
+ * The following text is non-normative:
+ *
+ * Using this method may result in larger output. If possible, use
+ * the const constructor of [Symbol] or symbol literals.
+ */
+ external static Symbol getSymbol(String name, [LibraryMirror library]);
+}
+
+/**
+ * Returns a [MirrorSystem] for the current isolate.
+ */
+external MirrorSystem currentMirrorSystem();
+
+/**
+ * Reflects an instance.
+ *
+ * Returns an [InstanceMirror] reflecting [reflectee]. If [reflectee] is a
+ * function or an instance of a class that has a [:call:] method, the returned
+ * instance mirror will be a [ClosureMirror].
+ *
+ * Note that since one cannot obtain an object from another isolate, this
+ * function can only be used to obtain mirrors on objects of the current
+ * isolate.
+ */
+external InstanceMirror reflect(Object reflectee);
+
+/**
+ * Reflects a class declaration.
+ *
+ * Let *C* be the original class declaration of the class represented by [key].
+ * This function returns a [ClassMirror] reflecting *C*.
+ *
+ * If [key] is not an instance of [Type], then this function throws an
+ * [ArgumentError]. If [key] is the Type for dynamic or a function typedef,
+ * throws an [ArgumentError].
+ *
+ * Note that since one cannot obtain a [Type] object from another isolate, this
+ * function can only be used to obtain class mirrors on classes of the current
+ * isolate.
+ */
+external ClassMirror reflectClass(Type key);
+
+/**
+ * Reflects the type represented by [key].
+ *
+ * If [key] is not an instance of [Type], then this function throws an
+ * [ArgumentError].
+ *
+ * Optionally takes a list of [typeArguments] for generic classes. If the list
+ * is provided, then the [key] must be a generic class type, and the number of
+ * the provided type arguments must be equal to the number of type variables
+ * declared by the class.
+ *
+ * Note that since one cannot obtain a [Type] object from another isolate, this
+ * function can only be used to obtain type mirrors on types of the current
+ * isolate.
+ */
+external TypeMirror reflectType(Type key, [List<Type> typeArguments]);
+
+/**
+ * A [Mirror] reflects some Dart language entity.
+ *
+ * Every [Mirror] originates from some [MirrorSystem].
+ */
+abstract class Mirror {}
+
+/**
+ * An [IsolateMirror] reflects an isolate.
+ */
+abstract class IsolateMirror implements Mirror {
+ /**
+ * A unique name used to refer to the isolate in debugging messages.
+ */
+ String get debugName;
+
+ /**
+ * Whether this mirror reflects the currently running isolate.
+ */
+ bool get isCurrent;
+
+ /**
+ * The root library for the reflected isolate.
+ */
+ LibraryMirror get rootLibrary;
+
+ /**
+ * Whether [other] is an [IsolateMirror] on the same isolate as this mirror.
+ *
+ * The equality holds if and only if
+ *
+ * 1. [other] is a mirror of the same kind, and
+ * 2. the isolate being reflected by this mirror is the same isolate being
+ * reflected by [other].
+ */
+ bool operator ==(other);
+
+ /**
+ * Loads the library at the given uri into this isolate.
+ *
+ * WARNING: You are strongly encouraged to use Isolate.spawnUri instead when
+ * possible. IsolateMirror.loadUri should only be used when synchronous
+ * communication or shared state with dynamically loaded code is needed.
+ *
+ * If a library with the same canonicalized uri has already been loaded,
+ * the existing library will be returned. (The isolate will not load a new
+ * copy of the library.)
+ *
+ * This behavior is similar to the behavior of an import statement that
+ * appears in the root library, except that the import scope of the root
+ * library is not changed.
+ */
+ Future<LibraryMirror> loadUri(Uri uri);
+}
+
+/**
+ * A [DeclarationMirror] reflects some entity declared in a Dart program.
+ */
+abstract class DeclarationMirror implements Mirror {
+ /**
+ * The simple name for this Dart language entity.
+ *
+ * The simple name is in most cases the identifier name of the entity,
+ * such as 'myMethod' for a method, [:void myMethod() {...}:] or 'mylibrary'
+ * for a [:library 'mylibrary';:] declaration.
+ */
+ Symbol get simpleName;
+
+ /**
+ * The fully-qualified name for this Dart language entity.
+ *
+ * This name is qualified by the name of the owner. For instance,
+ * the qualified name of a method 'method' in class 'Class' in
+ * library 'library' is 'library.Class.method'.
+ *
+ * Returns a [Symbol] constructed from a string representing the
+ * fully qualified name of the reflectee.
+ * Let *o* be the [owner] of this mirror, let *r* be the reflectee of
+ * this mirror, let *p* be the fully qualified
+ * name of the reflectee of *o*, and let *s* be the simple name of *r*
+ * computed by [simpleName].
+ * The fully qualified name of *r* is the
+ * concatenation of *p*, '.', and *s*.
+ *
+ * Because an isolate can contain more than one library with the same name (at
+ * different URIs), a fully-qualified name does not uniquely identify any
+ * language entity.
+ */
+ Symbol get qualifiedName;
+
+ /**
+ * A mirror on the owner of this Dart language entity.
+ *
+ * The owner is the declaration immediately surrounding the reflectee:
+ *
+ * * For a library, the owner is [:null:].
+ * * For a class declaration, typedef or top level function or variable, the
+ * owner is the enclosing library.
+ * * For a mixin application `S with M`, the owner is the owner of `M`.
+ * * For a constructor, the owner is the immediately enclosing class.
+ * * For a method, instance variable or a static variable, the owner is the
+ * immediately enclosing class, unless the class is a mixin application
+ * `S with M`, in which case the owner is `M`. Note that `M` may be an
+ * invocation of a generic.
+ * * For a parameter, local variable or local function the owner is the
+ * immediately enclosing function.
+ */
+ DeclarationMirror get owner;
+
+ /**
+ * Whether this declaration is library private.
+ *
+ * Always returns `false` for a library declaration,
+ * otherwise returns `true` if the declaration's name starts with an
+ * underscore character (`_`), and `false` if it doesn't.
+ */
+ bool get isPrivate;
+
+ /**
+ * Whether this declaration is top-level.
+ *
+ * A declaration is considered top-level if its [owner] is a [LibraryMirror].
+ */
+ bool get isTopLevel;
+
+ /**
+ * The source location of this Dart language entity, or [:null:] if the
+ * entity is synthetic.
+ *
+ * If the reflectee is a variable, the returned location gives the position
+ * of the variable name at its point of declaration.
+ *
+ * If the reflectee is a library, class, typedef, function or type variable
+ * with associated metadata, the returned location gives the position of the
+ * first metadata declaration associated with the reflectee.
+ *
+ * Otherwise:
+ *
+ * If the reflectee is a library, the returned location gives the position of
+ * the keyword 'library' at the reflectee's point of declaration, if the
+ * reflectee is a named library, or the first character of the first line in
+ * the compilation unit defining the reflectee if the reflectee is anonymous.
+ *
+ * If the reflectee is an abstract class, the returned location gives the
+ * position of the keyword 'abstract' at the reflectee's point of declaration.
+ * Otherwise, if the reflectee is a class, the returned location gives the
+ * position of the keyword 'class' at the reflectee's point of declaration.
+ *
+ * If the reflectee is a typedef the returned location gives the position of
+ * the of the keyword 'typedef' at the reflectee's point of declaration.
+ *
+ * If the reflectee is a function with a declared return type, the returned
+ * location gives the position of the function's return type at the
+ * reflectee's point of declaration. Otherwise. the returned location gives
+ * the position of the function's name at the reflectee's point of
+ * declaration.
+ *
+ * This operation is optional and may throw an [UnsupportedError].
+ */
+ SourceLocation get location;
+
+ /**
+ * A list of the metadata associated with this declaration.
+ *
+ * Let *D* be the declaration this mirror reflects.
+ * If *D* is decorated with annotations *A1, ..., An*
+ * where *n > 0*, then for each annotation *Ai* associated
+ * with *D, 1 <= i <= n*, let *ci* be the constant object
+ * specified by *Ai*. Then this method returns a list whose
+ * members are instance mirrors on *c1, ..., cn*.
+ * If no annotations are associated with *D*, then
+ * an empty list is returned.
+ *
+ * If evaluating any of *c1, ..., cn* would cause a
+ * compilation error
+ * the effect is the same as if a non-reflective compilation error
+ * had been encountered.
+ */
+ List<InstanceMirror> get metadata;
+}
+
+/**
+ * An [ObjectMirror] is a common superinterface of [InstanceMirror],
+ * [ClassMirror], and [LibraryMirror] that represents their shared
+ * functionality.
+ *
+ * For the purposes of the mirrors library, these types are all
+ * object-like, in that they support method invocation and field
+ * access. Real Dart objects are represented by the [InstanceMirror]
+ * type.
+ *
+ * See [InstanceMirror], [ClassMirror], and [LibraryMirror].
+ */
+abstract class ObjectMirror implements Mirror {
+ /**
+ * Invokes the named function and returns a mirror on the result.
+ *
+ * Let *o* be the object reflected by this mirror, let *f* be the simple name
+ * of the member denoted by [memberName], let *a1, ..., an* be the elements
+ * of [positionalArguments], let *k1, ..., km* be the identifiers denoted by
+ * the elements of [namedArguments.keys], and let *v1, ..., vm* be the
+ * elements of [namedArguments.values]. Then this method will perform the
+ * method invocation *o.f(a1, ..., an, k1: v1, ..., km: vm)* in a scope that
+ * has access to the private members of *o* (if *o* is a class or library) or
+ * the private members of the class of *o* (otherwise).
+ *
+ * If the invocation returns a result *r*, this method returns the result of
+ * calling [reflect]\(*r*\).
+ *
+ * If the invocation causes a compilation error the effect is the same as if
+ * a non-reflective compilation error had been encountered.
+ *
+ * If the invocation throws an exception *e* (that it does not catch), this
+ * method throws *e*.
+ */
+ /*
+ * TODO(turnidge): Handle ambiguous names.
+ * TODO(turnidge): Handle optional & named arguments.
+ */
+ InstanceMirror invoke(Symbol memberName, List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]);
+
+ /**
+ * Invokes a getter and returns a mirror on the result.
+ *
+ * The getter can be the implicit getter for a field or a user-defined getter
+ * method.
+ *
+ * Let *o* be the object reflected by this mirror,
+ * let *f* be the simple name of the getter denoted by [fieldName].
+ *
+ * Then this method will perform the getter invocation *o.f* in a scope that
+ * has access to the private members of *o* (if *o* is a class or library) or
+ * the private members of the class of *o* (otherwise).
+ *
+ * If this mirror is an [InstanceMirror], and [fieldName] denotes an instance
+ * method on its reflectee, the result of the invocation is an instance
+ * mirror on a closure corresponding to that method.
+ *
+ * If this mirror is a [LibraryMirror], and [fieldName] denotes a top-level
+ * method in the corresponding library, the result of the invocation is an
+ * instance mirror on a closure corresponding to that method.
+ *
+ * If this mirror is a [ClassMirror], and [fieldName] denotes a static method
+ * in the corresponding class, the result of the invocation is an instance
+ * mirror on a closure corresponding to that method.
+ *
+ * If the invocation returns a result *r*, this method returns the result of
+ * calling [reflect]\(*r*\).
+ *
+ * If the invocation causes a compilation error, the effect is the same as if
+ * a non-reflective compilation error had been encountered.
+ *
+ * If the invocation throws an exception *e* (that it does not catch), this
+ * method throws *e*.
+ */
+ // TODO(ahe): Remove stuff about scope and private members. [fieldName] is a
+ // capability giving access to private members.
+ InstanceMirror getField(Symbol fieldName);
+
+ /**
+ * Invokes a setter and returns a mirror on the result.
+ *
+ * The setter may be either the implicit setter for a non-final field or a
+ * user-defined setter method.
+ *
+ * Let *o* be the object reflected by this mirror,
+ * let *f* be the simple name of the getter denoted by [fieldName],
+ * and let *a* be the object bound to [value].
+ *
+ * Then this method will perform the setter invocation *o.f = a* in a scope
+ * that has access to the private members of *o* (if *o* is a class or
+ * library) or the private members of the class of *o* (otherwise).
+ *
+ * If the invocation returns a result *r*, this method returns the result of
+ * calling [reflect]\([value]\).
+ *
+ * If the invocation causes a compilation error, the effect is the same as if
+ * a non-reflective compilation error had been encountered.
+ *
+ * If the invocation throws an exception *e* (that it does not catch) this
+ * method throws *e*.
+ */
+ /* TODO(turnidge): Handle ambiguous names.*/
+ InstanceMirror setField(Symbol fieldName, Object value);
+
+ /**
+ * Performs [invocation] on the reflectee of this [ObjectMirror].
+ *
+ * Equivalent to
+ *
+ * if (invocation.isGetter) {
+ * return this.getField(invocation.memberName).reflectee;
+ * } else if (invocation.isSetter) {
+ * return this.setField(invocation.memberName,
+ * invocation.positionalArguments[0]).reflectee;
+ * } else {
+ * return this.invoke(invocation.memberName,
+ * invocation.positionalArguments,
+ * invocation.namedArguments).reflectee;
+ * }
+ */
+ delegate(Invocation invocation);
+}
+
+/**
+ * An [InstanceMirror] reflects an instance of a Dart language object.
+ */
+abstract class InstanceMirror implements ObjectMirror {
+ /**
+ * A mirror on the type of the reflectee.
+ *
+ * Returns a mirror on the actual class of the reflectee.
+ * The class of the reflectee may differ from
+ * the object returned by invoking [runtimeType] on
+ * the reflectee.
+ */
+ ClassMirror get type;
+
+ /**
+ * Whether [reflectee] will return the instance reflected by this mirror.
+ *
+ * This will always be true in the local case (reflecting instances in the
+ * same isolate), but only true in the remote case if this mirror reflects a
+ * simple value.
+ *
+ * A value is simple if one of the following holds:
+ *
+ * * the value is [:null:]
+ * * the value is of type [num]
+ * * the value is of type [bool]
+ * * the value is of type [String]
+ */
+ bool get hasReflectee;
+
+ /**
+ * If the [InstanceMirror] reflects an instance it is meaningful to
+ * have a local reference to, we provide access to the actual
+ * instance here.
+ *
+ * If you access [reflectee] when [hasReflectee] is false, an
+ * exception is thrown.
+ */
+ get reflectee;
+
+ /**
+ * Whether this mirror is equal to [other].
+ *
+ * The equality holds if and only if
+ *
+ * 1. [other] is a mirror of the same kind, and
+ * 2. either
+ *
+ * a. [hasReflectee] is true and so is
+ * [:identical(reflectee, other.reflectee):], or
+ *
+ * b. the remote objects reflected by this mirror and by [other] are
+ * identical.
+ */
+ bool operator ==(other);
+}
+
+/**
+ * A [ClosureMirror] reflects a closure.
+ *
+ * A [ClosureMirror] provides the ability to execute its reflectee and
+ * introspect its function.
+ */
+abstract class ClosureMirror implements InstanceMirror {
+ /**
+ * A mirror on the function associated with this closure.
+ *
+ * The function associated with an implicit closure of a function is that
+ * function.
+ *
+ * The function associated with an instance of a class that has a [:call:]
+ * method is that [:call:] method.
+ *
+ * A Dart implementation might choose to create a class for each closure
+ * expression, in which case [:function:] would be the same as
+ * [:type.declarations[#call]:]. But the Dart language model does not require
+ * this. A more typical implementation involves a single closure class for
+ * each type signature, where the call method dispatches to a function held
+ * in the closure rather the call method
+ * directly implementing the closure body. So one cannot rely on closures from
+ * distinct closure expressions having distinct classes ([:type:]), but one
+ * can rely on them having distinct functions ([:function:]).
+ */
+ MethodMirror get function;
+
+ /**
+ * Executes the closure and returns a mirror on the result.
+ *
+ * Let *f* be the closure reflected by this mirror,
+ * let *a1, ..., an* be the elements of [positionalArguments],
+ * let *k1, ..., km* be the identifiers denoted by the elements of
+ * [namedArguments.keys],
+ * and let *v1, ..., vm* be the elements of [namedArguments.values].
+ *
+ * Then this method will perform the method invocation
+ * *f(a1, ..., an, k1: v1, ..., km: vm)*.
+ *
+ * If the invocation returns a result *r*, this method returns the result of
+ * calling [reflect]\(*r*\).
+ *
+ * If the invocation causes a compilation error, the effect is the same as if
+ * a non-reflective compilation error had been encountered.
+ *
+ * If the invocation throws an exception *e* (that it does not catch), this
+ * method throws *e*.
+ */
+ InstanceMirror apply(List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]);
+}
+
+/**
+ * A [LibraryMirror] reflects a Dart language library, providing
+ * access to the variables, functions, and classes of the
+ * library.
+ */
+abstract class LibraryMirror implements DeclarationMirror, ObjectMirror {
+ /**
+ * The absolute uri of the library.
+ */
+ Uri get uri;
+
+ /**
+ * Returns an immutable map of the declarations actually given in the library.
+ *
+ * This map includes all regular methods, getters, setters, fields, classes
+ * and typedefs actually declared in the library. The map is keyed by the
+ * simple names of the declarations.
+ */
+ Map<Symbol, DeclarationMirror> get declarations;
+
+ /**
+ * Whether this mirror is equal to [other].
+ *
+ * The equality holds if and only if
+ *
+ * 1. [other] is a mirror of the same kind, and
+ * 2. The library being reflected by this mirror and the library being
+ * reflected by [other] are the same library in the same isolate.
+ */
+ bool operator ==(other);
+
+ /**
+ * Returns a list of the imports and exports in this library;
+ */
+ List<LibraryDependencyMirror> get libraryDependencies;
+}
+
+/// A mirror on an import or export declaration.
+abstract class LibraryDependencyMirror implements Mirror {
+ /// Is `true` if this dependency is an import.
+ bool get isImport;
+
+ /// Is `true` if this dependency is an export.
+ bool get isExport;
+
+ /// Returns true iff this dependency is a deferred import. Otherwise returns
+ /// false.
+ bool get isDeferred;
+
+ /// Returns the library mirror of the library that imports or exports the
+ /// [targetLibrary].
+ LibraryMirror get sourceLibrary;
+
+ /// Returns the library mirror of the library that is imported or exported,
+ /// or null if the library is not loaded.
+ LibraryMirror get targetLibrary;
+
+ /// Returns the prefix if this is a prefixed import and `null` otherwise.
+ Symbol get prefix;
+
+ /// Returns the list of show/hide combinators on the import/export
+ /// declaration.
+ List<CombinatorMirror> get combinators;
+
+ /// Returns the source location for this import/export declaration.
+ SourceLocation get location;
+
+ List<InstanceMirror> get metadata;
+
+ /// Returns a future that completes with a library mirror on the library being
+ /// imported or exported when it is loaded, and initiates a load of that
+ /// library if it is not loaded.
+ Future<LibraryMirror> loadLibrary();
+}
+
+/// A mirror on a show/hide combinator declared on a library dependency.
+abstract class CombinatorMirror implements Mirror {
+ /// The list of identifiers on the combinator.
+ List<Symbol> get identifiers;
+
+ /// Is `true` if this is a 'show' combinator.
+ bool get isShow;
+
+ /// Is `true` if this is a 'hide' combinator.
+ bool get isHide;
+}
+
+/**
+ * A [TypeMirror] reflects a Dart language class, typedef,
+ * function type or type variable.
+ */
+abstract class TypeMirror implements DeclarationMirror {
+ /**
+ * Returns true if this mirror reflects dynamic, a non-generic class or
+ * typedef, or an instantiated generic class or typedef in the current
+ * isolate. Otherwise, returns false.
+ */
+ bool get hasReflectedType;
+
+ /**
+ * If [:hasReflectedType:] returns true, returns the corresponding [Type].
+ * Otherwise, an [UnsupportedError] is thrown.
+ */
+ Type get reflectedType;
+
+ /**
+ * An immutable list with mirrors for all type variables for this type.
+ *
+ * If this type is a generic declaration or an invocation of a generic
+ * declaration, the returned list contains mirrors on the type variables
+ * declared in the original declaration.
+ * Otherwise, the returned list is empty.
+ *
+ * This list preserves the order of declaration of the type variables.
+ */
+ List<TypeVariableMirror> get typeVariables;
+
+ /**
+ * An immutable list with mirrors for all type arguments for
+ * this type.
+ *
+ * If the reflectee is an invocation of a generic class,
+ * the type arguments are the bindings of its type parameters.
+ * If the reflectee is the original declaration of a generic,
+ * it has no type arguments and this method returns an empty list.
+ * If the reflectee is not generic, then
+ * it has no type arguments and this method returns an empty list.
+ *
+ * This list preserves the order of declaration of the type variables.
+ */
+ List<TypeMirror> get typeArguments;
+
+ /**
+ * Is this the original declaration of this type?
+ *
+ * For most classes, they are their own original declaration. For
+ * generic classes, however, there is a distinction between the
+ * original class declaration, which has unbound type variables, and
+ * the instantiations of generic classes, which have bound type
+ * variables.
+ */
+ bool get isOriginalDeclaration;
+
+ /**
+ * A mirror on the original declaration of this type.
+ *
+ * For most classes, they are their own original declaration. For
+ * generic classes, however, there is a distinction between the
+ * original class declaration, which has unbound type variables, and
+ * the instantiations of generic classes, which have bound type
+ * variables.
+ */
+ TypeMirror get originalDeclaration;
+
+ /**
+ * Checks the subtype relationship, denoted by `<:` in the language
+ * specification.
+ *
+ * This is the type relationship used in `is` test checks.
+ */
+ bool isSubtypeOf(TypeMirror other);
+
+ /**
+ * Checks the assignability relationship, denoted by `<=>` in the language
+ * specification.
+ *
+ * This is the type relationship tested on assignment in checked mode.
+ */
+ bool isAssignableTo(TypeMirror other);
+}
+
+/**
+ * A [ClassMirror] reflects a Dart language class.
+ */
+abstract class ClassMirror implements TypeMirror, ObjectMirror {
+ /**
+ * A mirror on the superclass on the reflectee.
+ *
+ * If this type is [:Object:], the superclass will be null.
+ */
+ ClassMirror get superclass;
+
+ /**
+ * A list of mirrors on the superinterfaces of the reflectee.
+ */
+ List<ClassMirror> get superinterfaces;
+
+ /**
+ * Is the reflectee abstract?
+ */
+ bool get isAbstract;
+
+ /**
+ * Is the reflectee an enum?
+ */
+ bool get isEnum;
+
+ /**
+ * Returns an immutable map of the declarations actually given in the class
+ * declaration.
+ *
+ * This map includes all regular methods, getters, setters, fields,
+ * constructors and type variables actually declared in the class. Both
+ * static and instance members are included, but no inherited members are
+ * included. The map is keyed by the simple names of the declarations.
+ *
+ * This does not include inherited members.
+ */
+ Map<Symbol, DeclarationMirror> get declarations;
+
+ /**
+ * Returns a map of the methods, getters and setters of an instance of the
+ * class.
+ *
+ * The intent is to capture those members that constitute the API of an
+ * instance. Hence fields are not included, but the getters and setters
+ * implicitly introduced by fields are included. The map includes methods,
+ * getters and setters that are inherited as well as those introduced by the
+ * class itself.
+ *
+ * The map is keyed by the simple names of the members.
+ */
+ Map<Symbol, MethodMirror> get instanceMembers;
+
+ /**
+ * Returns a map of the static methods, getters and setters of the class.
+ *
+ * The intent is to capture those members that constitute the API of a class.
+ * Hence fields are not included, but the getters and setters implicitly
+ * introduced by fields are included.
+ *
+ * The map is keyed by the simple names of the members.
+ */
+ Map<Symbol, MethodMirror> get staticMembers;
+
+ /**
+ * The mixin of this class.
+ *
+ * If this class is the result of a mixin application of the form S with M,
+ * returns a class mirror on M. Otherwise returns a class mirror on
+ * the reflectee.
+ */
+ ClassMirror get mixin;
+
+ // TODO(ahe): What about:
+ // /// Finds the instance member named [name] declared or inherited in the
+ // /// reflected class.
+ // DeclarationMirror instanceLookup(Symbol name);
+
+ /**
+ * Invokes the named constructor and returns a mirror on the result.
+ *
+ * Let *c* be the class reflected by this mirror,
+ * let *a1, ..., an* be the elements of [positionalArguments],
+ * let *k1, ..., km* be the identifiers denoted by the elements of
+ * [namedArguments.keys],
+ * and let *v1, ..., vm* be the elements of [namedArguments.values].
+ *
+ * If [constructorName] was created from the empty string, then this method
+ * will execute the instance creation expression
+ * *new c(a1, ..., an, k1: v1, ..., km: vm)* in a scope that has access to
+ * the private members of *c*.
+ *
+ * Otherwise, let *f* be the simple name of the constructor denoted by
+ * [constructorName]. Then this method will execute the instance creation
+ * expression *new c.f(a1, ..., an, k1: v1, ..., km: vm)* in a scope that has
+ * access to the private members of *c*.
+ *
+ * In either case:
+ *
+ * * If the expression evaluates to a result *r*, this method returns the
+ * result of calling [reflect]\(*r*\).
+ * * If evaluating the expression causes a compilation error, the effect is
+ * the same as if a non-reflective compilation error had been encountered.
+ * * If evaluating the expression throws an exception *e* (that it does not
+ * catch), this method throws *e*.
+ */
+ InstanceMirror newInstance(Symbol constructorName, List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]);
+
+ /**
+ * Whether this mirror is equal to [other].
+ *
+ * The equality holds if and only if
+ *
+ * 1. [other] is a mirror of the same kind, and
+ * 2. This mirror and [other] reflect the same class.
+ *
+ * Note that if the reflected class is an invocation of a generic class, 2.
+ * implies that the reflected class and [other] have equal type arguments.
+ */
+ bool operator ==(other);
+
+ /**
+ * Returns whether the class denoted by the receiver is a subclass of the
+ * class denoted by the argument.
+ *
+ * Note that the subclass relationship is reflexive.
+ */
+ bool isSubclassOf(ClassMirror other);
+}
+
+/**
+ * A [FunctionTypeMirror] represents the type of a function in the
+ * Dart language.
+ */
+abstract class FunctionTypeMirror implements ClassMirror {
+ /**
+ * Returns the return type of the reflectee.
+ */
+ TypeMirror get returnType;
+
+ /**
+ * Returns a list of the parameter types of the reflectee.
+ */
+ List<ParameterMirror> get parameters;
+
+ /**
+ * A mirror on the [:call:] method for the reflectee.
+ */
+ // This is only here because in the past the VM did not implement a call
+ // method on closures.
+ MethodMirror get callMethod;
+}
+
+/**
+ * A [TypeVariableMirror] represents a type parameter of a generic type.
+ */
+abstract class TypeVariableMirror extends TypeMirror {
+ /**
+ * A mirror on the type that is the upper bound of this type variable.
+ */
+ TypeMirror get upperBound;
+
+ /**
+ * Is the reflectee static?
+ *
+ * For the purposes of the mirrors library, type variables are considered
+ * non-static.
+ */
+ bool get isStatic;
+
+ /**
+ * Whether [other] is a [TypeVariableMirror] on the same type variable as this
+ * mirror.
+ *
+ * The equality holds if and only if
+ *
+ * 1. [other] is a mirror of the same kind, and
+ * 2. [:simpleName == other.simpleName:] and [:owner == other.owner:].
+ */
+ bool operator ==(other);
+}
+
+/**
+ * A [TypedefMirror] represents a typedef in a Dart language program.
+ */
+abstract class TypedefMirror implements TypeMirror {
+ /**
+ * The defining type for this typedef.
+ *
+ * If the type referred to by the reflectee is a function type *F*, the
+ * result will be [:FunctionTypeMirror:] reflecting *F* which is abstract
+ * and has an abstract method [:call:] whose signature corresponds to *F*.
+ * For instance [:void f(int):] is the referent for [:typedef void f(int):].
+ */
+ FunctionTypeMirror get referent;
+}
+
+/**
+ * A [MethodMirror] reflects a Dart language function, method,
+ * constructor, getter, or setter.
+ */
+abstract class MethodMirror implements DeclarationMirror {
+ /**
+ * A mirror on the return type for the reflectee.
+ */
+ TypeMirror get returnType;
+
+ /**
+ * The source code for the reflectee, if available. Otherwise null.
+ */
+ String get source;
+
+ /**
+ * A list of mirrors on the parameters for the reflectee.
+ */
+ List<ParameterMirror> get parameters;
+
+ /**
+ * A function is considered non-static iff it is permited to refer to 'this'.
+ *
+ * Note that generative constructors are considered non-static, whereas
+ * factory constructors are considered static.
+ */
+ bool get isStatic;
+
+ /**
+ * Is the reflectee abstract?
+ */
+ bool get isAbstract;
+
+ /**
+ * Returns true if the reflectee is synthetic, and returns false otherwise.
+ *
+ * A reflectee is synthetic if it is a getter or setter implicitly introduced
+ * for a field or Type, or if it is a constructor that was implicitly
+ * introduced as a default constructor or as part of a mixin application.
+ */
+ bool get isSynthetic;
+
+ /**
+ * Is the reflectee a regular function or method?
+ *
+ * A function or method is regular if it is not a getter, setter, or
+ * constructor. Note that operators, by this definition, are
+ * regular methods.
+ */
+ bool get isRegularMethod;
+
+ /**
+ * Is the reflectee an operator?
+ */
+ bool get isOperator;
+
+ /**
+ * Is the reflectee a getter?
+ */
+ bool get isGetter;
+
+ /**
+ * Is the reflectee a setter?
+ */
+ bool get isSetter;
+
+ /**
+ * Is the reflectee a constructor?
+ */
+ bool get isConstructor;
+
+ /**
+ * The constructor name for named constructors and factory methods.
+ *
+ * For unnamed constructors, this is the empty string. For
+ * non-constructors, this is the empty string.
+ *
+ * For example, [:'bar':] is the constructor name for constructor
+ * [:Foo.bar:] of type [:Foo:].
+ */
+ Symbol get constructorName;
+
+ /**
+ * Is the reflectee a const constructor?
+ */
+ bool get isConstConstructor;
+
+ /**
+ * Is the reflectee a generative constructor?
+ */
+ bool get isGenerativeConstructor;
+
+ /**
+ * Is the reflectee a redirecting constructor?
+ */
+ bool get isRedirectingConstructor;
+
+ /**
+ * Is the reflectee a factory constructor?
+ */
+ bool get isFactoryConstructor;
+
+ /**
+ * Whether this mirror is equal to [other].
+ *
+ * The equality holds if and only if
+ *
+ * 1. [other] is a mirror of the same kind, and
+ * 2. [:simpleName == other.simpleName:] and [:owner == other.owner:].
+ */
+ bool operator ==(other);
+}
+
+/**
+ * A [VariableMirror] reflects a Dart language variable declaration.
+ */
+abstract class VariableMirror implements DeclarationMirror {
+ /**
+ * Returns a mirror on the type of the reflectee.
+ */
+ TypeMirror get type;
+
+ /**
+ * Returns [:true:] if the reflectee is a static variable.
+ * Otherwise returns [:false:].
+ *
+ * For the purposes of the mirror library, top-level variables are
+ * implicitly declared static.
+ */
+ bool get isStatic;
+
+ /**
+ * Returns [:true:] if the reflectee is a final variable.
+ * Otherwise returns [:false:].
+ */
+ bool get isFinal;
+
+ /**
+ * Returns [:true:] if the reflectee is declared [:const:].
+ * Otherwise returns [:false:].
+ */
+ bool get isConst;
+
+ /**
+ * Whether this mirror is equal to [other].
+ *
+ * The equality holds if and only if
+ *
+ * 1. [other] is a mirror of the same kind, and
+ * 2. [:simpleName == other.simpleName:] and [:owner == other.owner:].
+ */
+ bool operator ==(other);
+}
+
+/**
+ * A [ParameterMirror] reflects a Dart formal parameter declaration.
+ */
+abstract class ParameterMirror implements VariableMirror {
+ /**
+ * A mirror on the type of this parameter.
+ */
+ TypeMirror get type;
+
+ /**
+ * Returns [:true:] if the reflectee is an optional parameter.
+ * Otherwise returns [:false:].
+ */
+ bool get isOptional;
+
+ /**
+ * Returns [:true:] if the reflectee is a named parameter.
+ * Otherwise returns [:false:].
+ */
+ bool get isNamed;
+
+ /**
+ * Returns [:true:] if the reflectee has explicitly declared a default value.
+ * Otherwise returns [:false:].
+ */
+ bool get hasDefaultValue;
+
+ /**
+ * Returns the default value of an optional parameter.
+ *
+ * Returns an [InstanceMirror] on the (compile-time constant)
+ * default value for an optional parameter.
+ * If no default value is declared, it defaults to `null`
+ * and a mirror of `null` is returned.
+ *
+ * Returns `null` for a required parameter.
+ */
+ InstanceMirror get defaultValue;
+}
+
+/**
+ * A [SourceLocation] describes the span of an entity in Dart source code.
+ */
+abstract class SourceLocation {
+ /**
+ * The 1-based line number for this source location.
+ *
+ * A value of 0 means that the line number is unknown.
+ */
+ int get line;
+
+ /**
+ * The 1-based column number for this source location.
+ *
+ * A value of 0 means that the column number is unknown.
+ */
+ int get column;
+
+ /**
+ * Returns the URI where the source originated.
+ */
+ Uri get sourceUri;
+}
+
+/**
+ * Class used for encoding comments as metadata annotations.
+ */
+class Comment {
+ /**
+ * The comment text as written in the source text.
+ */
+ final String text;
+
+ /**
+ * The comment text without the start, end, and padding text.
+ *
+ * For example, if [text] is [: /** Comment text. */ :] then the [trimmedText]
+ * is [: Comment text. :].
+ */
+ final String trimmedText;
+
+ /**
+ * Is [:true:] if this comment is a documentation comment.
+ *
+ * That is, that the comment is either enclosed in [: /** ... */ :] or starts
+ * with [: /// :].
+ */
+ final bool isDocComment;
+
+ const Comment(this.text, this.trimmedText, this.isDocComment);
+}
+
+/**
+ * Annotation describing how "dart:mirrors" is used (EXPERIMENTAL).
+ *
+ * When used as metadata on an import of "dart:mirrors" in library *L*, this
+ * class describes how "dart:mirrors" is used by library *L* unless overridden.
+ * See [override].
+ *
+ * The following text is non-normative:
+ *
+ * In some scenarios, for example, when minifying Dart code, or when generating
+ * JavaScript code from a Dart program, the size and performance of the output
+ * can suffer from use of reflection. In those cases, telling the compiler
+ * what is used, can have a significant impact.
+ *
+ * Example usage:
+ *
+ * @MirrorsUsed(symbols: 'foo')
+ * import 'dart:mirrors';
+ *
+ * class Foo {
+ * noSuchMethod(Invocation invocation) {
+ * print(MirrorSystem.getName(invocation.memberName));
+ * }
+ * }
+ *
+ * main() {
+ * new Foo().foo(); // Prints "foo".
+ * new Foo().bar(); // Might print an arbitrary (mangled) name, "bar".
+ * }
+ *
+ * For a detailed description of the parameters to the [MirrorsUsed] constructor
+ * see the comments for [symbols], [targets], [metaTargets] and [override].
+ *
+ * An import of `dart:mirrors` may have multiple [MirrorsUsed] annotations. This
+ * is particularly helpful to specify overrides for specific libraries. For
+ * example:
+ *
+ * @MirrorsUsed(targets: 'foo.Bar', override: 'foo')
+ * @MirrorsUsed(targets: 'Bar')
+ * import 'dart:mirrors';
+ *
+ * will ensure that the target `Bar` from the current library and from library
+ * `foo` is available for reflection. See also [override].
+ */
+@Deprecated("No longer has any effect. Will be removed in a later release.")
+class MirrorsUsed {
+ // Note: the fields of this class are untyped. This is because the most
+ // convenient way to specify symbols today is using a single string. In
+ // some cases, a const list of classes might be convenient. Some
+ // might prefer to use a const list of symbols.
+
+ /**
+ * The list of strings passed to new [Symbol], and symbols that might be
+ * passed to [MirrorSystem.getName].
+ *
+ * Combined with the names of [targets], [metaTargets] and their members,
+ * this forms the complete list of strings passed to new [Symbol], and
+ * symbols that might be passed to [MirrorSystem.getName] by the library to
+ * which this metadata applies.
+ *
+ * The following text is non-normative:
+ *
+ * Dart2js currently supports the following formats to specify symbols:
+ *
+ * * A constant [List] of [String] constants representing symbol names,
+ * e.g., `const ['foo', 'bar']`.
+ * * A single [String] constant whose value is a comma-separated list of
+ * symbol names, e.g., `"foo, bar"`.
+ *
+ * Specifying the `symbols` field turns off the following warnings emitted by
+ * dart2js:
+ *
+ * * Using "MirrorSystem.getName" may result in larger output.
+ * * Using "new Symbol" may result in larger output.
+ *
+ * For example, if you're using [noSuchMethod] to interact with a database,
+ * extract all the possible column names and include them in this list.
+ * Similarly, if you're using [noSuchMethod] to interact with another
+ * language (JavaScript, for example) extract all the identifiers from the
+ * API you use and include them in this list.
+ *
+ * Note that specifying a symbol only ensures that the symbol will be
+ * available under that name at runtime. It does not mark targets with
+ * that name as available for reflection. See [targets] and [metaTargets]
+ * for that purpose.
+ */
+ final symbols;
+
+ /**
+ * A list of reflective targets.
+ *
+ * Combined with [metaTargets], this provides the complete list of reflective
+ * targets used by the library to which this metadata applies.
+ *
+ * The following text is non-normative:
+ *
+ * For now, there is no formal description of what a reflective target is.
+ * Informally, a target is a library, a class, a method or a field.
+ *
+ * Dart2js currently supports the following formats to specify targets:
+ *
+ * * A constant [List] containing [String] constants representing (qualified)
+ * names of targets and Dart types.
+ * * A single [String] constant whose value is a comma-separated list of
+ * (qualified) names.
+ * * A single Dart type.
+ *
+ * A (qualified) name is resolved to a target as follows:
+ *
+ * 1. If the qualified name matches a library name, the matching library is
+ * the target.
+ * 2. Else, find the longest prefix of the name such that the prefix ends
+ * just before a `.` and is a library name.
+ * 3. Use that library as current scope. If no matching prefix was found, use
+ * the current library, i.e., the library where the [MirrorsUsed]
+ * annotation was placed.
+ * 4. Split the remaining suffix (the entire name if no library name was
+ * found in step 3) into a list of [String] using `.` as a
+ * separator.
+ * 5. Select all targets in the current scope whose name matches a [String]
+ * from the list.
+ *
+ * For example:
+ *
+ * library my.library.one;
+ *
+ * class A {
+ * var aField;
+ * }
+ *
+ * library main;
+ *
+ * @MirrorsUsed(targets: "my.library.one.A.aField")
+ * import "dart:mirrors";
+ *
+ * The [MirrorsUsed] annotation specifies `A` and `aField` from library
+ * `my.library.one` as targets. This will mark the class `A` as a reflective
+ * target. The target specification for `aField` has no effect, as there is
+ * no target in `my.library.one` with that name.
+ *
+ * Note that everything within a target also is available for reflection.
+ * So, if a library is specified as target, all classes in that library
+ * become targets for reflection. Likewise, if a class is a target, all
+ * its methods and fields become targets for reflection. As a consequence,
+ * `aField` in the above example is also a reflective target.
+ *
+ */
+ final targets;
+
+ /**
+ * A list of classes that when used as metadata indicates a reflective
+ * target. See also [targets].
+ *
+ * The following text is non-normative:
+ *
+ * The format for specifying the list of classes is the same as used for
+ * specifying [targets]. However, as a library cannot be used as a metadata
+ * annotation in Dart, adding a library to the list of [metaTargets] has no
+ * effect. In particular, adding a library to [metaTargets] does not make
+ * the library's classes valid metadata annotations to enable reflection.
+ *
+ * If an instance of a class specified in [metaTargets] is used as
+ * metadata annotation on a library, class, field or method, that library,
+ * class, field or method is added to the set of targets for reflection.
+ *
+ * Example usage:
+ *
+ * library example;
+ * @MirrorsUsed(metaTargets: "example.Reflectable")
+ * import "dart:mirrors";
+ *
+ * class Reflectable {
+ * const Reflectable();
+ * }
+ *
+ * class Foo {
+ * @Reflectable()
+ * reflectableMethod() { ... }
+ *
+ * nonReflectableMethod() { ... }
+ * }
+ *
+ * In the above example. `reflectableMethod` is marked as reflectable by
+ * using the `Reflectable` class, which in turn is specified in the
+ * [metaTargets] annotation.
+ *
+ * The method `nonReflectableMethod` lacks a metadata annotation and thus
+ * will not be reflectable at runtime.
+ */
+ final metaTargets;
+
+ /**
+ * A list of library names or "*".
+ *
+ * When used as metadata on an import of "dart:mirrors", this metadata does
+ * not apply to the library in which the annotation is used, but instead
+ * applies to the other libraries (all libraries if "*" is used).
+ *
+ * The following text is non-normative:
+ *
+ * Dart2js currently supports the following formats to specify libraries:
+ *
+ * * A constant [List] containing [String] constants representing names of
+ * libraries.
+ * * A single [String] constant whose value is a comma-separated list of
+ * library names.
+ *
+ * Conceptually, a [MirrorsUsed] annotation with [override] has the same
+ * effect as placing the annotation directly on the import of `dart:mirrors`
+ * in each of the referenced libraries. Thus, if the library had no
+ * [MirrorsUsed] annotation before, its unconditional import of
+ * `dart:mirrors` is overridden by an annotated import.
+ *
+ * Note that, like multiple explicit [MirrorsUsed] annotations, using
+ * override on a library with an existing [MirrorsUsed] annotation is
+ * additive. That is, the overall set of reflective targets is the union
+ * of the reflective targets that arise from the original and the
+ * overriding [MirrorsUsed] annotations.
+ *
+ * The use of [override] is only meaningful for libraries that have an
+ * import of `dart:mirrors` without annotation because otherwise it would
+ * work exactly the same way without the [override] parameter.
+ *
+ * While the annotation will apply to the given target libraries, the
+ * [symbols], [targets] and [metaTargets] are still evaluated in the
+ * scope of the annotation. Thus, to select a target from library `foo`,
+ * a qualified name has to be used or, if the target is visible in the
+ * current scope, its type may be referenced.
+ *
+ * For example, the following code marks all targets in the library `foo`
+ * as reflectable that have a metadata annotation using the `Reflectable`
+ * class from the same library.
+ *
+ * @MirrorsUsed(metaTargets: "foo.Reflectable", override: "foo")
+ *
+ * However, the following code would require the use of the `Reflectable`
+ * class from the current library, instead.
+ *
+ * @MirrorsUsed(metaTargets: "Reflectable", override: "foo")
+ *
+ */
+ final override;
+
+ /**
+ * See the documentation for [MirrorsUsed.symbols], [MirrorsUsed.targets],
+ * [MirrorsUsed.metaTargets] and [MirrorsUsed.override] for documentation
+ * of the parameters.
+ */
+ const MirrorsUsed(
+ {this.symbols, this.targets, this.metaTargets, this.override});
+}
diff --git a/sdk_nnbd/lib/mirrors/mirrors_sources.gni b/sdk_nnbd/lib/mirrors/mirrors_sources.gni
new file mode 100644
index 0000000..e019c34
--- /dev/null
+++ b/sdk_nnbd/lib/mirrors/mirrors_sources.gni
@@ -0,0 +1,8 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+mirrors_sdk_sources = [
+ "mirrors.dart",
+ # The above file needs to be first if additional parts are added to the lib.
+]
diff --git a/sdk_nnbd/lib/profiler/profiler.dart b/sdk_nnbd/lib/profiler/profiler.dart
new file mode 100644
index 0000000..1b96dfe
--- /dev/null
+++ b/sdk_nnbd/lib/profiler/profiler.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Please see 'dart:developer'.
+@Deprecated("Dart SDK 1.12")
+library dart.profiler;
+
+export 'dart:developer'
+ show getCurrentTag, Counter, Gauge, Metric, Metrics, UserTag;
diff --git a/sdk_nnbd/lib/profiler/profiler_sources.gni b/sdk_nnbd/lib/profiler/profiler_sources.gni
new file mode 100644
index 0000000..adbf447
--- /dev/null
+++ b/sdk_nnbd/lib/profiler/profiler_sources.gni
@@ -0,0 +1,8 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+profiler_sdk_sources = [
+ "profiler.dart",
+ # The above file needs to be first if additional parts are added to the lib.
+]
diff --git a/sdk_nnbd/lib/svg/dart2js/svg_dart2js.dart b/sdk_nnbd/lib/svg/dart2js/svg_dart2js.dart
new file mode 100644
index 0000000..7966fd7
--- /dev/null
+++ b/sdk_nnbd/lib/svg/dart2js/svg_dart2js.dart
@@ -0,0 +1,4011 @@
+/**
+ * Scalable Vector Graphics:
+ * Two-dimensional vector graphics with support for events and animation.
+ *
+ * For details about the features and syntax of SVG, a W3C standard,
+ * refer to the
+ * [Scalable Vector Graphics Specification](http://www.w3.org/TR/SVG/).
+ *
+ * {@category Web}
+ */
+library dart.dom.svg;
+
+import 'dart:async';
+import 'dart:collection' hide LinkedList, LinkedListEntry;
+import 'dart:_internal' show FixedLengthListMixin;
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:_js_helper' show Creates, Returns, JSName, Native;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show Interceptor;
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:svg library.
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class _SvgElementFactoryProvider {
+ static SvgElement createSvgElement_tag(String tag) {
+ final Element temp =
+ document.createElementNS("http://www.w3.org/2000/svg", tag);
+ return temp;
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAElement")
+class AElement extends GraphicsElement implements UriReference {
+ // To suppress missing implicit constructor warnings.
+ factory AElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AElement() => _SvgElementFactoryProvider.createSvgElement_tag("a");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ AElement.created() : super.created();
+
+ final AnimatedString target;
+
+ // From SVGURIReference
+
+ final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAngle")
+class Angle extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Angle._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int SVG_ANGLETYPE_DEG = 2;
+
+ static const int SVG_ANGLETYPE_GRAD = 4;
+
+ static const int SVG_ANGLETYPE_RAD = 3;
+
+ static const int SVG_ANGLETYPE_UNKNOWN = 0;
+
+ static const int SVG_ANGLETYPE_UNSPECIFIED = 1;
+
+ final int unitType;
+
+ num value;
+
+ String valueAsString;
+
+ num valueInSpecifiedUnits;
+
+ void convertToSpecifiedUnits(int unitType) native;
+
+ void newValueSpecifiedUnits(int unitType, num valueInSpecifiedUnits) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGAnimateElement")
+class AnimateElement extends AnimationElement {
+ // To suppress missing implicit constructor warnings.
+ factory AnimateElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AnimateElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("animate");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ AnimateElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('animate') &&
+ (new SvgElement.tag('animate') is AnimateElement);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGAnimateMotionElement")
+class AnimateMotionElement extends AnimationElement {
+ // To suppress missing implicit constructor warnings.
+ factory AnimateMotionElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AnimateMotionElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("animateMotion");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ AnimateMotionElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('animateMotion') &&
+ (new SvgElement.tag('animateMotion') is AnimateMotionElement);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGAnimateTransformElement")
+class AnimateTransformElement extends AnimationElement {
+ // To suppress missing implicit constructor warnings.
+ factory AnimateTransformElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AnimateTransformElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("animateTransform");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ AnimateTransformElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('animateTransform') &&
+ (new SvgElement.tag('animateTransform') is AnimateTransformElement);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedAngle")
+class AnimatedAngle extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimatedAngle._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Angle animVal;
+
+ final Angle baseVal;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedBoolean")
+class AnimatedBoolean extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimatedBoolean._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool animVal;
+
+ bool baseVal;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedEnumeration")
+class AnimatedEnumeration extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimatedEnumeration._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int animVal;
+
+ int baseVal;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedInteger")
+class AnimatedInteger extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimatedInteger._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int animVal;
+
+ int baseVal;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedLength")
+class AnimatedLength extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimatedLength._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Length animVal;
+
+ final Length baseVal;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedLengthList")
+class AnimatedLengthList extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimatedLengthList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final LengthList animVal;
+
+ final LengthList baseVal;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedNumber")
+class AnimatedNumber extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimatedNumber._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num animVal;
+
+ num baseVal;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedNumberList")
+class AnimatedNumberList extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimatedNumberList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final NumberList animVal;
+
+ final NumberList baseVal;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedPreserveAspectRatio")
+class AnimatedPreserveAspectRatio extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimatedPreserveAspectRatio._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final PreserveAspectRatio animVal;
+
+ final PreserveAspectRatio baseVal;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedRect")
+class AnimatedRect extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimatedRect._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Rect animVal;
+
+ final Rect baseVal;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedString")
+class AnimatedString extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimatedString._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String animVal;
+
+ String baseVal;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimatedTransformList")
+class AnimatedTransformList extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AnimatedTransformList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final TransformList animVal;
+
+ final TransformList baseVal;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGAnimationElement")
+class AnimationElement extends SvgElement implements Tests {
+ // To suppress missing implicit constructor warnings.
+ factory AnimationElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AnimationElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("animation");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ AnimationElement.created() : super.created();
+
+ final SvgElement targetElement;
+
+ void beginElement() native;
+
+ void beginElementAt(num offset) native;
+
+ void endElement() native;
+
+ void endElementAt(num offset) native;
+
+ double getCurrentTime() native;
+
+ double getSimpleDuration() native;
+
+ double getStartTime() native;
+
+ // From SVGTests
+
+ final StringList requiredExtensions;
+
+ final StringList systemLanguage;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGCircleElement")
+class CircleElement extends GeometryElement {
+ // To suppress missing implicit constructor warnings.
+ factory CircleElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory CircleElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("circle");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ CircleElement.created() : super.created();
+
+ final AnimatedLength cx;
+
+ final AnimatedLength cy;
+
+ final AnimatedLength r;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGClipPathElement")
+class ClipPathElement extends GraphicsElement {
+ // To suppress missing implicit constructor warnings.
+ factory ClipPathElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ClipPathElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("clipPath");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ClipPathElement.created() : super.created();
+
+ final AnimatedEnumeration clipPathUnits;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGDefsElement")
+class DefsElement extends GraphicsElement {
+ // To suppress missing implicit constructor warnings.
+ factory DefsElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DefsElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("defs");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ DefsElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGDescElement")
+class DescElement extends SvgElement {
+ // To suppress missing implicit constructor warnings.
+ factory DescElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DescElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("desc");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ DescElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SVGDiscardElement")
+class DiscardElement extends SvgElement {
+ // To suppress missing implicit constructor warnings.
+ factory DiscardElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ DiscardElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGEllipseElement")
+class EllipseElement extends GeometryElement {
+ // To suppress missing implicit constructor warnings.
+ factory EllipseElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory EllipseElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("ellipse");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ EllipseElement.created() : super.created();
+
+ final AnimatedLength cx;
+
+ final AnimatedLength cy;
+
+ final AnimatedLength rx;
+
+ final AnimatedLength ry;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEBlendElement")
+class FEBlendElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FEBlendElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEBlendElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feBlend");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEBlendElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feBlend') &&
+ (new SvgElement.tag('feBlend') is FEBlendElement);
+
+ static const int SVG_FEBLEND_MODE_DARKEN = 4;
+
+ static const int SVG_FEBLEND_MODE_LIGHTEN = 5;
+
+ static const int SVG_FEBLEND_MODE_MULTIPLY = 2;
+
+ static const int SVG_FEBLEND_MODE_NORMAL = 1;
+
+ static const int SVG_FEBLEND_MODE_SCREEN = 3;
+
+ static const int SVG_FEBLEND_MODE_UNKNOWN = 0;
+
+ final AnimatedString in1;
+
+ final AnimatedString in2;
+
+ final AnimatedEnumeration mode;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEColorMatrixElement")
+class FEColorMatrixElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FEColorMatrixElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEColorMatrixElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feColorMatrix");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEColorMatrixElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feColorMatrix') &&
+ (new SvgElement.tag('feColorMatrix') is FEColorMatrixElement);
+
+ static const int SVG_FECOLORMATRIX_TYPE_HUEROTATE = 3;
+
+ static const int SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4;
+
+ static const int SVG_FECOLORMATRIX_TYPE_MATRIX = 1;
+
+ static const int SVG_FECOLORMATRIX_TYPE_SATURATE = 2;
+
+ static const int SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0;
+
+ final AnimatedString in1;
+
+ final AnimatedEnumeration type;
+
+ final AnimatedNumberList values;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEComponentTransferElement")
+class FEComponentTransferElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FEComponentTransferElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEComponentTransferElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feComponentTransfer");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEComponentTransferElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feComponentTransfer') &&
+ (new SvgElement.tag('feComponentTransfer') is FEComponentTransferElement);
+
+ final AnimatedString in1;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGFECompositeElement")
+class FECompositeElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FECompositeElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FECompositeElement.created() : super.created();
+
+ static const int SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6;
+
+ static const int SVG_FECOMPOSITE_OPERATOR_ATOP = 4;
+
+ static const int SVG_FECOMPOSITE_OPERATOR_IN = 2;
+
+ static const int SVG_FECOMPOSITE_OPERATOR_OUT = 3;
+
+ static const int SVG_FECOMPOSITE_OPERATOR_OVER = 1;
+
+ static const int SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0;
+
+ static const int SVG_FECOMPOSITE_OPERATOR_XOR = 5;
+
+ final AnimatedString in1;
+
+ final AnimatedString in2;
+
+ final AnimatedNumber k1;
+
+ final AnimatedNumber k2;
+
+ final AnimatedNumber k3;
+
+ final AnimatedNumber k4;
+
+ final AnimatedEnumeration operator;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEConvolveMatrixElement")
+class FEConvolveMatrixElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FEConvolveMatrixElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEConvolveMatrixElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feConvolveMatrix");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEConvolveMatrixElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feConvolveMatrix') &&
+ (new SvgElement.tag('feConvolveMatrix') is FEConvolveMatrixElement);
+
+ static const int SVG_EDGEMODE_DUPLICATE = 1;
+
+ static const int SVG_EDGEMODE_NONE = 3;
+
+ static const int SVG_EDGEMODE_UNKNOWN = 0;
+
+ static const int SVG_EDGEMODE_WRAP = 2;
+
+ final AnimatedNumber bias;
+
+ final AnimatedNumber divisor;
+
+ final AnimatedEnumeration edgeMode;
+
+ final AnimatedString in1;
+
+ final AnimatedNumberList kernelMatrix;
+
+ final AnimatedNumber kernelUnitLengthX;
+
+ final AnimatedNumber kernelUnitLengthY;
+
+ final AnimatedInteger orderX;
+
+ final AnimatedInteger orderY;
+
+ final AnimatedBoolean preserveAlpha;
+
+ final AnimatedInteger targetX;
+
+ final AnimatedInteger targetY;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEDiffuseLightingElement")
+class FEDiffuseLightingElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FEDiffuseLightingElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEDiffuseLightingElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feDiffuseLighting");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEDiffuseLightingElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feDiffuseLighting') &&
+ (new SvgElement.tag('feDiffuseLighting') is FEDiffuseLightingElement);
+
+ final AnimatedNumber diffuseConstant;
+
+ final AnimatedString in1;
+
+ final AnimatedNumber kernelUnitLengthX;
+
+ final AnimatedNumber kernelUnitLengthY;
+
+ final AnimatedNumber surfaceScale;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEDisplacementMapElement")
+class FEDisplacementMapElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FEDisplacementMapElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEDisplacementMapElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feDisplacementMap");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEDisplacementMapElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feDisplacementMap') &&
+ (new SvgElement.tag('feDisplacementMap') is FEDisplacementMapElement);
+
+ static const int SVG_CHANNEL_A = 4;
+
+ static const int SVG_CHANNEL_B = 3;
+
+ static const int SVG_CHANNEL_G = 2;
+
+ static const int SVG_CHANNEL_R = 1;
+
+ static const int SVG_CHANNEL_UNKNOWN = 0;
+
+ final AnimatedString in1;
+
+ final AnimatedString in2;
+
+ final AnimatedNumber scale;
+
+ final AnimatedEnumeration xChannelSelector;
+
+ final AnimatedEnumeration yChannelSelector;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEDistantLightElement")
+class FEDistantLightElement extends SvgElement {
+ // To suppress missing implicit constructor warnings.
+ factory FEDistantLightElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEDistantLightElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feDistantLight");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEDistantLightElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feDistantLight') &&
+ (new SvgElement.tag('feDistantLight') is FEDistantLightElement);
+
+ final AnimatedNumber azimuth;
+
+ final AnimatedNumber elevation;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEFloodElement")
+class FEFloodElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FEFloodElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEFloodElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feFlood");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEFloodElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feFlood') &&
+ (new SvgElement.tag('feFlood') is FEFloodElement);
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEFuncAElement")
+class FEFuncAElement extends _SVGComponentTransferFunctionElement {
+ // To suppress missing implicit constructor warnings.
+ factory FEFuncAElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEFuncAElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feFuncA");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEFuncAElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feFuncA') &&
+ (new SvgElement.tag('feFuncA') is FEFuncAElement);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEFuncBElement")
+class FEFuncBElement extends _SVGComponentTransferFunctionElement {
+ // To suppress missing implicit constructor warnings.
+ factory FEFuncBElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEFuncBElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feFuncB");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEFuncBElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feFuncB') &&
+ (new SvgElement.tag('feFuncB') is FEFuncBElement);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEFuncGElement")
+class FEFuncGElement extends _SVGComponentTransferFunctionElement {
+ // To suppress missing implicit constructor warnings.
+ factory FEFuncGElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEFuncGElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feFuncG");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEFuncGElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feFuncG') &&
+ (new SvgElement.tag('feFuncG') is FEFuncGElement);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEFuncRElement")
+class FEFuncRElement extends _SVGComponentTransferFunctionElement {
+ // To suppress missing implicit constructor warnings.
+ factory FEFuncRElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEFuncRElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feFuncR");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEFuncRElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feFuncR') &&
+ (new SvgElement.tag('feFuncR') is FEFuncRElement);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEGaussianBlurElement")
+class FEGaussianBlurElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FEGaussianBlurElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEGaussianBlurElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feGaussianBlur");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEGaussianBlurElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feGaussianBlur') &&
+ (new SvgElement.tag('feGaussianBlur') is FEGaussianBlurElement);
+
+ final AnimatedString in1;
+
+ final AnimatedNumber stdDeviationX;
+
+ final AnimatedNumber stdDeviationY;
+
+ void setStdDeviation(num stdDeviationX, num stdDeviationY) native;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEImageElement")
+class FEImageElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes, UriReference {
+ // To suppress missing implicit constructor warnings.
+ factory FEImageElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEImageElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feImage");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEImageElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feImage') &&
+ (new SvgElement.tag('feImage') is FEImageElement);
+
+ final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+
+ // From SVGURIReference
+
+ final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEMergeElement")
+class FEMergeElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FEMergeElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEMergeElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feMerge");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEMergeElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feMerge') &&
+ (new SvgElement.tag('feMerge') is FEMergeElement);
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEMergeNodeElement")
+class FEMergeNodeElement extends SvgElement {
+ // To suppress missing implicit constructor warnings.
+ factory FEMergeNodeElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEMergeNodeElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feMergeNode");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEMergeNodeElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feMergeNode') &&
+ (new SvgElement.tag('feMergeNode') is FEMergeNodeElement);
+
+ final AnimatedString in1;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEMorphologyElement")
+class FEMorphologyElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FEMorphologyElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEMorphologyElement.created() : super.created();
+
+ static const int SVG_MORPHOLOGY_OPERATOR_DILATE = 2;
+
+ static const int SVG_MORPHOLOGY_OPERATOR_ERODE = 1;
+
+ static const int SVG_MORPHOLOGY_OPERATOR_UNKNOWN = 0;
+
+ final AnimatedString in1;
+
+ final AnimatedEnumeration operator;
+
+ final AnimatedNumber radiusX;
+
+ final AnimatedNumber radiusY;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEOffsetElement")
+class FEOffsetElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FEOffsetElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEOffsetElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feOffset");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEOffsetElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feOffset') &&
+ (new SvgElement.tag('feOffset') is FEOffsetElement);
+
+ final AnimatedNumber dx;
+
+ final AnimatedNumber dy;
+
+ final AnimatedString in1;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFEPointLightElement")
+class FEPointLightElement extends SvgElement {
+ // To suppress missing implicit constructor warnings.
+ factory FEPointLightElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FEPointLightElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("fePointLight");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FEPointLightElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('fePointLight') &&
+ (new SvgElement.tag('fePointLight') is FEPointLightElement);
+
+ final AnimatedNumber x;
+
+ final AnimatedNumber y;
+
+ final AnimatedNumber z;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFESpecularLightingElement")
+class FESpecularLightingElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FESpecularLightingElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FESpecularLightingElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feSpecularLighting");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FESpecularLightingElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feSpecularLighting') &&
+ (new SvgElement.tag('feSpecularLighting') is FESpecularLightingElement);
+
+ final AnimatedString in1;
+
+ final AnimatedNumber kernelUnitLengthX;
+
+ final AnimatedNumber kernelUnitLengthY;
+
+ final AnimatedNumber specularConstant;
+
+ final AnimatedNumber specularExponent;
+
+ final AnimatedNumber surfaceScale;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFESpotLightElement")
+class FESpotLightElement extends SvgElement {
+ // To suppress missing implicit constructor warnings.
+ factory FESpotLightElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FESpotLightElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feSpotLight");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FESpotLightElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feSpotLight') &&
+ (new SvgElement.tag('feSpotLight') is FESpotLightElement);
+
+ final AnimatedNumber limitingConeAngle;
+
+ final AnimatedNumber pointsAtX;
+
+ final AnimatedNumber pointsAtY;
+
+ final AnimatedNumber pointsAtZ;
+
+ final AnimatedNumber specularExponent;
+
+ final AnimatedNumber x;
+
+ final AnimatedNumber y;
+
+ final AnimatedNumber z;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFETileElement")
+class FETileElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FETileElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FETileElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feTile");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FETileElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feTile') &&
+ (new SvgElement.tag('feTile') is FETileElement);
+
+ final AnimatedString in1;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFETurbulenceElement")
+class FETurbulenceElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory FETurbulenceElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FETurbulenceElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("feTurbulence");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FETurbulenceElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('feTurbulence') &&
+ (new SvgElement.tag('feTurbulence') is FETurbulenceElement);
+
+ static const int SVG_STITCHTYPE_NOSTITCH = 2;
+
+ static const int SVG_STITCHTYPE_STITCH = 1;
+
+ static const int SVG_STITCHTYPE_UNKNOWN = 0;
+
+ static const int SVG_TURBULENCE_TYPE_FRACTALNOISE = 1;
+
+ static const int SVG_TURBULENCE_TYPE_TURBULENCE = 2;
+
+ static const int SVG_TURBULENCE_TYPE_UNKNOWN = 0;
+
+ final AnimatedNumber baseFrequencyX;
+
+ final AnimatedNumber baseFrequencyY;
+
+ final AnimatedInteger numOctaves;
+
+ final AnimatedNumber seed;
+
+ final AnimatedEnumeration stitchTiles;
+
+ final AnimatedEnumeration type;
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGFilterElement")
+class FilterElement extends SvgElement implements UriReference {
+ // To suppress missing implicit constructor warnings.
+ factory FilterElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory FilterElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("filter");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ FilterElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('filter') &&
+ (new SvgElement.tag('filter') is FilterElement);
+
+ final AnimatedEnumeration filterUnits;
+
+ final AnimatedLength height;
+
+ final AnimatedEnumeration primitiveUnits;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+
+ // From SVGURIReference
+
+ final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+abstract class FilterPrimitiveStandardAttributes extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory FilterPrimitiveStandardAttributes._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final AnimatedLength height;
+
+ final AnimatedString result;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+abstract class FitToViewBox extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory FitToViewBox._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+ final AnimatedRect viewBox;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGForeignObjectElement")
+class ForeignObjectElement extends GraphicsElement {
+ // To suppress missing implicit constructor warnings.
+ factory ForeignObjectElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ForeignObjectElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("foreignObject");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ForeignObjectElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('foreignObject') &&
+ (new SvgElement.tag('foreignObject') is ForeignObjectElement);
+
+ final AnimatedLength height;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGGElement")
+class GElement extends GraphicsElement {
+ // To suppress missing implicit constructor warnings.
+ factory GElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory GElement() => _SvgElementFactoryProvider.createSvgElement_tag("g");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ GElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SVGGeometryElement")
+class GeometryElement extends GraphicsElement {
+ // To suppress missing implicit constructor warnings.
+ factory GeometryElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ GeometryElement.created() : super.created();
+
+ final AnimatedNumber pathLength;
+
+ Point getPointAtLength(num distance) native;
+
+ double getTotalLength() native;
+
+ bool isPointInFill(Point point) native;
+
+ bool isPointInStroke(Point point) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SVGGraphicsElement")
+class GraphicsElement extends SvgElement implements Tests {
+ // To suppress missing implicit constructor warnings.
+ factory GraphicsElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ GraphicsElement.created() : super.created();
+
+ final SvgElement farthestViewportElement;
+
+ final SvgElement nearestViewportElement;
+
+ final AnimatedTransformList transform;
+
+ Rect getBBox() native;
+
+ @JSName('getCTM')
+ Matrix getCtm() native;
+
+ @JSName('getScreenCTM')
+ Matrix getScreenCtm() native;
+
+ // From SVGTests
+
+ final StringList requiredExtensions;
+
+ final StringList systemLanguage;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGImageElement")
+class ImageElement extends GraphicsElement implements UriReference {
+ // To suppress missing implicit constructor warnings.
+ factory ImageElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ImageElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("image");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ImageElement.created() : super.created();
+
+ String async;
+
+ final AnimatedLength height;
+
+ final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+
+ Future decode() => promiseToFuture(JS("", "#.decode()", this));
+
+ // From SVGURIReference
+
+ final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGLength")
+class Length extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Length._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int SVG_LENGTHTYPE_CM = 6;
+
+ static const int SVG_LENGTHTYPE_EMS = 3;
+
+ static const int SVG_LENGTHTYPE_EXS = 4;
+
+ static const int SVG_LENGTHTYPE_IN = 8;
+
+ static const int SVG_LENGTHTYPE_MM = 7;
+
+ static const int SVG_LENGTHTYPE_NUMBER = 1;
+
+ static const int SVG_LENGTHTYPE_PC = 10;
+
+ static const int SVG_LENGTHTYPE_PERCENTAGE = 2;
+
+ static const int SVG_LENGTHTYPE_PT = 9;
+
+ static const int SVG_LENGTHTYPE_PX = 5;
+
+ static const int SVG_LENGTHTYPE_UNKNOWN = 0;
+
+ final int unitType;
+
+ num value;
+
+ String valueAsString;
+
+ num valueInSpecifiedUnits;
+
+ void convertToSpecifiedUnits(int unitType) native;
+
+ void newValueSpecifiedUnits(int unitType, num valueInSpecifiedUnits) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGLengthList")
+class LengthList extends Interceptor
+ with ListMixin<Length>, ImmutableListMixin<Length>
+ implements List<Length> {
+ // To suppress missing implicit constructor warnings.
+ factory LengthList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ final int numberOfItems;
+
+ Length operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return this.getItem(index);
+ }
+
+ void operator []=(int index, Length value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<Length> mixins.
+ // Length is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ Length get first {
+ if (this.length > 0) {
+ return JS('Length', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ Length get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('Length', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ Length get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('Length', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ Length elementAt(int index) => this[index];
+ // -- end List<Length> mixins.
+
+ void __setter__(int index, Length newItem) native;
+
+ Length appendItem(Length newItem) native;
+
+ void clear() native;
+
+ Length getItem(int index) native;
+
+ Length initialize(Length newItem) native;
+
+ Length insertItemBefore(Length newItem, int index) native;
+
+ Length removeItem(int index) native;
+
+ Length replaceItem(Length newItem, int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGLineElement")
+class LineElement extends GeometryElement {
+ // To suppress missing implicit constructor warnings.
+ factory LineElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory LineElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("line");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ LineElement.created() : super.created();
+
+ final AnimatedLength x1;
+
+ final AnimatedLength x2;
+
+ final AnimatedLength y1;
+
+ final AnimatedLength y2;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGLinearGradientElement")
+class LinearGradientElement extends _GradientElement {
+ // To suppress missing implicit constructor warnings.
+ factory LinearGradientElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory LinearGradientElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("linearGradient");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ LinearGradientElement.created() : super.created();
+
+ final AnimatedLength x1;
+
+ final AnimatedLength x2;
+
+ final AnimatedLength y1;
+
+ final AnimatedLength y2;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGMarkerElement")
+class MarkerElement extends SvgElement implements FitToViewBox {
+ // To suppress missing implicit constructor warnings.
+ factory MarkerElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MarkerElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("marker");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ MarkerElement.created() : super.created();
+
+ static const int SVG_MARKERUNITS_STROKEWIDTH = 2;
+
+ static const int SVG_MARKERUNITS_UNKNOWN = 0;
+
+ static const int SVG_MARKERUNITS_USERSPACEONUSE = 1;
+
+ static const int SVG_MARKER_ORIENT_ANGLE = 2;
+
+ static const int SVG_MARKER_ORIENT_AUTO = 1;
+
+ static const int SVG_MARKER_ORIENT_UNKNOWN = 0;
+
+ final AnimatedLength markerHeight;
+
+ final AnimatedEnumeration markerUnits;
+
+ final AnimatedLength markerWidth;
+
+ final AnimatedAngle orientAngle;
+
+ final AnimatedEnumeration orientType;
+
+ final AnimatedLength refX;
+
+ final AnimatedLength refY;
+
+ void setOrientToAngle(Angle angle) native;
+
+ void setOrientToAuto() native;
+
+ // From SVGFitToViewBox
+
+ final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+ final AnimatedRect viewBox;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGMaskElement")
+class MaskElement extends SvgElement implements Tests {
+ // To suppress missing implicit constructor warnings.
+ factory MaskElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MaskElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("mask");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ MaskElement.created() : super.created();
+
+ final AnimatedLength height;
+
+ final AnimatedEnumeration maskContentUnits;
+
+ final AnimatedEnumeration maskUnits;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+
+ // From SVGTests
+
+ final StringList requiredExtensions;
+
+ final StringList systemLanguage;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGMatrix")
+class Matrix extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Matrix._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ num a;
+
+ num b;
+
+ num c;
+
+ num d;
+
+ num e;
+
+ num f;
+
+ Matrix flipX() native;
+
+ Matrix flipY() native;
+
+ Matrix inverse() native;
+
+ Matrix multiply(Matrix secondMatrix) native;
+
+ Matrix rotate(num angle) native;
+
+ Matrix rotateFromVector(num x, num y) native;
+
+ Matrix scale(num scaleFactor) native;
+
+ Matrix scaleNonUniform(num scaleFactorX, num scaleFactorY) native;
+
+ Matrix skewX(num angle) native;
+
+ Matrix skewY(num angle) native;
+
+ Matrix translate(num x, num y) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGMetadataElement")
+class MetadataElement extends SvgElement {
+ // To suppress missing implicit constructor warnings.
+ factory MetadataElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ MetadataElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGNumber")
+class Number extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Number._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ num value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGNumberList")
+class NumberList extends Interceptor
+ with ListMixin<Number>, ImmutableListMixin<Number>
+ implements List<Number> {
+ // To suppress missing implicit constructor warnings.
+ factory NumberList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ final int numberOfItems;
+
+ Number operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return this.getItem(index);
+ }
+
+ void operator []=(int index, Number value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<Number> mixins.
+ // Number is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ Number get first {
+ if (this.length > 0) {
+ return JS('Number', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ Number get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('Number', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ Number get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('Number', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ Number elementAt(int index) => this[index];
+ // -- end List<Number> mixins.
+
+ void __setter__(int index, Number newItem) native;
+
+ Number appendItem(Number newItem) native;
+
+ void clear() native;
+
+ Number getItem(int index) native;
+
+ Number initialize(Number newItem) native;
+
+ Number insertItemBefore(Number newItem, int index) native;
+
+ Number removeItem(int index) native;
+
+ Number replaceItem(Number newItem, int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPathElement")
+class PathElement extends GeometryElement {
+ // To suppress missing implicit constructor warnings.
+ factory PathElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PathElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("path");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ PathElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPatternElement")
+class PatternElement extends SvgElement
+ implements FitToViewBox, UriReference, Tests {
+ // To suppress missing implicit constructor warnings.
+ factory PatternElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PatternElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("pattern");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ PatternElement.created() : super.created();
+
+ final AnimatedLength height;
+
+ final AnimatedEnumeration patternContentUnits;
+
+ final AnimatedTransformList patternTransform;
+
+ final AnimatedEnumeration patternUnits;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+
+ // From SVGFitToViewBox
+
+ final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+ final AnimatedRect viewBox;
+
+ // From SVGTests
+
+ final StringList requiredExtensions;
+
+ final StringList systemLanguage;
+
+ // From SVGURIReference
+
+ final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPoint")
+class Point extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Point._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ num x;
+
+ num y;
+
+ Point matrixTransform(Matrix matrix) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPointList")
+class PointList extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PointList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int length;
+
+ final int numberOfItems;
+
+ void __setter__(int index, Point newItem) native;
+
+ Point appendItem(Point newItem) native;
+
+ void clear() native;
+
+ Point getItem(int index) native;
+
+ Point initialize(Point newItem) native;
+
+ Point insertItemBefore(Point newItem, int index) native;
+
+ Point removeItem(int index) native;
+
+ Point replaceItem(Point newItem, int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPolygonElement")
+class PolygonElement extends GeometryElement {
+ // To suppress missing implicit constructor warnings.
+ factory PolygonElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PolygonElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("polygon");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ PolygonElement.created() : super.created();
+
+ final PointList animatedPoints;
+
+ final PointList points;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPolylineElement")
+class PolylineElement extends GeometryElement {
+ // To suppress missing implicit constructor warnings.
+ factory PolylineElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PolylineElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("polyline");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ PolylineElement.created() : super.created();
+
+ final PointList animatedPoints;
+
+ final PointList points;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGPreserveAspectRatio")
+class PreserveAspectRatio extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PreserveAspectRatio._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int SVG_MEETORSLICE_MEET = 1;
+
+ static const int SVG_MEETORSLICE_SLICE = 2;
+
+ static const int SVG_MEETORSLICE_UNKNOWN = 0;
+
+ static const int SVG_PRESERVEASPECTRATIO_NONE = 1;
+
+ static const int SVG_PRESERVEASPECTRATIO_UNKNOWN = 0;
+
+ static const int SVG_PRESERVEASPECTRATIO_XMAXYMAX = 10;
+
+ static const int SVG_PRESERVEASPECTRATIO_XMAXYMID = 7;
+
+ static const int SVG_PRESERVEASPECTRATIO_XMAXYMIN = 4;
+
+ static const int SVG_PRESERVEASPECTRATIO_XMIDYMAX = 9;
+
+ static const int SVG_PRESERVEASPECTRATIO_XMIDYMID = 6;
+
+ static const int SVG_PRESERVEASPECTRATIO_XMIDYMIN = 3;
+
+ static const int SVG_PRESERVEASPECTRATIO_XMINYMAX = 8;
+
+ static const int SVG_PRESERVEASPECTRATIO_XMINYMID = 5;
+
+ static const int SVG_PRESERVEASPECTRATIO_XMINYMIN = 2;
+
+ int align;
+
+ int meetOrSlice;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGRadialGradientElement")
+class RadialGradientElement extends _GradientElement {
+ // To suppress missing implicit constructor warnings.
+ factory RadialGradientElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory RadialGradientElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("radialGradient");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ RadialGradientElement.created() : super.created();
+
+ final AnimatedLength cx;
+
+ final AnimatedLength cy;
+
+ final AnimatedLength fr;
+
+ final AnimatedLength fx;
+
+ final AnimatedLength fy;
+
+ final AnimatedLength r;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGRect")
+class Rect extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Rect._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ num height;
+
+ num width;
+
+ num x;
+
+ num y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGRectElement")
+class RectElement extends GeometryElement {
+ // To suppress missing implicit constructor warnings.
+ factory RectElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory RectElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("rect");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ RectElement.created() : super.created();
+
+ final AnimatedLength height;
+
+ final AnimatedLength rx;
+
+ final AnimatedLength ry;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGScriptElement")
+class ScriptElement extends SvgElement implements UriReference {
+ // To suppress missing implicit constructor warnings.
+ factory ScriptElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ScriptElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("script");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ScriptElement.created() : super.created();
+
+ String type;
+
+ // From SVGURIReference
+
+ final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Unstable()
+@Native("SVGSetElement")
+class SetElement extends AnimationElement {
+ // To suppress missing implicit constructor warnings.
+ factory SetElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SetElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("set");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ SetElement.created() : super.created();
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ SvgElement.isTagSupported('set') &&
+ (new SvgElement.tag('set') is SetElement);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGStopElement")
+class StopElement extends SvgElement {
+ // To suppress missing implicit constructor warnings.
+ factory StopElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory StopElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("stop");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ StopElement.created() : super.created();
+
+ @JSName('offset')
+ final AnimatedNumber gradientOffset;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGStringList")
+class StringList extends Interceptor
+ with ListMixin<String>, ImmutableListMixin<String>
+ implements List<String> {
+ // To suppress missing implicit constructor warnings.
+ factory StringList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ final int numberOfItems;
+
+ String operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return this.getItem(index);
+ }
+
+ void operator []=(int index, String value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<String> mixins.
+ // String is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ String get first {
+ if (this.length > 0) {
+ return JS('String', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ String get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('String', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ String get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('String', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ String elementAt(int index) => this[index];
+ // -- end List<String> mixins.
+
+ void __setter__(int index, String newItem) native;
+
+ String appendItem(String newItem) native;
+
+ void clear() native;
+
+ String getItem(int index) native;
+
+ String initialize(String newItem) native;
+
+ String insertItemBefore(String item, int index) native;
+
+ String removeItem(int index) native;
+
+ String replaceItem(String newItem, int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SVGStyleElement")
+class StyleElement extends SvgElement {
+ // To suppress missing implicit constructor warnings.
+ factory StyleElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory StyleElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("style");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ StyleElement.created() : super.created();
+
+ bool disabled;
+
+ String media;
+
+ final StyleSheet sheet;
+
+ // Use implementation from Element.
+ // final String title;
+
+ String type;
+}
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class AttributeClassSet extends CssClassSetImpl {
+ final Element _element;
+
+ AttributeClassSet(this._element);
+
+ Set<String> readClasses() {
+ var classname = _element.attributes['class'];
+ if (classname is AnimatedString) {
+ classname = (classname as AnimatedString).baseVal;
+ }
+
+ Set<String> s = new LinkedHashSet<String>();
+ if (classname == null) {
+ return s;
+ }
+ for (String name in classname.split(' ')) {
+ String trimmed = name.trim();
+ if (!trimmed.isEmpty) {
+ s.add(trimmed);
+ }
+ }
+ return s;
+ }
+
+ void writeClasses(Set s) {
+ _element.setAttribute('class', s.join(' '));
+ }
+}
+
+@Unstable()
+@Native("SVGElement")
+class SvgElement extends Element implements GlobalEventHandlers, NoncedElement {
+ static final _START_TAG_REGEXP = new RegExp('<(\\w+)');
+
+ factory SvgElement.tag(String tag) =>
+ document.createElementNS("http://www.w3.org/2000/svg", tag);
+ factory SvgElement.svg(String svg,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ if (validator == null && treeSanitizer == null) {
+ validator = new NodeValidatorBuilder.common()..allowSvg();
+ }
+
+ final match = _START_TAG_REGEXP.firstMatch(svg);
+ var parentElement;
+ if (match != null && match.group(1).toLowerCase() == 'svg') {
+ parentElement = document.body;
+ } else {
+ parentElement = new SvgSvgElement();
+ }
+ var fragment = parentElement.createFragment(svg,
+ validator: validator, treeSanitizer: treeSanitizer);
+ return fragment.nodes.where((e) => e is SvgElement).single;
+ }
+
+ CssClassSet get classes => new AttributeClassSet(this);
+
+ List<Element> get children => new FilteredElementList(this);
+
+ set children(List<Element> value) {
+ final children = this.children;
+ children.clear();
+ children.addAll(value);
+ }
+
+ String get outerHtml {
+ final container = new DivElement();
+ final SvgElement cloned = this.clone(true);
+ container.children.add(cloned);
+ return container.innerHtml;
+ }
+
+ String get innerHtml {
+ final container = new DivElement();
+ final SvgElement cloned = this.clone(true);
+ container.children.addAll(cloned.children);
+ return container.innerHtml;
+ }
+
+ set innerHtml(String value) {
+ this.setInnerHtml(value);
+ }
+
+ DocumentFragment createFragment(String svg,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ if (treeSanitizer == null) {
+ if (validator == null) {
+ validator = new NodeValidatorBuilder.common()..allowSvg();
+ }
+ treeSanitizer = new NodeTreeSanitizer(validator);
+ }
+
+ // We create a fragment which will parse in the HTML parser
+ var html = '<svg version="1.1">$svg</svg>';
+ var fragment =
+ document.body.createFragment(html, treeSanitizer: treeSanitizer);
+
+ var svgFragment = new DocumentFragment();
+ // The root is the <svg/> element, need to pull out the contents.
+ var root = fragment.nodes.single;
+ while (root.firstChild != null) {
+ svgFragment.append(root.firstChild);
+ }
+ return svgFragment;
+ }
+
+ // Unsupported methods inherited from Element.
+
+ void insertAdjacentText(String where, String text) {
+ throw new UnsupportedError("Cannot invoke insertAdjacentText on SVG.");
+ }
+
+ void insertAdjacentHtml(String where, String text,
+ {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
+ throw new UnsupportedError("Cannot invoke insertAdjacentHtml on SVG.");
+ }
+
+ Element insertAdjacentElement(String where, Element element) {
+ throw new UnsupportedError("Cannot invoke insertAdjacentElement on SVG.");
+ }
+
+ HtmlCollection get _children {
+ throw new UnsupportedError("Cannot get _children on SVG.");
+ }
+
+ bool get isContentEditable => false;
+ void click() {
+ throw new UnsupportedError("Cannot invoke click SVG.");
+ }
+
+ /**
+ * Checks to see if the SVG element type is supported by the current platform.
+ *
+ * The tag should be a valid SVG element tag name.
+ */
+ static bool isTagSupported(String tag) {
+ var e = new SvgElement.tag(tag);
+ return e is SvgElement && !(e is UnknownElement);
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory SvgElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> abortEvent =
+ const EventStreamProvider<Event>('abort');
+
+ static const EventStreamProvider<Event> blurEvent =
+ const EventStreamProvider<Event>('blur');
+
+ static const EventStreamProvider<Event> canPlayEvent =
+ const EventStreamProvider<Event>('canplay');
+
+ static const EventStreamProvider<Event> canPlayThroughEvent =
+ const EventStreamProvider<Event>('canplaythrough');
+
+ static const EventStreamProvider<Event> changeEvent =
+ const EventStreamProvider<Event>('change');
+
+ static const EventStreamProvider<MouseEvent> clickEvent =
+ const EventStreamProvider<MouseEvent>('click');
+
+ static const EventStreamProvider<MouseEvent> contextMenuEvent =
+ const EventStreamProvider<MouseEvent>('contextmenu');
+
+ @DomName('SVGElement.dblclickEvent')
+ static const EventStreamProvider<Event> doubleClickEvent =
+ const EventStreamProvider<Event>('dblclick');
+
+ static const EventStreamProvider<MouseEvent> dragEvent =
+ const EventStreamProvider<MouseEvent>('drag');
+
+ static const EventStreamProvider<MouseEvent> dragEndEvent =
+ const EventStreamProvider<MouseEvent>('dragend');
+
+ static const EventStreamProvider<MouseEvent> dragEnterEvent =
+ const EventStreamProvider<MouseEvent>('dragenter');
+
+ static const EventStreamProvider<MouseEvent> dragLeaveEvent =
+ const EventStreamProvider<MouseEvent>('dragleave');
+
+ static const EventStreamProvider<MouseEvent> dragOverEvent =
+ const EventStreamProvider<MouseEvent>('dragover');
+
+ static const EventStreamProvider<MouseEvent> dragStartEvent =
+ const EventStreamProvider<MouseEvent>('dragstart');
+
+ static const EventStreamProvider<MouseEvent> dropEvent =
+ const EventStreamProvider<MouseEvent>('drop');
+
+ static const EventStreamProvider<Event> durationChangeEvent =
+ const EventStreamProvider<Event>('durationchange');
+
+ static const EventStreamProvider<Event> emptiedEvent =
+ const EventStreamProvider<Event>('emptied');
+
+ static const EventStreamProvider<Event> endedEvent =
+ const EventStreamProvider<Event>('ended');
+
+ static const EventStreamProvider<Event> errorEvent =
+ const EventStreamProvider<Event>('error');
+
+ static const EventStreamProvider<Event> focusEvent =
+ const EventStreamProvider<Event>('focus');
+
+ static const EventStreamProvider<Event> inputEvent =
+ const EventStreamProvider<Event>('input');
+
+ static const EventStreamProvider<Event> invalidEvent =
+ const EventStreamProvider<Event>('invalid');
+
+ static const EventStreamProvider<KeyboardEvent> keyDownEvent =
+ const EventStreamProvider<KeyboardEvent>('keydown');
+
+ static const EventStreamProvider<KeyboardEvent> keyPressEvent =
+ const EventStreamProvider<KeyboardEvent>('keypress');
+
+ static const EventStreamProvider<KeyboardEvent> keyUpEvent =
+ const EventStreamProvider<KeyboardEvent>('keyup');
+
+ static const EventStreamProvider<Event> loadEvent =
+ const EventStreamProvider<Event>('load');
+
+ static const EventStreamProvider<Event> loadedDataEvent =
+ const EventStreamProvider<Event>('loadeddata');
+
+ static const EventStreamProvider<Event> loadedMetadataEvent =
+ const EventStreamProvider<Event>('loadedmetadata');
+
+ static const EventStreamProvider<MouseEvent> mouseDownEvent =
+ const EventStreamProvider<MouseEvent>('mousedown');
+
+ static const EventStreamProvider<MouseEvent> mouseEnterEvent =
+ const EventStreamProvider<MouseEvent>('mouseenter');
+
+ static const EventStreamProvider<MouseEvent> mouseLeaveEvent =
+ const EventStreamProvider<MouseEvent>('mouseleave');
+
+ static const EventStreamProvider<MouseEvent> mouseMoveEvent =
+ const EventStreamProvider<MouseEvent>('mousemove');
+
+ static const EventStreamProvider<MouseEvent> mouseOutEvent =
+ const EventStreamProvider<MouseEvent>('mouseout');
+
+ static const EventStreamProvider<MouseEvent> mouseOverEvent =
+ const EventStreamProvider<MouseEvent>('mouseover');
+
+ static const EventStreamProvider<MouseEvent> mouseUpEvent =
+ const EventStreamProvider<MouseEvent>('mouseup');
+
+ static const EventStreamProvider<WheelEvent> mouseWheelEvent =
+ const EventStreamProvider<WheelEvent>('mousewheel');
+
+ static const EventStreamProvider<Event> pauseEvent =
+ const EventStreamProvider<Event>('pause');
+
+ static const EventStreamProvider<Event> playEvent =
+ const EventStreamProvider<Event>('play');
+
+ static const EventStreamProvider<Event> playingEvent =
+ const EventStreamProvider<Event>('playing');
+
+ static const EventStreamProvider<Event> rateChangeEvent =
+ const EventStreamProvider<Event>('ratechange');
+
+ static const EventStreamProvider<Event> resetEvent =
+ const EventStreamProvider<Event>('reset');
+
+ static const EventStreamProvider<Event> resizeEvent =
+ const EventStreamProvider<Event>('resize');
+
+ static const EventStreamProvider<Event> scrollEvent =
+ const EventStreamProvider<Event>('scroll');
+
+ static const EventStreamProvider<Event> seekedEvent =
+ const EventStreamProvider<Event>('seeked');
+
+ static const EventStreamProvider<Event> seekingEvent =
+ const EventStreamProvider<Event>('seeking');
+
+ static const EventStreamProvider<Event> selectEvent =
+ const EventStreamProvider<Event>('select');
+
+ static const EventStreamProvider<Event> stalledEvent =
+ const EventStreamProvider<Event>('stalled');
+
+ static const EventStreamProvider<Event> submitEvent =
+ const EventStreamProvider<Event>('submit');
+
+ static const EventStreamProvider<Event> suspendEvent =
+ const EventStreamProvider<Event>('suspend');
+
+ static const EventStreamProvider<Event> timeUpdateEvent =
+ const EventStreamProvider<Event>('timeupdate');
+
+ static const EventStreamProvider<TouchEvent> touchCancelEvent =
+ const EventStreamProvider<TouchEvent>('touchcancel');
+
+ static const EventStreamProvider<TouchEvent> touchEndEvent =
+ const EventStreamProvider<TouchEvent>('touchend');
+
+ static const EventStreamProvider<TouchEvent> touchMoveEvent =
+ const EventStreamProvider<TouchEvent>('touchmove');
+
+ static const EventStreamProvider<TouchEvent> touchStartEvent =
+ const EventStreamProvider<TouchEvent>('touchstart');
+
+ static const EventStreamProvider<Event> volumeChangeEvent =
+ const EventStreamProvider<Event>('volumechange');
+
+ static const EventStreamProvider<Event> waitingEvent =
+ const EventStreamProvider<Event>('waiting');
+
+ static const EventStreamProvider<WheelEvent> wheelEvent =
+ const EventStreamProvider<WheelEvent>('wheel');
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ SvgElement.created() : super.created();
+
+ // Shadowing definition.
+ AnimatedString get _svgClassName => JS("AnimatedString", "#.className", this);
+
+ @JSName('ownerSVGElement')
+ final SvgSvgElement ownerSvgElement;
+
+ // Use implementation from Element.
+ // final CssStyleDeclaration style;
+
+ // Use implementation from Element.
+ // final int tabIndex;
+
+ final SvgElement viewportElement;
+
+ void blur() native;
+
+ void focus() native;
+
+ // From NoncedElement
+
+ String nonce;
+
+ ElementStream<Event> get onAbort => abortEvent.forElement(this);
+
+ ElementStream<Event> get onBlur => blurEvent.forElement(this);
+
+ ElementStream<Event> get onCanPlay => canPlayEvent.forElement(this);
+
+ ElementStream<Event> get onCanPlayThrough =>
+ canPlayThroughEvent.forElement(this);
+
+ ElementStream<Event> get onChange => changeEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onClick => clickEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onContextMenu =>
+ contextMenuEvent.forElement(this);
+
+ @DomName('SVGElement.ondblclick')
+ ElementStream<Event> get onDoubleClick => doubleClickEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onDrag => dragEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onDragEnd => dragEndEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onDragEnter => dragEnterEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onDragLeave => dragLeaveEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onDragOver => dragOverEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onDragStart => dragStartEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onDrop => dropEvent.forElement(this);
+
+ ElementStream<Event> get onDurationChange =>
+ durationChangeEvent.forElement(this);
+
+ ElementStream<Event> get onEmptied => emptiedEvent.forElement(this);
+
+ ElementStream<Event> get onEnded => endedEvent.forElement(this);
+
+ ElementStream<Event> get onError => errorEvent.forElement(this);
+
+ ElementStream<Event> get onFocus => focusEvent.forElement(this);
+
+ ElementStream<Event> get onInput => inputEvent.forElement(this);
+
+ ElementStream<Event> get onInvalid => invalidEvent.forElement(this);
+
+ ElementStream<KeyboardEvent> get onKeyDown => keyDownEvent.forElement(this);
+
+ ElementStream<KeyboardEvent> get onKeyPress => keyPressEvent.forElement(this);
+
+ ElementStream<KeyboardEvent> get onKeyUp => keyUpEvent.forElement(this);
+
+ ElementStream<Event> get onLoad => loadEvent.forElement(this);
+
+ ElementStream<Event> get onLoadedData => loadedDataEvent.forElement(this);
+
+ ElementStream<Event> get onLoadedMetadata =>
+ loadedMetadataEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onMouseDown => mouseDownEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onMouseEnter =>
+ mouseEnterEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onMouseLeave =>
+ mouseLeaveEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onMouseMove => mouseMoveEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onMouseOut => mouseOutEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onMouseOver => mouseOverEvent.forElement(this);
+
+ ElementStream<MouseEvent> get onMouseUp => mouseUpEvent.forElement(this);
+
+ ElementStream<WheelEvent> get onMouseWheel =>
+ mouseWheelEvent.forElement(this);
+
+ ElementStream<Event> get onPause => pauseEvent.forElement(this);
+
+ ElementStream<Event> get onPlay => playEvent.forElement(this);
+
+ ElementStream<Event> get onPlaying => playingEvent.forElement(this);
+
+ ElementStream<Event> get onRateChange => rateChangeEvent.forElement(this);
+
+ ElementStream<Event> get onReset => resetEvent.forElement(this);
+
+ ElementStream<Event> get onResize => resizeEvent.forElement(this);
+
+ ElementStream<Event> get onScroll => scrollEvent.forElement(this);
+
+ ElementStream<Event> get onSeeked => seekedEvent.forElement(this);
+
+ ElementStream<Event> get onSeeking => seekingEvent.forElement(this);
+
+ ElementStream<Event> get onSelect => selectEvent.forElement(this);
+
+ ElementStream<Event> get onStalled => stalledEvent.forElement(this);
+
+ ElementStream<Event> get onSubmit => submitEvent.forElement(this);
+
+ ElementStream<Event> get onSuspend => suspendEvent.forElement(this);
+
+ ElementStream<Event> get onTimeUpdate => timeUpdateEvent.forElement(this);
+
+ ElementStream<TouchEvent> get onTouchCancel =>
+ touchCancelEvent.forElement(this);
+
+ ElementStream<TouchEvent> get onTouchEnd => touchEndEvent.forElement(this);
+
+ ElementStream<TouchEvent> get onTouchMove => touchMoveEvent.forElement(this);
+
+ ElementStream<TouchEvent> get onTouchStart =>
+ touchStartEvent.forElement(this);
+
+ ElementStream<Event> get onVolumeChange => volumeChangeEvent.forElement(this);
+
+ ElementStream<Event> get onWaiting => waitingEvent.forElement(this);
+
+ ElementStream<WheelEvent> get onWheel => wheelEvent.forElement(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGSVGElement")
+class SvgSvgElement extends GraphicsElement
+ implements FitToViewBox, ZoomAndPan {
+ factory SvgSvgElement() {
+ final el = new SvgElement.tag("svg");
+ // The SVG spec requires the version attribute to match the spec version
+ el.attributes['version'] = "1.1";
+ return el;
+ }
+
+ // To suppress missing implicit constructor warnings.
+ factory SvgSvgElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ SvgSvgElement.created() : super.created();
+
+ num currentScale;
+
+ final Point currentTranslate;
+
+ final AnimatedLength height;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+
+ bool animationsPaused() native;
+
+ bool checkEnclosure(SvgElement element, Rect rect) native;
+
+ bool checkIntersection(SvgElement element, Rect rect) native;
+
+ @JSName('createSVGAngle')
+ Angle createSvgAngle() native;
+
+ @JSName('createSVGLength')
+ Length createSvgLength() native;
+
+ @JSName('createSVGMatrix')
+ Matrix createSvgMatrix() native;
+
+ @JSName('createSVGNumber')
+ Number createSvgNumber() native;
+
+ @JSName('createSVGPoint')
+ Point createSvgPoint() native;
+
+ @JSName('createSVGRect')
+ Rect createSvgRect() native;
+
+ @JSName('createSVGTransform')
+ Transform createSvgTransform() native;
+
+ @JSName('createSVGTransformFromMatrix')
+ Transform createSvgTransformFromMatrix(Matrix matrix) native;
+
+ void deselectAll() native;
+
+ void forceRedraw() native;
+
+ double getCurrentTime() native;
+
+ Element getElementById(String elementId) native;
+
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ List<Node> getEnclosureList(Rect rect, SvgElement referenceElement) native;
+
+ @Returns('NodeList|Null')
+ @Creates('NodeList')
+ List<Node> getIntersectionList(Rect rect, SvgElement referenceElement) native;
+
+ void pauseAnimations() native;
+
+ void setCurrentTime(num seconds) native;
+
+ int suspendRedraw(int maxWaitMilliseconds) native;
+
+ void unpauseAnimations() native;
+
+ void unsuspendRedraw(int suspendHandleId) native;
+
+ void unsuspendRedrawAll() native;
+
+ // From SVGFitToViewBox
+
+ final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+ final AnimatedRect viewBox;
+
+ // From SVGZoomAndPan
+
+ int zoomAndPan;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGSwitchElement")
+class SwitchElement extends GraphicsElement {
+ // To suppress missing implicit constructor warnings.
+ factory SwitchElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SwitchElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("switch");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ SwitchElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGSymbolElement")
+class SymbolElement extends SvgElement implements FitToViewBox {
+ // To suppress missing implicit constructor warnings.
+ factory SymbolElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory SymbolElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("symbol");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ SymbolElement.created() : super.created();
+
+ // From SVGFitToViewBox
+
+ final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+ final AnimatedRect viewBox;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTSpanElement")
+class TSpanElement extends TextPositioningElement {
+ // To suppress missing implicit constructor warnings.
+ factory TSpanElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TSpanElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("tspan");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TSpanElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+abstract class Tests extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Tests._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final StringList requiredExtensions;
+
+ final StringList systemLanguage;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTextContentElement")
+class TextContentElement extends GraphicsElement {
+ // To suppress missing implicit constructor warnings.
+ factory TextContentElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TextContentElement.created() : super.created();
+
+ static const int LENGTHADJUST_SPACING = 1;
+
+ static const int LENGTHADJUST_SPACINGANDGLYPHS = 2;
+
+ static const int LENGTHADJUST_UNKNOWN = 0;
+
+ final AnimatedEnumeration lengthAdjust;
+
+ final AnimatedLength textLength;
+
+ int getCharNumAtPosition(Point point) native;
+
+ double getComputedTextLength() native;
+
+ Point getEndPositionOfChar(int charnum) native;
+
+ Rect getExtentOfChar(int charnum) native;
+
+ int getNumberOfChars() native;
+
+ double getRotationOfChar(int charnum) native;
+
+ Point getStartPositionOfChar(int charnum) native;
+
+ double getSubStringLength(int charnum, int nchars) native;
+
+ void selectSubString(int charnum, int nchars) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTextElement")
+class TextElement extends TextPositioningElement {
+ // To suppress missing implicit constructor warnings.
+ factory TextElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TextElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("text");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TextElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTextPathElement")
+class TextPathElement extends TextContentElement implements UriReference {
+ // To suppress missing implicit constructor warnings.
+ factory TextPathElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TextPathElement.created() : super.created();
+
+ static const int TEXTPATH_METHODTYPE_ALIGN = 1;
+
+ static const int TEXTPATH_METHODTYPE_STRETCH = 2;
+
+ static const int TEXTPATH_METHODTYPE_UNKNOWN = 0;
+
+ static const int TEXTPATH_SPACINGTYPE_AUTO = 1;
+
+ static const int TEXTPATH_SPACINGTYPE_EXACT = 2;
+
+ static const int TEXTPATH_SPACINGTYPE_UNKNOWN = 0;
+
+ final AnimatedEnumeration method;
+
+ final AnimatedEnumeration spacing;
+
+ final AnimatedLength startOffset;
+
+ // From SVGURIReference
+
+ final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTextPositioningElement")
+class TextPositioningElement extends TextContentElement {
+ // To suppress missing implicit constructor warnings.
+ factory TextPositioningElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TextPositioningElement.created() : super.created();
+
+ final AnimatedLengthList dx;
+
+ final AnimatedLengthList dy;
+
+ final AnimatedNumberList rotate;
+
+ final AnimatedLengthList x;
+
+ final AnimatedLengthList y;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTitleElement")
+class TitleElement extends SvgElement {
+ // To suppress missing implicit constructor warnings.
+ factory TitleElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory TitleElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("title");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ TitleElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTransform")
+class Transform extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Transform._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int SVG_TRANSFORM_MATRIX = 1;
+
+ static const int SVG_TRANSFORM_ROTATE = 4;
+
+ static const int SVG_TRANSFORM_SCALE = 3;
+
+ static const int SVG_TRANSFORM_SKEWX = 5;
+
+ static const int SVG_TRANSFORM_SKEWY = 6;
+
+ static const int SVG_TRANSFORM_TRANSLATE = 2;
+
+ static const int SVG_TRANSFORM_UNKNOWN = 0;
+
+ final num angle;
+
+ final Matrix matrix;
+
+ final int type;
+
+ void setMatrix(Matrix matrix) native;
+
+ void setRotate(num angle, num cx, num cy) native;
+
+ void setScale(num sx, num sy) native;
+
+ void setSkewX(num angle) native;
+
+ void setSkewY(num angle) native;
+
+ void setTranslate(num tx, num ty) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGTransformList")
+class TransformList extends Interceptor
+ with ListMixin<Transform>, ImmutableListMixin<Transform>
+ implements List<Transform> {
+ // To suppress missing implicit constructor warnings.
+ factory TransformList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ final int numberOfItems;
+
+ Transform operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return this.getItem(index);
+ }
+
+ void operator []=(int index, Transform value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<Transform> mixins.
+ // Transform is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ Transform get first {
+ if (this.length > 0) {
+ return JS('Transform', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ Transform get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('Transform', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ Transform get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('Transform', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ Transform elementAt(int index) => this[index];
+ // -- end List<Transform> mixins.
+
+ void __setter__(int index, Transform newItem) native;
+
+ Transform appendItem(Transform newItem) native;
+
+ void clear() native;
+
+ Transform consolidate() native;
+
+ @JSName('createSVGTransformFromMatrix')
+ Transform createSvgTransformFromMatrix(Matrix matrix) native;
+
+ Transform getItem(int index) native;
+
+ Transform initialize(Transform newItem) native;
+
+ Transform insertItemBefore(Transform newItem, int index) native;
+
+ Transform removeItem(int index) native;
+
+ Transform replaceItem(Transform newItem, int index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGUnitTypes")
+class UnitTypes extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory UnitTypes._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int SVG_UNIT_TYPE_OBJECTBOUNDINGBOX = 2;
+
+ static const int SVG_UNIT_TYPE_UNKNOWN = 0;
+
+ static const int SVG_UNIT_TYPE_USERSPACEONUSE = 1;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+abstract class UriReference extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory UriReference._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGUseElement")
+class UseElement extends GraphicsElement implements UriReference {
+ // To suppress missing implicit constructor warnings.
+ factory UseElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory UseElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("use");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ UseElement.created() : super.created();
+
+ final AnimatedLength height;
+
+ final AnimatedLength width;
+
+ final AnimatedLength x;
+
+ final AnimatedLength y;
+
+ // From SVGURIReference
+
+ final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGViewElement")
+class ViewElement extends SvgElement implements FitToViewBox, ZoomAndPan {
+ // To suppress missing implicit constructor warnings.
+ factory ViewElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ViewElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("view");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ ViewElement.created() : super.created();
+
+ // From SVGFitToViewBox
+
+ final AnimatedPreserveAspectRatio preserveAspectRatio;
+
+ final AnimatedRect viewBox;
+
+ // From SVGZoomAndPan
+
+ int zoomAndPan;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+abstract class ZoomAndPan extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ZoomAndPan._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int SVG_ZOOMANDPAN_DISABLE = 1;
+
+ static const int SVG_ZOOMANDPAN_MAGNIFY = 2;
+
+ static const int SVG_ZOOMANDPAN_UNKNOWN = 0;
+
+ int zoomAndPan;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGGradientElement")
+class _GradientElement extends SvgElement implements UriReference {
+ // To suppress missing implicit constructor warnings.
+ factory _GradientElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ _GradientElement.created() : super.created();
+
+ static const int SVG_SPREADMETHOD_PAD = 1;
+
+ static const int SVG_SPREADMETHOD_REFLECT = 2;
+
+ static const int SVG_SPREADMETHOD_REPEAT = 3;
+
+ static const int SVG_SPREADMETHOD_UNKNOWN = 0;
+
+ final AnimatedTransformList gradientTransform;
+
+ final AnimatedEnumeration gradientUnits;
+
+ final AnimatedEnumeration spreadMethod;
+
+ // From SVGURIReference
+
+ final AnimatedString href;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("SVGComponentTransferFunctionElement")
+abstract class _SVGComponentTransferFunctionElement extends SvgElement {
+ // To suppress missing implicit constructor warnings.
+ factory _SVGComponentTransferFunctionElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ _SVGComponentTransferFunctionElement.created() : super.created();
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SVGFEDropShadowElement")
+abstract class _SVGFEDropShadowElement extends SvgElement
+ implements FilterPrimitiveStandardAttributes {
+ // To suppress missing implicit constructor warnings.
+ factory _SVGFEDropShadowElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ _SVGFEDropShadowElement.created() : super.created();
+
+ // From SVGFilterPrimitiveStandardAttributes
+
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SVGMPathElement")
+abstract class _SVGMPathElement extends SvgElement implements UriReference {
+ // To suppress missing implicit constructor warnings.
+ factory _SVGMPathElement._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory _SVGMPathElement() =>
+ _SvgElementFactoryProvider.createSvgElement_tag("mpath");
+ /**
+ * Constructor instantiated by the DOM when a custom element has been created.
+ *
+ * This can only be called by subclasses from their created constructor.
+ */
+ _SVGMPathElement.created() : super.created();
+
+ // From SVGURIReference
+
+}
diff --git a/sdk_nnbd/lib/typed_data/typed_data.dart b/sdk_nnbd/lib/typed_data/typed_data.dart
new file mode 100644
index 0000000..89c9496
--- /dev/null
+++ b/sdk_nnbd/lib/typed_data/typed_data.dart
@@ -0,0 +1,2596 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Lists that efficiently handle fixed sized data
+/// (for example, unsigned 8 byte integers) and SIMD numeric types.
+///
+/// To use this library in your code:
+///
+/// import 'dart:typed_data';
+///
+/// {@category Core}
+library dart.typed_data;
+
+import "dart:_internal" show UnmodifiableListBase;
+
+part "unmodifiable_typed_data.dart";
+
+/**
+ * A sequence of bytes underlying a typed data object.
+ *
+ * Used to process large quantities of binary or numerical data
+ * more efficiently using a typed view.
+ */
+abstract class ByteBuffer {
+ /**
+ * Returns the length of this byte buffer, in bytes.
+ */
+ int get lengthInBytes;
+
+ /**
+ * Creates a [Uint8List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Uint8List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes] and contains [length] bytes.
+ * If [length] is omitted, the range extends to the end of the buffer.
+ *
+ * The start index and length must describe a valid range of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length` must not be greater than [lengthInBytes].
+ */
+ Uint8List asUint8List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Int8List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Int8List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes] and contains [length] bytes.
+ * If [length] is omitted, the range extends to the end of the buffer.
+ *
+ * The start index and length must describe a valid range of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length` must not be greater than [lengthInBytes].
+ */
+ Int8List asInt8List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Uint8ClampedList] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Uint8ClampedList` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes] and contains [length] bytes.
+ * If [length] is omitted, the range extends to the end of the buffer.
+ *
+ * The start index and length must describe a valid range of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length` must not be greater than [lengthInBytes].
+ */
+ Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Uint16List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Uint16List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes], which must be 16-bit aligned,
+ * and contains [length] 16-bit integers.
+ * If [length] is omitted, the range extends as far towards the end of
+ * the buffer as possible -
+ * if [lengthInBytes] is not even, the last byte can't be part of the view.
+ *
+ * The start index and length must describe a valid 16-bit aligned range
+ * of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `offsetInBytes` must be divisible by two,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length * 2` must not be greater than [lengthInBytes].
+ */
+ Uint16List asUint16List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Int16List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Int16List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes], which must be 16-bit aligned,
+ * and contains [length] 16-bit integers.
+ * If [length] is omitted, the range extends as far towards the end of
+ * the buffer as possible -
+ * if [lengthInBytes] is not even, the last byte can't be part of the view.
+ *
+ * The start index and length must describe a valid 16-bit aligned range
+ * of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `offsetInBytes` must be divisible by two,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length * 2` must not be greater than [lengthInBytes].
+ */
+ Int16List asInt16List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Uint32List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Uint32List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes], which must be 32-bit aligned,
+ * and contains [length] 32-bit integers.
+ * If [length] is omitted, the range extends as far towards the end of
+ * the buffer as possible -
+ * if [lengthInBytes] is not divisible by four, the last bytes can't be part
+ * of the view.
+ *
+ * The start index and length must describe a valid 32-bit aligned range
+ * of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `offsetInBytes` must be divisible by four,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length * 4` must not be greater than [lengthInBytes].
+ */
+ Uint32List asUint32List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Int32List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Int32List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes], which must be 32-bit aligned,
+ * and contains [length] 32-bit integers.
+ * If [length] is omitted, the range extends as far towards the end of
+ * the buffer as possible -
+ * if [lengthInBytes] is not divisible by four, the last bytes can't be part
+ * of the view.
+ *
+ * The start index and length must describe a valid 32-bit aligned range
+ * of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `offsetInBytes` must be divisible by four,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length * 4` must not be greater than [lengthInBytes].
+ */
+ Int32List asInt32List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Uint64List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Uint64List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes], which must be 64-bit aligned,
+ * and contains [length] 64-bit integers.
+ * If [length] is omitted, the range extends as far towards the end of
+ * the buffer as possible -
+ * if [lengthInBytes] is not divisible by eight, the last bytes can't be part
+ * of the view.
+ *
+ * The start index and length must describe a valid 64-bit aligned range
+ * of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `offsetInBytes` must be divisible by eight,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length * 8` must not be greater than [lengthInBytes].
+ */
+ Uint64List asUint64List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Int64List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Int64List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes], which must be 64-bit aligned,
+ * and contains [length] 64-bit integers.
+ * If [length] is omitted, the range extends as far towards the end of
+ * the buffer as possible -
+ * if [lengthInBytes] is not divisible by eight, the last bytes can't be part
+ * of the view.
+ *
+ * The start index and length must describe a valid 64-bit aligned range
+ * of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `offsetInBytes` must be divisible by eight,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length * 8` must not be greater than [lengthInBytes].
+ */
+ Int64List asInt64List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Int32x4List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Int32x4List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes], which must be 128-bit aligned,
+ * and contains [length] 128-bit integers.
+ * If [length] is omitted, the range extends as far towards the end of
+ * the buffer as possible -
+ * if [lengthInBytes] is not divisible by 16, the last bytes can't be part
+ * of the view.
+ *
+ * The start index and length must describe a valid 128-bit aligned range
+ * of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `offsetInBytes` must be divisible by sixteen,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length * 16` must not be greater than [lengthInBytes].
+ */
+ Int32x4List asInt32x4List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Float32List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Float32List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes], which must be 32-bit aligned,
+ * and contains [length] 32-bit integers.
+ * If [length] is omitted, the range extends as far towards the end of
+ * the buffer as possible -
+ * if [lengthInBytes] is not divisible by four, the last bytes can't be part
+ * of the view.
+ *
+ * The start index and length must describe a valid 32-bit aligned range
+ * of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `offsetInBytes` must be divisible by four,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length * 4` must not be greater than [lengthInBytes].
+ */
+ Float32List asFloat32List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Float64List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Float64List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes], which must be 64-bit aligned,
+ * and contains [length] 64-bit integers.
+ * If [length] is omitted, the range extends as far towards the end of
+ * the buffer as possible -
+ * if [lengthInBytes] is not divisible by eight, the last bytes can't be part
+ * of the view.
+ *
+ * The start index and length must describe a valid 64-bit aligned range
+ * of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `offsetInBytes` must be divisible by eight,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length * 8` must not be greater than [lengthInBytes].
+ */
+ Float64List asFloat64List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Float32x4List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Float32x4List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes], which must be 128-bit aligned,
+ * and contains [length] 128-bit integers.
+ * If [length] is omitted, the range extends as far towards the end of
+ * the buffer as possible -
+ * if [lengthInBytes] is not divisible by 16, the last bytes can't be part
+ * of the view.
+ *
+ * The start index and length must describe a valid 128-bit aligned range
+ * of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `offsetInBytes` must be divisible by sixteen,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length * 16` must not be greater than [lengthInBytes].
+ */
+ Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [Float64x2List] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `Float64x2List` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes], which must be 128-bit aligned,
+ * and contains [length] 128-bit integers.
+ * If [length] is omitted, the range extends as far towards the end of
+ * the buffer as possible -
+ * if [lengthInBytes] is not divisible by 16, the last bytes can't be part
+ * of the view.
+ *
+ * The start index and length must describe a valid 128-bit aligned range
+ * of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `offsetInBytes` must be divisible by sixteen,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length * 16` must not be greater than [lengthInBytes].
+ */
+ Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]);
+
+ /**
+ * Creates a [ByteData] _view_ of a region of this byte buffer.
+ *
+ * The view is backed by the bytes of this byte buffer.
+ * Any changes made to the `ByteData` will also change the buffer,
+ * and vice versa.
+ *
+ * The viewed region start at [offsetInBytes] and contains [length] bytes.
+ * If [length] is omitted, the range extends to the end of the buffer.
+ *
+ * The start index and length must describe a valid range of the buffer:
+ *
+ * * `offsetInBytes` must not be negative,
+ * * `length` must not be negative, and
+ * * `offsetInBytes + length` must not be greater than [lengthInBytes].
+ */
+ ByteData asByteData([int offsetInBytes = 0, int length]);
+}
+
+/**
+ * A typed view of a sequence of bytes.
+ */
+abstract class TypedData {
+ /**
+ * Returns the number of bytes in the representation of each element in this
+ * list.
+ */
+ int get elementSizeInBytes;
+
+ /**
+ * Returns the offset in bytes into the underlying byte buffer of this view.
+ */
+ int get offsetInBytes;
+
+ /**
+ * Returns the length of this view, in bytes.
+ */
+ int get lengthInBytes;
+
+ /**
+ * Returns the byte buffer associated with this object.
+ */
+ ByteBuffer get buffer;
+}
+
+abstract class _TypedIntList extends TypedData {
+ /**
+ * Returns the concatenation of this list and [other].
+ *
+ * If other is also a typed-data integer list, the returned list will
+ * be a type-data integer list capable of containing all the elements of
+ * this list and of [other].
+ * Otherwise the returned list will be a normal growable `List<int>`.
+ */
+ List<int> operator +(List<int> other);
+}
+
+abstract class _TypedFloatList extends TypedData {
+ /**
+ * Returns the concatenation of this list and [other].
+ *
+ * If other is also a typed-data floating point number list,
+ * the returned list will be a type-data float list capable of containing
+ * all the elements of this list and of [other].
+ * Otherwise the returned list will be a normal growable `List<double>`.
+ */
+ List<double> operator +(List<double> other);
+}
+
+/**
+ * Describes endianness to be used when accessing or updating a
+ * sequence of bytes.
+ */
+class Endian {
+ final bool _littleEndian;
+ const Endian._(this._littleEndian);
+
+ static const Endian big = const Endian._(false);
+ static const Endian little = const Endian._(true);
+ static final Endian host =
+ (new ByteData.view(new Uint16List.fromList([1]).buffer)).getInt8(0) == 1
+ ? little
+ : big;
+}
+
+/**
+ * A fixed-length, random-access sequence of bytes that also provides random
+ * and unaligned access to the fixed-width integers and floating point
+ * numbers represented by those bytes.
+ *
+ * `ByteData` may be used to pack and unpack data from external sources
+ * (such as networks or files systems), and to process large quantities
+ * of numerical data more efficiently than would be possible
+ * with ordinary [List] implementations.
+ * `ByteData` can save space, by eliminating the need for object headers,
+ * and time, by eliminating the need for data copies.
+ * Finally, `ByteData` may be used to intentionally reinterpret the bytes
+ * representing one arithmetic type as another.
+ * For example this code fragment determine what 32-bit signed integer
+ * is represented by the bytes of a 32-bit floating point number:
+ *
+ * var buffer = new Uint8List(8).buffer;
+ * var bdata = new ByteData.view(buffer);
+ * bdata.setFloat32(0, 3.04);
+ * int huh = bdata.getInt32(0);
+ */
+abstract class ByteData implements TypedData {
+ /**
+ * Creates a [ByteData] of the specified length (in elements), all of
+ * whose bytes are initially zero.
+ */
+ @pragma("vm:entry-point")
+ external factory ByteData(int length);
+
+ /**
+ * Creates an [ByteData] _view_ of the specified region in [buffer].
+ *
+ * Changes in the [ByteData] will be visible in the byte
+ * buffer and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ */
+ factory ByteData.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asByteData(offsetInBytes, length);
+ }
+
+ /**
+ * Returns the (possibly negative) integer represented by the byte at the
+ * specified [byteOffset] in this object, in two's complement binary
+ * representation.
+ *
+ * The return value will be between -128 and 127, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * greater than or equal to the length of this object.
+ */
+ int getInt8(int byteOffset);
+
+ /**
+ * Sets the byte at the specified [byteOffset] in this object to the
+ * two's complement binary representation of the specified [value], which
+ * must fit in a single byte.
+ *
+ * In other words, [value] must be between -128 and 127, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * greater than or equal to the length of this object.
+ */
+ void setInt8(int byteOffset, int value);
+
+ /**
+ * Returns the positive integer represented by the byte at the specified
+ * [byteOffset] in this object, in unsigned binary form.
+ *
+ * The return value will be between 0 and 255, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * greater than or equal to the length of this object.
+ */
+ int getUint8(int byteOffset);
+
+ /**
+ * Sets the byte at the specified [byteOffset] in this object to the
+ * unsigned binary representation of the specified [value], which must fit
+ * in a single byte.
+ *
+ * In other words, [value] must be between 0 and 255, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative,
+ * or greater than or equal to the length of this object.
+ */
+ void setUint8(int byteOffset, int value);
+
+ /**
+ * Returns the (possibly negative) integer represented by the two bytes at
+ * the specified [byteOffset] in this object, in two's complement binary
+ * form.
+ *
+ * The return value will be between -2<sup>15</sup> and 2<sup>15</sup> - 1,
+ * inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 2` is greater than the length of this object.
+ */
+ int getInt16(int byteOffset, [Endian endian = Endian.big]);
+
+ /**
+ * Sets the two bytes starting at the specified [byteOffset] in this
+ * object to the two's complement binary representation of the specified
+ * [value], which must fit in two bytes.
+ *
+ * In other words, [value] must lie
+ * between -2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 2` is greater than the length of this object.
+ */
+ void setInt16(int byteOffset, int value, [Endian endian = Endian.big]);
+
+ /**
+ * Returns the positive integer represented by the two bytes starting
+ * at the specified [byteOffset] in this object, in unsigned binary
+ * form.
+ *
+ * The return value will be between 0 and 2<sup>16</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 2` is greater than the length of this object.
+ */
+ int getUint16(int byteOffset, [Endian endian = Endian.big]);
+
+ /**
+ * Sets the two bytes starting at the specified [byteOffset] in this object
+ * to the unsigned binary representation of the specified [value],
+ * which must fit in two bytes.
+ *
+ * In other words, [value] must be between
+ * 0 and 2<sup>16</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 2` is greater than the length of this object.
+ */
+ void setUint16(int byteOffset, int value, [Endian endian = Endian.big]);
+
+ /**
+ * Returns the (possibly negative) integer represented by the four bytes at
+ * the specified [byteOffset] in this object, in two's complement binary
+ * form.
+ *
+ * The return value will be between -2<sup>31</sup> and 2<sup>31</sup> - 1,
+ * inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 4` is greater than the length of this object.
+ */
+ int getInt32(int byteOffset, [Endian endian = Endian.big]);
+
+ /**
+ * Sets the four bytes starting at the specified [byteOffset] in this
+ * object to the two's complement binary representation of the specified
+ * [value], which must fit in four bytes.
+ *
+ * In other words, [value] must lie
+ * between -2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 4` is greater than the length of this object.
+ */
+ void setInt32(int byteOffset, int value, [Endian endian = Endian.big]);
+
+ /**
+ * Returns the positive integer represented by the four bytes starting
+ * at the specified [byteOffset] in this object, in unsigned binary
+ * form.
+ *
+ * The return value will be between 0 and 2<sup>32</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 4` is greater than the length of this object.
+ */
+ int getUint32(int byteOffset, [Endian endian = Endian.big]);
+
+ /**
+ * Sets the four bytes starting at the specified [byteOffset] in this object
+ * to the unsigned binary representation of the specified [value],
+ * which must fit in four bytes.
+ *
+ * In other words, [value] must be between
+ * 0 and 2<sup>32</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 4` is greater than the length of this object.
+ */
+ void setUint32(int byteOffset, int value, [Endian endian = Endian.big]);
+
+ /**
+ * Returns the (possibly negative) integer represented by the eight bytes at
+ * the specified [byteOffset] in this object, in two's complement binary
+ * form.
+ *
+ * The return value will be between -2<sup>63</sup> and 2<sup>63</sup> - 1,
+ * inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 8` is greater than the length of this object.
+ */
+ int getInt64(int byteOffset, [Endian endian = Endian.big]);
+
+ /**
+ * Sets the eight bytes starting at the specified [byteOffset] in this
+ * object to the two's complement binary representation of the specified
+ * [value], which must fit in eight bytes.
+ *
+ * In other words, [value] must lie
+ * between -2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 8` is greater than the length of this object.
+ */
+ void setInt64(int byteOffset, int value, [Endian endian = Endian.big]);
+
+ /**
+ * Returns the positive integer represented by the eight bytes starting
+ * at the specified [byteOffset] in this object, in unsigned binary
+ * form.
+ *
+ * The return value will be between 0 and 2<sup>64</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 8` is greater than the length of this object.
+ */
+ int getUint64(int byteOffset, [Endian endian = Endian.big]);
+
+ /**
+ * Sets the eight bytes starting at the specified [byteOffset] in this object
+ * to the unsigned binary representation of the specified [value],
+ * which must fit in eight bytes.
+ *
+ * In other words, [value] must be between
+ * 0 and 2<sup>64</sup> - 1, inclusive.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 8` is greater than the length of this object.
+ */
+ void setUint64(int byteOffset, int value, [Endian endian = Endian.big]);
+
+ /**
+ * Returns the floating point number represented by the four bytes at
+ * the specified [byteOffset] in this object, in IEEE 754
+ * single-precision binary floating-point format (binary32).
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 4` is greater than the length of this object.
+ */
+ double getFloat32(int byteOffset, [Endian endian = Endian.big]);
+
+ /**
+ * Sets the four bytes starting at the specified [byteOffset] in this
+ * object to the IEEE 754 single-precision binary floating-point
+ * (binary32) representation of the specified [value].
+ *
+ * **Note that this method can lose precision.** The input [value] is
+ * a 64-bit floating point value, which will be converted to 32-bit
+ * floating point value by IEEE 754 rounding rules before it is stored.
+ * If [value] cannot be represented exactly as a binary32, it will be
+ * converted to the nearest binary32 value. If two binary32 values are
+ * equally close, the one whose least significant bit is zero will be used.
+ * Note that finite (but large) values can be converted to infinity, and
+ * small non-zero values can be converted to zero.
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 4` is greater than the length of this object.
+ */
+ void setFloat32(int byteOffset, double value, [Endian endian = Endian.big]);
+
+ /**
+ * Returns the floating point number represented by the eight bytes at
+ * the specified [byteOffset] in this object, in IEEE 754
+ * double-precision binary floating-point format (binary64).
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 8` is greater than the length of this object.
+ */
+ double getFloat64(int byteOffset, [Endian endian = Endian.big]);
+
+ /**
+ * Sets the eight bytes starting at the specified [byteOffset] in this
+ * object to the IEEE 754 double-precision binary floating-point
+ * (binary64) representation of the specified [value].
+ *
+ * Throws [RangeError] if [byteOffset] is negative, or
+ * `byteOffset + 8` is greater than the length of this object.
+ */
+ void setFloat64(int byteOffset, double value, [Endian endian = Endian.big]);
+}
+
+/**
+ * A fixed-length list of 8-bit signed integers.
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low eight bits,
+ * interpreted as a signed 8-bit two's complement integer with values in the
+ * range -128 to +127.
+ */
+abstract class Int8List implements List<int>, _TypedIntList {
+ /**
+ * Creates an [Int8List] of the specified length (in elements), all of
+ * whose elements are initially zero.
+ */
+ external factory Int8List(int length);
+
+ /**
+ * Creates a [Int8List] with the same length as the [elements] list
+ * and copies over the elements.
+ *
+ * Values are truncated to fit in the list when they are copied,
+ * the same way storing values truncates them.
+ */
+ external factory Int8List.fromList(List<int> elements);
+
+ /**
+ * Creates an [Int8List] _view_ of the specified region in [buffer].
+ *
+ * Changes in the [Int8List] will be visible in the byte
+ * buffer and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ */
+ factory Int8List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asInt8List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is an `Int8List` containing the elements of this list at
+ * positions greater than or equal to [start] and less than [end] in the same
+ * order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Int8List.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Int8List
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Int8List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 1;
+}
+
+/**
+ * A fixed-length list of 8-bit unsigned integers.
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low eight bits,
+ * interpreted as an unsigned 8-bit integer with values in the
+ * range 0 to 255.
+ */
+abstract class Uint8List implements List<int>, _TypedIntList {
+ /**
+ * Creates a [Uint8List] of the specified length (in elements), all of
+ * whose elements are initially zero.
+ */
+ external factory Uint8List(int length);
+
+ /**
+ * Creates a [Uint8List] with the same length as the [elements] list
+ * and copies over the elements.
+ *
+ * Values are truncated to fit in the list when they are copied,
+ * the same way storing values truncates them.
+ */
+ external factory Uint8List.fromList(List<int> elements);
+
+ /**
+ * Creates a [Uint8List] _view_ of the specified region in [buffer].
+ *
+ * Changes in the [Uint8List] will be visible in the byte
+ * buffer and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ */
+ factory Uint8List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asUint8List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns a concatenation of this list and [other].
+ *
+ * If [other] is also a typed-data list, then the return list will be a
+ * typed data list capable of holding both unsigned 8-bit integers and
+ * the elements of [other], otherwise it'll be a normal list of integers.
+ */
+ List<int> operator +(List<int> other);
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is a `Uint8List` containing the elements of this list at
+ * positions greater than or equal to [start] and less than [end] in the same
+ * order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Uint8List.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Uint8List
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Uint8List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 1;
+}
+
+/**
+ * A fixed-length list of 8-bit unsigned integers.
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are clamped to an unsigned eight bit value.
+ * That is, all values below zero are stored as zero
+ * and all values above 255 are stored as 255.
+ */
+abstract class Uint8ClampedList implements List<int>, _TypedIntList {
+ /**
+ * Creates a [Uint8ClampedList] of the specified length (in elements), all of
+ * whose elements are initially zero.
+ */
+ external factory Uint8ClampedList(int length);
+
+ /**
+ * Creates a [Uint8ClampedList] of the same size as the [elements]
+ * list and copies over the values clamping when needed.
+ *
+ * Values are clamped to fit in the list when they are copied,
+ * the same way storing values clamps them.
+ */
+ external factory Uint8ClampedList.fromList(List<int> elements);
+
+ /**
+ * Creates a [Uint8ClampedList] _view_ of the specified region in the
+ * specified byte [buffer].
+ *
+ * Changes in the [Uint8List] will be visible in the byte buffer
+ * and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ */
+ factory Uint8ClampedList.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asUint8ClampedList(offsetInBytes, length);
+ }
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is a `Uint8ClampedList` containing the elements of this
+ * list at positions greater than or equal to [start] and less than [end] in
+ * the same order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Uint8ClampedList.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Uint8ClampedList
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Uint8ClampedList sublist(int start, [int end]);
+
+ static const int bytesPerElement = 1;
+}
+
+/**
+ * A fixed-length list of 16-bit signed integers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low 16 bits,
+ * interpreted as a signed 16-bit two's complement integer with values in the
+ * range -32768 to +32767.
+ */
+abstract class Int16List implements List<int>, _TypedIntList {
+ /**
+ * Creates an [Int16List] of the specified length (in elements), all of
+ * whose elements are initially zero.
+ */
+ external factory Int16List(int length);
+
+ /**
+ * Creates a [Int16List] with the same length as the [elements] list
+ * and copies over the elements.
+ *
+ * Values are truncated to fit in the list when they are copied,
+ * the same way storing values truncates them.
+ */
+ external factory Int16List.fromList(List<int> elements);
+
+ /**
+ * Creates an [Int16List] _view_ of the specified region in [buffer].
+ *
+ * Changes in the [Int16List] will be visible in the byte
+ * buffer and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * [bytesPerElement].
+ */
+ factory Int16List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asInt16List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is an `Int16List` containing the elements of this
+ * list at positions greater than or equal to [start] and less than [end] in
+ * the same order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Int16List.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Int16List
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Int16List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 2;
+}
+
+/**
+ * A fixed-length list of 16-bit unsigned integers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low 16 bits,
+ * interpreted as an unsigned 16-bit integer with values in the
+ * range 0 to 65535.
+ */
+abstract class Uint16List implements List<int>, _TypedIntList {
+ /**
+ * Creates a [Uint16List] of the specified length (in elements), all
+ * of whose elements are initially zero.
+ */
+ external factory Uint16List(int length);
+
+ /**
+ * Creates a [Uint16List] with the same length as the [elements] list
+ * and copies over the elements.
+ *
+ * Values are truncated to fit in the list when they are copied,
+ * the same way storing values truncates them.
+ */
+ external factory Uint16List.fromList(List<int> elements);
+
+ /**
+ * Creates a [Uint16List] _view_ of the specified region in
+ * the specified byte buffer.
+ *
+ * Changes in the [Uint16List] will be visible in the byte buffer
+ * and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * [bytesPerElement].
+ */
+ factory Uint16List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asUint16List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is a `Uint16List` containing the elements of this
+ * list at positions greater than or equal to [start] and less than [end] in
+ * the same order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Uint16List.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Uint16List
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Uint16List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 2;
+}
+
+/**
+ * A fixed-length list of 32-bit signed integers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low 32 bits,
+ * interpreted as a signed 32-bit two's complement integer with values in the
+ * range -2147483648 to 2147483647.
+ */
+abstract class Int32List implements List<int>, _TypedIntList {
+ /**
+ * Creates an [Int32List] of the specified length (in elements), all of
+ * whose elements are initially zero.
+ */
+ external factory Int32List(int length);
+
+ /**
+ * Creates a [Int32List] with the same length as the [elements] list
+ * and copies over the elements.
+ *
+ * Values are truncated to fit in the list when they are copied,
+ * the same way storing values truncates them.
+ */
+ external factory Int32List.fromList(List<int> elements);
+
+ /**
+ * Creates an [Int32List] _view_ of the specified region in [buffer].
+ *
+ * Changes in the [Int32List] will be visible in the byte
+ * buffer and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * [bytesPerElement].
+ */
+ factory Int32List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asInt32List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is an `Int32List` containing the elements of this
+ * list at positions greater than or equal to [start] and less than [end] in
+ * the same order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Int32List.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Int32List
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Int32List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 4;
+}
+
+/**
+ * A fixed-length list of 32-bit unsigned integers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low 32 bits,
+ * interpreted as an unsigned 32-bit integer with values in the
+ * range 0 to 4294967295.
+ */
+abstract class Uint32List implements List<int>, _TypedIntList {
+ /**
+ * Creates a [Uint32List] of the specified length (in elements), all
+ * of whose elements are initially zero.
+ */
+ external factory Uint32List(int length);
+
+ /**
+ * Creates a [Uint32List] with the same length as the [elements] list
+ * and copies over the elements.
+ *
+ * Values are truncated to fit in the list when they are copied,
+ * the same way storing values truncates them.
+ */
+ external factory Uint32List.fromList(List<int> elements);
+
+ /**
+ * Creates a [Uint32List] _view_ of the specified region in
+ * the specified byte buffer.
+ *
+ * Changes in the [Uint32List] will be visible in the byte buffer
+ * and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * [bytesPerElement].
+ */
+ factory Uint32List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asUint32List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is a `Uint32List` containing the elements of this
+ * list at positions greater than or equal to [start] and less than [end] in
+ * the same order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Uint32List.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Uint32List
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Uint32List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 4;
+}
+
+/**
+ * A fixed-length list of 64-bit signed integers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low 64 bits,
+ * interpreted as a signed 64-bit two's complement integer with values in the
+ * range -9223372036854775808 to +9223372036854775807.
+ */
+abstract class Int64List implements List<int>, _TypedIntList {
+ /**
+ * Creates an [Int64List] of the specified length (in elements), all of
+ * whose elements are initially zero.
+ */
+ external factory Int64List(int length);
+
+ /**
+ * Creates a [Int64List] with the same length as the [elements] list
+ * and copies over the elements.
+ *
+ * Values are truncated to fit in the list when they are copied,
+ * the same way storing values truncates them.
+ */
+ external factory Int64List.fromList(List<int> elements);
+
+ /**
+ * Creates an [Int64List] _view_ of the specified region in [buffer].
+ *
+ * Changes in the [Int64List] will be visible in the byte buffer
+ * and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * [bytesPerElement].
+ */
+ factory Int64List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asInt64List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is an `Int64List` containing the elements of this
+ * list at positions greater than or equal to [start] and less than [end] in
+ * the same order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Int64List.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Int64List
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Int64List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 8;
+}
+
+/**
+ * A fixed-length list of 64-bit unsigned integers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation can be considerably
+ * more space- and time-efficient than the default [List] implementation.
+ *
+ * Integers stored in the list are truncated to their low 64 bits,
+ * interpreted as an unsigned 64-bit integer with values in the
+ * range 0 to 18446744073709551615.
+ */
+abstract class Uint64List implements List<int>, _TypedIntList {
+ /**
+ * Creates a [Uint64List] of the specified length (in elements), all
+ * of whose elements are initially zero.
+ */
+ external factory Uint64List(int length);
+
+ /**
+ * Creates a [Uint64List] with the same length as the [elements] list
+ * and copies over the elements.
+ *
+ * Values are truncated to fit in the list when they are copied,
+ * the same way storing values truncates them.
+ */
+ external factory Uint64List.fromList(List<int> elements);
+
+ /**
+ * Creates an [Uint64List] _view_ of the specified region in
+ * the specified byte buffer.
+ *
+ * Changes in the [Uint64List] will be visible in the byte buffer
+ * and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * [bytesPerElement].
+ */
+ factory Uint64List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asUint64List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is a `Uint64List` containing the elements of this
+ * list at positions greater than or equal to [start] and less than [end] in
+ * the same order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Uint64List.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Uint64List
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Uint64List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 8;
+}
+
+/**
+ * A fixed-length list of IEEE 754 single-precision binary floating-point
+ * numbers that is viewable as a [TypedData].
+ *
+ * For long lists, this
+ * implementation can be considerably more space- and time-efficient than
+ * the default [List] implementation.
+ *
+ * Double values stored in the list are converted to the nearest
+ * single-precision value. Values read are converted to a double
+ * value with the same value.
+ */
+abstract class Float32List implements List<double>, _TypedFloatList {
+ /**
+ * Creates a [Float32List] of the specified length (in elements), all of
+ * whose elements are initially zero.
+ */
+ external factory Float32List(int length);
+
+ /**
+ * Creates a [Float32List] with the same length as the [elements] list
+ * and copies over the elements.
+ *
+ * Values are truncated to fit in the list when they are copied,
+ * the same way storing values truncates them.
+ */
+ external factory Float32List.fromList(List<double> elements);
+
+ /**
+ * Creates a [Float32List] _view_ of the specified region in [buffer].
+ *
+ * Changes in the [Float32List] will be visible in the byte
+ * buffer and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * [bytesPerElement].
+ */
+ factory Float32List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asFloat32List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is a `Float32List` containing the elements of this
+ * list at positions greater than or equal to [start] and less than [end] in
+ * the same order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Float32List.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Float32List
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Float32List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 4;
+}
+
+/**
+ * A fixed-length list of IEEE 754 double-precision binary floating-point
+ * numbers that is viewable as a [TypedData].
+ *
+ * For long lists, this
+ * implementation can be considerably more space- and time-efficient than
+ * the default [List] implementation.
+ */
+abstract class Float64List implements List<double>, _TypedFloatList {
+ /**
+ * Creates a [Float64List] of the specified length (in elements), all of
+ * whose elements are initially zero.
+ */
+ external factory Float64List(int length);
+
+ /**
+ * Creates a [Float64List] with the same length as the [elements] list
+ * and copies over the elements.
+ */
+ external factory Float64List.fromList(List<double> elements);
+
+ /**
+ * Creates a [Float64List] _view_ of the specified region in [buffer].
+ *
+ * Changes in the [Float64List] will be visible in the byte
+ * buffer and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * [bytesPerElement].
+ */
+ factory Float64List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asFloat64List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is a `Float64List` containing the elements of this
+ * list at positions greater than or equal to [start] and less than [end] in
+ * the same order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Float64List.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Float64List
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Float64List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 8;
+}
+
+/**
+ * A fixed-length list of Float32x4 numbers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+abstract class Float32x4List implements List<Float32x4>, TypedData {
+ /**
+ * Creates a [Float32x4List] of the specified length (in elements),
+ * all of whose elements are initially zero.
+ */
+ external factory Float32x4List(int length);
+
+ /**
+ * Creates a [Float32x4List] with the same length as the [elements] list
+ * and copies over the elements.
+ */
+ external factory Float32x4List.fromList(List<Float32x4> elements);
+
+ /**
+ * Creates a [Float32x4List] _view_ of the specified region in [buffer].
+ *
+ * Changes in the [Float32x4List] will be visible in the byte
+ * buffer and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * [bytesPerElement].
+ */
+ factory Float32x4List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asFloat32x4List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns the concatenation of this list and [other].
+ *
+ * If [other] is also a [Float32x4List], the result is a new [Float32x4List],
+ * otherwise the result is a normal growable `List<Float32x4>`.
+ */
+ List<Float32x4> operator +(List<Float32x4> other);
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is a `Float32x4List` containing the elements of this
+ * list at positions greater than or equal to [start] and less than [end] in
+ * the same order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Float32x4List.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Float32x4List
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Float32x4List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 16;
+}
+
+/**
+ * A fixed-length list of Int32x4 numbers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+abstract class Int32x4List implements List<Int32x4>, TypedData {
+ /**
+ * Creates a [Int32x4List] of the specified length (in elements),
+ * all of whose elements are initially zero.
+ */
+ external factory Int32x4List(int length);
+
+ /**
+ * Creates a [Int32x4List] with the same length as the [elements] list
+ * and copies over the elements.
+ */
+ external factory Int32x4List.fromList(List<Int32x4> elements);
+
+ /**
+ * Creates a [Int32x4List] _view_ of the specified region in [buffer].
+ *
+ * Changes in the [Int32x4List] will be visible in the byte
+ * buffer and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * [bytesPerElement].
+ */
+ factory Int32x4List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asInt32x4List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns the concatenation of this list and [other].
+ *
+ * If [other] is also a [Int32x4List], the result is a new [Int32x4List],
+ * otherwise the result is a normal growable `List<Int32x4>`.
+ */
+ List<Int32x4> operator +(List<Int32x4> other);
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is an `Int32x4list` containing the elements of this
+ * list at positions greater than or equal to [start] and less than [end] in
+ * the same order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Int32x4list.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Int32x4list
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Int32x4List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 16;
+}
+
+/**
+ * A fixed-length list of Float64x2 numbers that is viewable as a
+ * [TypedData].
+ *
+ * For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+abstract class Float64x2List implements List<Float64x2>, TypedData {
+ /**
+ * Creates a [Float64x2List] of the specified length (in elements),
+ * all of whose elements have all lanes set to zero.
+ */
+ external factory Float64x2List(int length);
+
+ /**
+ * Creates a [Float64x2List] with the same length as the [elements] list
+ * and copies over the elements.
+ */
+ external factory Float64x2List.fromList(List<Float64x2> elements);
+
+ /**
+ * Returns the concatenation of this list and [other].
+ *
+ * If [other] is also a [Float64x2List], the result is a new [Float64x2List],
+ * otherwise the result is a normal growable `List<Float64x2>`.
+ */
+ List<Float64x2> operator +(List<Float64x2> other);
+
+ /**
+ * Creates a [Float64x2List] _view_ of the specified region in [buffer].
+ *
+ * Changes in the [Float64x2List] will be visible in the byte
+ * buffer and vice versa.
+ * If the [offsetInBytes] index of the region is not specified,
+ * it defaults to zero (the first byte in the byte buffer).
+ * If the length is not specified, it defaults to `null`,
+ * which indicates that the view extends to the end of the byte buffer.
+ *
+ * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+ * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+ * the length of [buffer].
+ *
+ * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+ * [bytesPerElement].
+ */
+ factory Float64x2List.view(ByteBuffer buffer,
+ [int offsetInBytes = 0, int length]) {
+ return buffer.asFloat64x2List(offsetInBytes, length);
+ }
+
+ /**
+ * Returns a new list containing the elements between [start] and [end].
+ *
+ * The new list is a `Float64x2List` containing the elements of this
+ * list at positions greater than or equal to [start] and less than [end] in
+ * the same order as they occur in this list.
+ *
+ * ```dart
+ * var numbers = Float64x2List.fromList([0, 1, 2, 3, 4]);
+ * print(numbers.sublist(1, 3)); // [1, 2]
+ * print(numbers.sublist(1, 3).runtimeType); // Float64x2List
+ * ```
+ *
+ * If [end] is omitted, it defaults to the [length] of this list.
+ *
+ * ```dart
+ * print(numbers.sublist(1)); // [1, 2, 3, 4]
+ * ```
+ *
+ * The `start` and `end` positions must satisfy the relations
+ * 0 ≤ `start` ≤ `end` ≤ `this.length`
+ * If `end` is equal to `start`, then the returned list is empty.
+ */
+ Float64x2List sublist(int start, [int end]);
+
+ static const int bytesPerElement = 16;
+}
+
+/**
+ * Float32x4 immutable value type and operations.
+ *
+ * Float32x4 stores 4 32-bit floating point values in "lanes".
+ * The lanes are "x", "y", "z", and "w" respectively.
+ */
+abstract class Float32x4 {
+ external factory Float32x4(double x, double y, double z, double w);
+ external factory Float32x4.splat(double v);
+ external factory Float32x4.zero();
+ external factory Float32x4.fromInt32x4Bits(Int32x4 x);
+
+ /// Sets the x and y lanes to their respective values in [v] and sets the z
+ /// and w lanes to 0.0.
+ external factory Float32x4.fromFloat64x2(Float64x2 v);
+
+ /// Addition operator.
+ Float32x4 operator +(Float32x4 other);
+
+ /// Negate operator.
+ Float32x4 operator -();
+
+ /// Subtraction operator.
+ Float32x4 operator -(Float32x4 other);
+
+ /// Multiplication operator.
+ Float32x4 operator *(Float32x4 other);
+
+ /// Division operator.
+ Float32x4 operator /(Float32x4 other);
+
+ /// Relational less than.
+ Int32x4 lessThan(Float32x4 other);
+
+ /// Relational less than or equal.
+ Int32x4 lessThanOrEqual(Float32x4 other);
+
+ /// Relational greater than.
+ Int32x4 greaterThan(Float32x4 other);
+
+ /// Relational greater than or equal.
+ Int32x4 greaterThanOrEqual(Float32x4 other);
+
+ /// Relational equal.
+ Int32x4 equal(Float32x4 other);
+
+ /// Relational not-equal.
+ Int32x4 notEqual(Float32x4 other);
+
+ /// Returns a copy of [this] each lane being scaled by [s].
+ /// Equivalent to this * new Float32x4.splat(s)
+ Float32x4 scale(double s);
+
+ /// Returns the lane-wise absolute value of this [Float32x4].
+ Float32x4 abs();
+
+ /// Lane-wise clamp [this] to be in the range [lowerLimit]-[upperLimit].
+ Float32x4 clamp(Float32x4 lowerLimit, Float32x4 upperLimit);
+
+ /// Extracted x value.
+ double get x;
+
+ /// Extracted y value.
+ double get y;
+
+ /// Extracted z value.
+ double get z;
+
+ /// Extracted w value.
+ double get w;
+
+ /// Extract the sign bits from each lane return them in the first 4 bits.
+ /// "x" lane is bit 0.
+ /// "y" lane is bit 1.
+ /// "z" lane is bit 2.
+ /// "w" lane is bit 3.
+ int get signMask;
+
+ /// Mask passed to [shuffle] or [shuffleMix].
+ static const int xxxx = 0x0;
+ static const int xxxy = 0x40;
+ static const int xxxz = 0x80;
+ static const int xxxw = 0xC0;
+ static const int xxyx = 0x10;
+ static const int xxyy = 0x50;
+ static const int xxyz = 0x90;
+ static const int xxyw = 0xD0;
+ static const int xxzx = 0x20;
+ static const int xxzy = 0x60;
+ static const int xxzz = 0xA0;
+ static const int xxzw = 0xE0;
+ static const int xxwx = 0x30;
+ static const int xxwy = 0x70;
+ static const int xxwz = 0xB0;
+ static const int xxww = 0xF0;
+ static const int xyxx = 0x4;
+ static const int xyxy = 0x44;
+ static const int xyxz = 0x84;
+ static const int xyxw = 0xC4;
+ static const int xyyx = 0x14;
+ static const int xyyy = 0x54;
+ static const int xyyz = 0x94;
+ static const int xyyw = 0xD4;
+ static const int xyzx = 0x24;
+ static const int xyzy = 0x64;
+ static const int xyzz = 0xA4;
+ static const int xyzw = 0xE4;
+ static const int xywx = 0x34;
+ static const int xywy = 0x74;
+ static const int xywz = 0xB4;
+ static const int xyww = 0xF4;
+ static const int xzxx = 0x8;
+ static const int xzxy = 0x48;
+ static const int xzxz = 0x88;
+ static const int xzxw = 0xC8;
+ static const int xzyx = 0x18;
+ static const int xzyy = 0x58;
+ static const int xzyz = 0x98;
+ static const int xzyw = 0xD8;
+ static const int xzzx = 0x28;
+ static const int xzzy = 0x68;
+ static const int xzzz = 0xA8;
+ static const int xzzw = 0xE8;
+ static const int xzwx = 0x38;
+ static const int xzwy = 0x78;
+ static const int xzwz = 0xB8;
+ static const int xzww = 0xF8;
+ static const int xwxx = 0xC;
+ static const int xwxy = 0x4C;
+ static const int xwxz = 0x8C;
+ static const int xwxw = 0xCC;
+ static const int xwyx = 0x1C;
+ static const int xwyy = 0x5C;
+ static const int xwyz = 0x9C;
+ static const int xwyw = 0xDC;
+ static const int xwzx = 0x2C;
+ static const int xwzy = 0x6C;
+ static const int xwzz = 0xAC;
+ static const int xwzw = 0xEC;
+ static const int xwwx = 0x3C;
+ static const int xwwy = 0x7C;
+ static const int xwwz = 0xBC;
+ static const int xwww = 0xFC;
+ static const int yxxx = 0x1;
+ static const int yxxy = 0x41;
+ static const int yxxz = 0x81;
+ static const int yxxw = 0xC1;
+ static const int yxyx = 0x11;
+ static const int yxyy = 0x51;
+ static const int yxyz = 0x91;
+ static const int yxyw = 0xD1;
+ static const int yxzx = 0x21;
+ static const int yxzy = 0x61;
+ static const int yxzz = 0xA1;
+ static const int yxzw = 0xE1;
+ static const int yxwx = 0x31;
+ static const int yxwy = 0x71;
+ static const int yxwz = 0xB1;
+ static const int yxww = 0xF1;
+ static const int yyxx = 0x5;
+ static const int yyxy = 0x45;
+ static const int yyxz = 0x85;
+ static const int yyxw = 0xC5;
+ static const int yyyx = 0x15;
+ static const int yyyy = 0x55;
+ static const int yyyz = 0x95;
+ static const int yyyw = 0xD5;
+ static const int yyzx = 0x25;
+ static const int yyzy = 0x65;
+ static const int yyzz = 0xA5;
+ static const int yyzw = 0xE5;
+ static const int yywx = 0x35;
+ static const int yywy = 0x75;
+ static const int yywz = 0xB5;
+ static const int yyww = 0xF5;
+ static const int yzxx = 0x9;
+ static const int yzxy = 0x49;
+ static const int yzxz = 0x89;
+ static const int yzxw = 0xC9;
+ static const int yzyx = 0x19;
+ static const int yzyy = 0x59;
+ static const int yzyz = 0x99;
+ static const int yzyw = 0xD9;
+ static const int yzzx = 0x29;
+ static const int yzzy = 0x69;
+ static const int yzzz = 0xA9;
+ static const int yzzw = 0xE9;
+ static const int yzwx = 0x39;
+ static const int yzwy = 0x79;
+ static const int yzwz = 0xB9;
+ static const int yzww = 0xF9;
+ static const int ywxx = 0xD;
+ static const int ywxy = 0x4D;
+ static const int ywxz = 0x8D;
+ static const int ywxw = 0xCD;
+ static const int ywyx = 0x1D;
+ static const int ywyy = 0x5D;
+ static const int ywyz = 0x9D;
+ static const int ywyw = 0xDD;
+ static const int ywzx = 0x2D;
+ static const int ywzy = 0x6D;
+ static const int ywzz = 0xAD;
+ static const int ywzw = 0xED;
+ static const int ywwx = 0x3D;
+ static const int ywwy = 0x7D;
+ static const int ywwz = 0xBD;
+ static const int ywww = 0xFD;
+ static const int zxxx = 0x2;
+ static const int zxxy = 0x42;
+ static const int zxxz = 0x82;
+ static const int zxxw = 0xC2;
+ static const int zxyx = 0x12;
+ static const int zxyy = 0x52;
+ static const int zxyz = 0x92;
+ static const int zxyw = 0xD2;
+ static const int zxzx = 0x22;
+ static const int zxzy = 0x62;
+ static const int zxzz = 0xA2;
+ static const int zxzw = 0xE2;
+ static const int zxwx = 0x32;
+ static const int zxwy = 0x72;
+ static const int zxwz = 0xB2;
+ static const int zxww = 0xF2;
+ static const int zyxx = 0x6;
+ static const int zyxy = 0x46;
+ static const int zyxz = 0x86;
+ static const int zyxw = 0xC6;
+ static const int zyyx = 0x16;
+ static const int zyyy = 0x56;
+ static const int zyyz = 0x96;
+ static const int zyyw = 0xD6;
+ static const int zyzx = 0x26;
+ static const int zyzy = 0x66;
+ static const int zyzz = 0xA6;
+ static const int zyzw = 0xE6;
+ static const int zywx = 0x36;
+ static const int zywy = 0x76;
+ static const int zywz = 0xB6;
+ static const int zyww = 0xF6;
+ static const int zzxx = 0xA;
+ static const int zzxy = 0x4A;
+ static const int zzxz = 0x8A;
+ static const int zzxw = 0xCA;
+ static const int zzyx = 0x1A;
+ static const int zzyy = 0x5A;
+ static const int zzyz = 0x9A;
+ static const int zzyw = 0xDA;
+ static const int zzzx = 0x2A;
+ static const int zzzy = 0x6A;
+ static const int zzzz = 0xAA;
+ static const int zzzw = 0xEA;
+ static const int zzwx = 0x3A;
+ static const int zzwy = 0x7A;
+ static const int zzwz = 0xBA;
+ static const int zzww = 0xFA;
+ static const int zwxx = 0xE;
+ static const int zwxy = 0x4E;
+ static const int zwxz = 0x8E;
+ static const int zwxw = 0xCE;
+ static const int zwyx = 0x1E;
+ static const int zwyy = 0x5E;
+ static const int zwyz = 0x9E;
+ static const int zwyw = 0xDE;
+ static const int zwzx = 0x2E;
+ static const int zwzy = 0x6E;
+ static const int zwzz = 0xAE;
+ static const int zwzw = 0xEE;
+ static const int zwwx = 0x3E;
+ static const int zwwy = 0x7E;
+ static const int zwwz = 0xBE;
+ static const int zwww = 0xFE;
+ static const int wxxx = 0x3;
+ static const int wxxy = 0x43;
+ static const int wxxz = 0x83;
+ static const int wxxw = 0xC3;
+ static const int wxyx = 0x13;
+ static const int wxyy = 0x53;
+ static const int wxyz = 0x93;
+ static const int wxyw = 0xD3;
+ static const int wxzx = 0x23;
+ static const int wxzy = 0x63;
+ static const int wxzz = 0xA3;
+ static const int wxzw = 0xE3;
+ static const int wxwx = 0x33;
+ static const int wxwy = 0x73;
+ static const int wxwz = 0xB3;
+ static const int wxww = 0xF3;
+ static const int wyxx = 0x7;
+ static const int wyxy = 0x47;
+ static const int wyxz = 0x87;
+ static const int wyxw = 0xC7;
+ static const int wyyx = 0x17;
+ static const int wyyy = 0x57;
+ static const int wyyz = 0x97;
+ static const int wyyw = 0xD7;
+ static const int wyzx = 0x27;
+ static const int wyzy = 0x67;
+ static const int wyzz = 0xA7;
+ static const int wyzw = 0xE7;
+ static const int wywx = 0x37;
+ static const int wywy = 0x77;
+ static const int wywz = 0xB7;
+ static const int wyww = 0xF7;
+ static const int wzxx = 0xB;
+ static const int wzxy = 0x4B;
+ static const int wzxz = 0x8B;
+ static const int wzxw = 0xCB;
+ static const int wzyx = 0x1B;
+ static const int wzyy = 0x5B;
+ static const int wzyz = 0x9B;
+ static const int wzyw = 0xDB;
+ static const int wzzx = 0x2B;
+ static const int wzzy = 0x6B;
+ static const int wzzz = 0xAB;
+ static const int wzzw = 0xEB;
+ static const int wzwx = 0x3B;
+ static const int wzwy = 0x7B;
+ static const int wzwz = 0xBB;
+ static const int wzww = 0xFB;
+ static const int wwxx = 0xF;
+ static const int wwxy = 0x4F;
+ static const int wwxz = 0x8F;
+ static const int wwxw = 0xCF;
+ static const int wwyx = 0x1F;
+ static const int wwyy = 0x5F;
+ static const int wwyz = 0x9F;
+ static const int wwyw = 0xDF;
+ static const int wwzx = 0x2F;
+ static const int wwzy = 0x6F;
+ static const int wwzz = 0xAF;
+ static const int wwzw = 0xEF;
+ static const int wwwx = 0x3F;
+ static const int wwwy = 0x7F;
+ static const int wwwz = 0xBF;
+ static const int wwww = 0xFF;
+
+ /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
+ Float32x4 shuffle(int mask);
+
+ /// Shuffle the lane values in [this] and [other]. The returned
+ /// Float32x4 will have XY lanes from [this] and ZW lanes from [other].
+ /// Uses the same [mask] as [shuffle].
+ Float32x4 shuffleMix(Float32x4 other, int mask);
+
+ /// Returns a new [Float32x4] copied from [this] with a new x value.
+ Float32x4 withX(double x);
+
+ /// Returns a new [Float32x4] copied from [this] with a new y value.
+ Float32x4 withY(double y);
+
+ /// Returns a new [Float32x4] copied from [this] with a new z value.
+ Float32x4 withZ(double z);
+
+ /// Returns a new [Float32x4] copied from [this] with a new w value.
+ Float32x4 withW(double w);
+
+ /// Returns the lane-wise minimum value in [this] or [other].
+ Float32x4 min(Float32x4 other);
+
+ /// Returns the lane-wise maximum value in [this] or [other].
+ Float32x4 max(Float32x4 other);
+
+ /// Returns the square root of [this].
+ Float32x4 sqrt();
+
+ /// Returns the reciprocal of [this].
+ Float32x4 reciprocal();
+
+ /// Returns the square root of the reciprocal of [this].
+ Float32x4 reciprocalSqrt();
+}
+
+/**
+ * Int32x4 and operations.
+ *
+ * Int32x4 stores 4 32-bit bit-masks in "lanes".
+ * The lanes are "x", "y", "z", and "w" respectively.
+ */
+abstract class Int32x4 {
+ external factory Int32x4(int x, int y, int z, int w);
+ external factory Int32x4.bool(bool x, bool y, bool z, bool w);
+ external factory Int32x4.fromFloat32x4Bits(Float32x4 x);
+
+ /// The bit-wise or operator.
+ Int32x4 operator |(Int32x4 other);
+
+ /// The bit-wise and operator.
+ Int32x4 operator &(Int32x4 other);
+
+ /// The bit-wise xor operator.
+ Int32x4 operator ^(Int32x4 other);
+
+ /// Addition operator.
+ Int32x4 operator +(Int32x4 other);
+
+ /// Subtraction operator.
+ Int32x4 operator -(Int32x4 other);
+
+ /// Extract 32-bit mask from x lane.
+ int get x;
+
+ /// Extract 32-bit mask from y lane.
+ int get y;
+
+ /// Extract 32-bit mask from z lane.
+ int get z;
+
+ /// Extract 32-bit mask from w lane.
+ int get w;
+
+ /// Extract the top bit from each lane return them in the first 4 bits.
+ /// "x" lane is bit 0.
+ /// "y" lane is bit 1.
+ /// "z" lane is bit 2.
+ /// "w" lane is bit 3.
+ int get signMask;
+
+ /// Mask passed to [shuffle] or [shuffleMix].
+ static const int xxxx = 0x0;
+ static const int xxxy = 0x40;
+ static const int xxxz = 0x80;
+ static const int xxxw = 0xC0;
+ static const int xxyx = 0x10;
+ static const int xxyy = 0x50;
+ static const int xxyz = 0x90;
+ static const int xxyw = 0xD0;
+ static const int xxzx = 0x20;
+ static const int xxzy = 0x60;
+ static const int xxzz = 0xA0;
+ static const int xxzw = 0xE0;
+ static const int xxwx = 0x30;
+ static const int xxwy = 0x70;
+ static const int xxwz = 0xB0;
+ static const int xxww = 0xF0;
+ static const int xyxx = 0x4;
+ static const int xyxy = 0x44;
+ static const int xyxz = 0x84;
+ static const int xyxw = 0xC4;
+ static const int xyyx = 0x14;
+ static const int xyyy = 0x54;
+ static const int xyyz = 0x94;
+ static const int xyyw = 0xD4;
+ static const int xyzx = 0x24;
+ static const int xyzy = 0x64;
+ static const int xyzz = 0xA4;
+ static const int xyzw = 0xE4;
+ static const int xywx = 0x34;
+ static const int xywy = 0x74;
+ static const int xywz = 0xB4;
+ static const int xyww = 0xF4;
+ static const int xzxx = 0x8;
+ static const int xzxy = 0x48;
+ static const int xzxz = 0x88;
+ static const int xzxw = 0xC8;
+ static const int xzyx = 0x18;
+ static const int xzyy = 0x58;
+ static const int xzyz = 0x98;
+ static const int xzyw = 0xD8;
+ static const int xzzx = 0x28;
+ static const int xzzy = 0x68;
+ static const int xzzz = 0xA8;
+ static const int xzzw = 0xE8;
+ static const int xzwx = 0x38;
+ static const int xzwy = 0x78;
+ static const int xzwz = 0xB8;
+ static const int xzww = 0xF8;
+ static const int xwxx = 0xC;
+ static const int xwxy = 0x4C;
+ static const int xwxz = 0x8C;
+ static const int xwxw = 0xCC;
+ static const int xwyx = 0x1C;
+ static const int xwyy = 0x5C;
+ static const int xwyz = 0x9C;
+ static const int xwyw = 0xDC;
+ static const int xwzx = 0x2C;
+ static const int xwzy = 0x6C;
+ static const int xwzz = 0xAC;
+ static const int xwzw = 0xEC;
+ static const int xwwx = 0x3C;
+ static const int xwwy = 0x7C;
+ static const int xwwz = 0xBC;
+ static const int xwww = 0xFC;
+ static const int yxxx = 0x1;
+ static const int yxxy = 0x41;
+ static const int yxxz = 0x81;
+ static const int yxxw = 0xC1;
+ static const int yxyx = 0x11;
+ static const int yxyy = 0x51;
+ static const int yxyz = 0x91;
+ static const int yxyw = 0xD1;
+ static const int yxzx = 0x21;
+ static const int yxzy = 0x61;
+ static const int yxzz = 0xA1;
+ static const int yxzw = 0xE1;
+ static const int yxwx = 0x31;
+ static const int yxwy = 0x71;
+ static const int yxwz = 0xB1;
+ static const int yxww = 0xF1;
+ static const int yyxx = 0x5;
+ static const int yyxy = 0x45;
+ static const int yyxz = 0x85;
+ static const int yyxw = 0xC5;
+ static const int yyyx = 0x15;
+ static const int yyyy = 0x55;
+ static const int yyyz = 0x95;
+ static const int yyyw = 0xD5;
+ static const int yyzx = 0x25;
+ static const int yyzy = 0x65;
+ static const int yyzz = 0xA5;
+ static const int yyzw = 0xE5;
+ static const int yywx = 0x35;
+ static const int yywy = 0x75;
+ static const int yywz = 0xB5;
+ static const int yyww = 0xF5;
+ static const int yzxx = 0x9;
+ static const int yzxy = 0x49;
+ static const int yzxz = 0x89;
+ static const int yzxw = 0xC9;
+ static const int yzyx = 0x19;
+ static const int yzyy = 0x59;
+ static const int yzyz = 0x99;
+ static const int yzyw = 0xD9;
+ static const int yzzx = 0x29;
+ static const int yzzy = 0x69;
+ static const int yzzz = 0xA9;
+ static const int yzzw = 0xE9;
+ static const int yzwx = 0x39;
+ static const int yzwy = 0x79;
+ static const int yzwz = 0xB9;
+ static const int yzww = 0xF9;
+ static const int ywxx = 0xD;
+ static const int ywxy = 0x4D;
+ static const int ywxz = 0x8D;
+ static const int ywxw = 0xCD;
+ static const int ywyx = 0x1D;
+ static const int ywyy = 0x5D;
+ static const int ywyz = 0x9D;
+ static const int ywyw = 0xDD;
+ static const int ywzx = 0x2D;
+ static const int ywzy = 0x6D;
+ static const int ywzz = 0xAD;
+ static const int ywzw = 0xED;
+ static const int ywwx = 0x3D;
+ static const int ywwy = 0x7D;
+ static const int ywwz = 0xBD;
+ static const int ywww = 0xFD;
+ static const int zxxx = 0x2;
+ static const int zxxy = 0x42;
+ static const int zxxz = 0x82;
+ static const int zxxw = 0xC2;
+ static const int zxyx = 0x12;
+ static const int zxyy = 0x52;
+ static const int zxyz = 0x92;
+ static const int zxyw = 0xD2;
+ static const int zxzx = 0x22;
+ static const int zxzy = 0x62;
+ static const int zxzz = 0xA2;
+ static const int zxzw = 0xE2;
+ static const int zxwx = 0x32;
+ static const int zxwy = 0x72;
+ static const int zxwz = 0xB2;
+ static const int zxww = 0xF2;
+ static const int zyxx = 0x6;
+ static const int zyxy = 0x46;
+ static const int zyxz = 0x86;
+ static const int zyxw = 0xC6;
+ static const int zyyx = 0x16;
+ static const int zyyy = 0x56;
+ static const int zyyz = 0x96;
+ static const int zyyw = 0xD6;
+ static const int zyzx = 0x26;
+ static const int zyzy = 0x66;
+ static const int zyzz = 0xA6;
+ static const int zyzw = 0xE6;
+ static const int zywx = 0x36;
+ static const int zywy = 0x76;
+ static const int zywz = 0xB6;
+ static const int zyww = 0xF6;
+ static const int zzxx = 0xA;
+ static const int zzxy = 0x4A;
+ static const int zzxz = 0x8A;
+ static const int zzxw = 0xCA;
+ static const int zzyx = 0x1A;
+ static const int zzyy = 0x5A;
+ static const int zzyz = 0x9A;
+ static const int zzyw = 0xDA;
+ static const int zzzx = 0x2A;
+ static const int zzzy = 0x6A;
+ static const int zzzz = 0xAA;
+ static const int zzzw = 0xEA;
+ static const int zzwx = 0x3A;
+ static const int zzwy = 0x7A;
+ static const int zzwz = 0xBA;
+ static const int zzww = 0xFA;
+ static const int zwxx = 0xE;
+ static const int zwxy = 0x4E;
+ static const int zwxz = 0x8E;
+ static const int zwxw = 0xCE;
+ static const int zwyx = 0x1E;
+ static const int zwyy = 0x5E;
+ static const int zwyz = 0x9E;
+ static const int zwyw = 0xDE;
+ static const int zwzx = 0x2E;
+ static const int zwzy = 0x6E;
+ static const int zwzz = 0xAE;
+ static const int zwzw = 0xEE;
+ static const int zwwx = 0x3E;
+ static const int zwwy = 0x7E;
+ static const int zwwz = 0xBE;
+ static const int zwww = 0xFE;
+ static const int wxxx = 0x3;
+ static const int wxxy = 0x43;
+ static const int wxxz = 0x83;
+ static const int wxxw = 0xC3;
+ static const int wxyx = 0x13;
+ static const int wxyy = 0x53;
+ static const int wxyz = 0x93;
+ static const int wxyw = 0xD3;
+ static const int wxzx = 0x23;
+ static const int wxzy = 0x63;
+ static const int wxzz = 0xA3;
+ static const int wxzw = 0xE3;
+ static const int wxwx = 0x33;
+ static const int wxwy = 0x73;
+ static const int wxwz = 0xB3;
+ static const int wxww = 0xF3;
+ static const int wyxx = 0x7;
+ static const int wyxy = 0x47;
+ static const int wyxz = 0x87;
+ static const int wyxw = 0xC7;
+ static const int wyyx = 0x17;
+ static const int wyyy = 0x57;
+ static const int wyyz = 0x97;
+ static const int wyyw = 0xD7;
+ static const int wyzx = 0x27;
+ static const int wyzy = 0x67;
+ static const int wyzz = 0xA7;
+ static const int wyzw = 0xE7;
+ static const int wywx = 0x37;
+ static const int wywy = 0x77;
+ static const int wywz = 0xB7;
+ static const int wyww = 0xF7;
+ static const int wzxx = 0xB;
+ static const int wzxy = 0x4B;
+ static const int wzxz = 0x8B;
+ static const int wzxw = 0xCB;
+ static const int wzyx = 0x1B;
+ static const int wzyy = 0x5B;
+ static const int wzyz = 0x9B;
+ static const int wzyw = 0xDB;
+ static const int wzzx = 0x2B;
+ static const int wzzy = 0x6B;
+ static const int wzzz = 0xAB;
+ static const int wzzw = 0xEB;
+ static const int wzwx = 0x3B;
+ static const int wzwy = 0x7B;
+ static const int wzwz = 0xBB;
+ static const int wzww = 0xFB;
+ static const int wwxx = 0xF;
+ static const int wwxy = 0x4F;
+ static const int wwxz = 0x8F;
+ static const int wwxw = 0xCF;
+ static const int wwyx = 0x1F;
+ static const int wwyy = 0x5F;
+ static const int wwyz = 0x9F;
+ static const int wwyw = 0xDF;
+ static const int wwzx = 0x2F;
+ static const int wwzy = 0x6F;
+ static const int wwzz = 0xAF;
+ static const int wwzw = 0xEF;
+ static const int wwwx = 0x3F;
+ static const int wwwy = 0x7F;
+ static const int wwwz = 0xBF;
+ static const int wwww = 0xFF;
+
+ /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
+ Int32x4 shuffle(int mask);
+
+ /// Shuffle the lane values in [this] and [other]. The returned
+ /// Int32x4 will have XY lanes from [this] and ZW lanes from [other].
+ /// Uses the same [mask] as [shuffle].
+ Int32x4 shuffleMix(Int32x4 other, int mask);
+
+ /// Returns a new [Int32x4] copied from [this] with a new x value.
+ Int32x4 withX(int x);
+
+ /// Returns a new [Int32x4] copied from [this] with a new y value.
+ Int32x4 withY(int y);
+
+ /// Returns a new [Int32x4] copied from [this] with a new z value.
+ Int32x4 withZ(int z);
+
+ /// Returns a new [Int32x4] copied from [this] with a new w value.
+ Int32x4 withW(int w);
+
+ /// Extracted x value. Returns false for 0, true for any other value.
+ bool get flagX;
+
+ /// Extracted y value. Returns false for 0, true for any other value.
+ bool get flagY;
+
+ /// Extracted z value. Returns false for 0, true for any other value.
+ bool get flagZ;
+
+ /// Extracted w value. Returns false for 0, true for any other value.
+ bool get flagW;
+
+ /// Returns a new [Int32x4] copied from [this] with a new x value.
+ Int32x4 withFlagX(bool x);
+
+ /// Returns a new [Int32x4] copied from [this] with a new y value.
+ Int32x4 withFlagY(bool y);
+
+ /// Returns a new [Int32x4] copied from [this] with a new z value.
+ Int32x4 withFlagZ(bool z);
+
+ /// Returns a new [Int32x4] copied from [this] with a new w value.
+ Int32x4 withFlagW(bool w);
+
+ /// Merge [trueValue] and [falseValue] based on [this]' bit mask:
+ /// Select bit from [trueValue] when bit in [this] is on.
+ /// Select bit from [falseValue] when bit in [this] is off.
+ Float32x4 select(Float32x4 trueValue, Float32x4 falseValue);
+}
+
+/**
+ * Float64x2 immutable value type and operations.
+ *
+ * Float64x2 stores 2 64-bit floating point values in "lanes".
+ * The lanes are "x" and "y" respectively.
+ */
+abstract class Float64x2 {
+ external factory Float64x2(double x, double y);
+ external factory Float64x2.splat(double v);
+ external factory Float64x2.zero();
+
+ /// Uses the "x" and "y" lanes from [v].
+ external factory Float64x2.fromFloat32x4(Float32x4 v);
+
+ /// Addition operator.
+ Float64x2 operator +(Float64x2 other);
+
+ /// Negate operator.
+ Float64x2 operator -();
+
+ /// Subtraction operator.
+ Float64x2 operator -(Float64x2 other);
+
+ /// Multiplication operator.
+ Float64x2 operator *(Float64x2 other);
+
+ /// Division operator.
+ Float64x2 operator /(Float64x2 other);
+
+ /// Returns a copy of [this] each lane being scaled by [s].
+ /// Equivalent to this * new Float64x2.splat(s)
+ Float64x2 scale(double s);
+
+ /// Returns the lane-wise absolute value of this [Float64x2].
+ Float64x2 abs();
+
+ /// Lane-wise clamp [this] to be in the range [lowerLimit]-[upperLimit].
+ Float64x2 clamp(Float64x2 lowerLimit, Float64x2 upperLimit);
+
+ /// Extracted x value.
+ double get x;
+
+ /// Extracted y value.
+ double get y;
+
+ /// Extract the sign bits from each lane return them in the first 2 bits.
+ /// "x" lane is bit 0.
+ /// "y" lane is bit 1.
+ int get signMask;
+
+ /// Returns a new [Float64x2] copied from [this] with a new x value.
+ Float64x2 withX(double x);
+
+ /// Returns a new [Float64x2] copied from [this] with a new y value.
+ Float64x2 withY(double y);
+
+ /// Returns the lane-wise minimum value in [this] or [other].
+ Float64x2 min(Float64x2 other);
+
+ /// Returns the lane-wise maximum value in [this] or [other].
+ Float64x2 max(Float64x2 other);
+
+ /// Returns the lane-wise square root of [this].
+ Float64x2 sqrt();
+}
diff --git a/sdk_nnbd/lib/typed_data/typed_data_sources.gni b/sdk_nnbd/lib/typed_data/typed_data_sources.gni
new file mode 100644
index 0000000..23ba0f0
--- /dev/null
+++ b/sdk_nnbd/lib/typed_data/typed_data_sources.gni
@@ -0,0 +1,9 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+typed_data_sdk_sources = [
+ "typed_data.dart",
+ # The above file needs to be first if additional parts are added to the lib.
+ "unmodifiable_typed_data.dart",
+]
diff --git a/sdk_nnbd/lib/typed_data/unmodifiable_typed_data.dart b/sdk_nnbd/lib/typed_data/unmodifiable_typed_data.dart
new file mode 100644
index 0000000..3549041
--- /dev/null
+++ b/sdk_nnbd/lib/typed_data/unmodifiable_typed_data.dart
@@ -0,0 +1,341 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.typed_data;
+
+/**
+ * A read-only view of a [ByteBuffer].
+ */
+class UnmodifiableByteBufferView implements ByteBuffer {
+ final ByteBuffer _data;
+
+ UnmodifiableByteBufferView(ByteBuffer data) : _data = data;
+
+ int get lengthInBytes => _data.lengthInBytes;
+
+ Uint8List asUint8List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableUint8ListView(_data.asUint8List(offsetInBytes, length));
+
+ Int8List asInt8List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableInt8ListView(_data.asInt8List(offsetInBytes, length));
+
+ Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableUint8ClampedListView(
+ _data.asUint8ClampedList(offsetInBytes, length));
+
+ Uint16List asUint16List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableUint16ListView(_data.asUint16List(offsetInBytes, length));
+
+ Int16List asInt16List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableInt16ListView(_data.asInt16List(offsetInBytes, length));
+
+ Uint32List asUint32List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableUint32ListView(_data.asUint32List(offsetInBytes, length));
+
+ Int32List asInt32List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableInt32ListView(_data.asInt32List(offsetInBytes, length));
+
+ Uint64List asUint64List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableUint64ListView(_data.asUint64List(offsetInBytes, length));
+
+ Int64List asInt64List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableInt64ListView(_data.asInt64List(offsetInBytes, length));
+
+ Int32x4List asInt32x4List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableInt32x4ListView(
+ _data.asInt32x4List(offsetInBytes, length));
+
+ Float32List asFloat32List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableFloat32ListView(
+ _data.asFloat32List(offsetInBytes, length));
+
+ Float64List asFloat64List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableFloat64ListView(
+ _data.asFloat64List(offsetInBytes, length));
+
+ Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableFloat32x4ListView(
+ _data.asFloat32x4List(offsetInBytes, length));
+
+ Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableFloat64x2ListView(
+ _data.asFloat64x2List(offsetInBytes, length));
+
+ ByteData asByteData([int offsetInBytes = 0, int length]) =>
+ new UnmodifiableByteDataView(_data.asByteData(offsetInBytes, length));
+}
+
+/**
+ * A read-only view of a [ByteData].
+ */
+class UnmodifiableByteDataView implements ByteData {
+ final ByteData _data;
+
+ UnmodifiableByteDataView(ByteData data) : _data = data;
+
+ int getInt8(int byteOffset) => _data.getInt8(byteOffset);
+
+ void setInt8(int byteOffset, int value) => _unsupported();
+
+ int getUint8(int byteOffset) => _data.getUint8(byteOffset);
+
+ void setUint8(int byteOffset, int value) => _unsupported();
+
+ int getInt16(int byteOffset, [Endian endian = Endian.big]) =>
+ _data.getInt16(byteOffset, endian);
+
+ void setInt16(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _unsupported();
+
+ int getUint16(int byteOffset, [Endian endian = Endian.big]) =>
+ _data.getUint16(byteOffset, endian);
+
+ void setUint16(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _unsupported();
+
+ int getInt32(int byteOffset, [Endian endian = Endian.big]) =>
+ _data.getInt32(byteOffset, endian);
+
+ void setInt32(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _unsupported();
+
+ int getUint32(int byteOffset, [Endian endian = Endian.big]) =>
+ _data.getUint32(byteOffset, endian);
+
+ void setUint32(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _unsupported();
+
+ int getInt64(int byteOffset, [Endian endian = Endian.big]) =>
+ _data.getInt64(byteOffset, endian);
+
+ void setInt64(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _unsupported();
+
+ int getUint64(int byteOffset, [Endian endian = Endian.big]) =>
+ _data.getUint64(byteOffset, endian);
+
+ void setUint64(int byteOffset, int value, [Endian endian = Endian.big]) =>
+ _unsupported();
+
+ double getFloat32(int byteOffset, [Endian endian = Endian.big]) =>
+ _data.getFloat32(byteOffset, endian);
+
+ void setFloat32(int byteOffset, double value, [Endian endian = Endian.big]) =>
+ _unsupported();
+
+ double getFloat64(int byteOffset, [Endian endian = Endian.big]) =>
+ _data.getFloat64(byteOffset, endian);
+
+ void setFloat64(int byteOffset, double value, [Endian endian = Endian.big]) =>
+ _unsupported();
+
+ int get elementSizeInBytes => _data.elementSizeInBytes;
+
+ int get offsetInBytes => _data.offsetInBytes;
+
+ int get lengthInBytes => _data.lengthInBytes;
+
+ ByteBuffer get buffer => new UnmodifiableByteBufferView(_data.buffer);
+
+ void _unsupported() {
+ throw new UnsupportedError(
+ "An UnmodifiableByteDataView may not be modified");
+ }
+}
+
+abstract class _UnmodifiableListMixin<N, L extends List<N>,
+ TD extends TypedData> {
+ L get _list;
+ TD get _data => (_list as TD);
+
+ int get length => _list.length;
+
+ N operator [](int index) => _list[index];
+
+ int get elementSizeInBytes => _data.elementSizeInBytes;
+
+ int get offsetInBytes => _data.offsetInBytes;
+
+ int get lengthInBytes => _data.lengthInBytes;
+
+ ByteBuffer get buffer => new UnmodifiableByteBufferView(_data.buffer);
+
+ L _createList(int length);
+
+ L sublist(int start, [int end]) {
+ end = RangeError.checkValidRange(start, end, length);
+ int sublistLength = end - start;
+ L result = _createList(sublistLength);
+ result.setRange(0, sublistLength, _list, start);
+ return result;
+ }
+}
+
+/**
+ * View of a [Uint8List] that disallows modification.
+ */
+class UnmodifiableUint8ListView extends UnmodifiableListBase<int>
+ with _UnmodifiableListMixin<int, Uint8List, Uint8List>
+ implements Uint8List {
+ final Uint8List _list;
+ UnmodifiableUint8ListView(Uint8List list) : _list = list;
+
+ Uint8List _createList(int length) => Uint8List(length);
+}
+
+/**
+ * View of a [Int8List] that disallows modification.
+ */
+class UnmodifiableInt8ListView extends UnmodifiableListBase<int>
+ with _UnmodifiableListMixin<int, Int8List, Int8List>
+ implements Int8List {
+ final Int8List _list;
+ UnmodifiableInt8ListView(Int8List list) : _list = list;
+
+ Int8List _createList(int length) => Int8List(length);
+}
+
+/**
+ * View of a [Uint8ClampedList] that disallows modification.
+ */
+class UnmodifiableUint8ClampedListView extends UnmodifiableListBase<int>
+ with _UnmodifiableListMixin<int, Uint8ClampedList, Uint8ClampedList>
+ implements Uint8ClampedList {
+ final Uint8ClampedList _list;
+ UnmodifiableUint8ClampedListView(Uint8ClampedList list) : _list = list;
+
+ Uint8ClampedList _createList(int length) => Uint8ClampedList(length);
+}
+
+/**
+ * View of a [Uint16List] that disallows modification.
+ */
+class UnmodifiableUint16ListView extends UnmodifiableListBase<int>
+ with _UnmodifiableListMixin<int, Uint16List, Uint16List>
+ implements Uint16List {
+ final Uint16List _list;
+ UnmodifiableUint16ListView(Uint16List list) : _list = list;
+
+ Uint16List _createList(int length) => Uint16List(length);
+}
+
+/**
+ * View of a [Int16List] that disallows modification.
+ */
+class UnmodifiableInt16ListView extends UnmodifiableListBase<int>
+ with _UnmodifiableListMixin<int, Int16List, Int16List>
+ implements Int16List {
+ final Int16List _list;
+ UnmodifiableInt16ListView(Int16List list) : _list = list;
+
+ Int16List _createList(int length) => Int16List(length);
+}
+
+/**
+ * View of a [Uint32List] that disallows modification.
+ */
+class UnmodifiableUint32ListView extends UnmodifiableListBase<int>
+ with _UnmodifiableListMixin<int, Uint32List, Uint32List>
+ implements Uint32List {
+ final Uint32List _list;
+ UnmodifiableUint32ListView(Uint32List list) : _list = list;
+
+ Uint32List _createList(int length) => Uint32List(length);
+}
+
+/**
+ * View of a [Int32List] that disallows modification.
+ */
+class UnmodifiableInt32ListView extends UnmodifiableListBase<int>
+ with _UnmodifiableListMixin<int, Int32List, Int32List>
+ implements Int32List {
+ final Int32List _list;
+ UnmodifiableInt32ListView(Int32List list) : _list = list;
+
+ Int32List _createList(int length) => Int32List(length);
+}
+
+/**
+ * View of a [Uint64List] that disallows modification.
+ */
+class UnmodifiableUint64ListView extends UnmodifiableListBase<int>
+ with _UnmodifiableListMixin<int, Uint64List, Uint64List>
+ implements Uint64List {
+ final Uint64List _list;
+ UnmodifiableUint64ListView(Uint64List list) : _list = list;
+
+ Uint64List _createList(int length) => Uint64List(length);
+}
+
+/**
+ * View of a [Int64List] that disallows modification.
+ */
+class UnmodifiableInt64ListView extends UnmodifiableListBase<int>
+ with _UnmodifiableListMixin<int, Int64List, Int64List>
+ implements Int64List {
+ final Int64List _list;
+ UnmodifiableInt64ListView(Int64List list) : _list = list;
+
+ Int64List _createList(int length) => Int64List(length);
+}
+
+/**
+ * View of a [Int32x4List] that disallows modification.
+ */
+class UnmodifiableInt32x4ListView extends UnmodifiableListBase<Int32x4>
+ with _UnmodifiableListMixin<Int32x4, Int32x4List, Int32x4List>
+ implements Int32x4List {
+ final Int32x4List _list;
+ UnmodifiableInt32x4ListView(Int32x4List list) : _list = list;
+
+ Int32x4List _createList(int length) => Int32x4List(length);
+}
+
+/**
+ * View of a [Float32x4List] that disallows modification.
+ */
+class UnmodifiableFloat32x4ListView extends UnmodifiableListBase<Float32x4>
+ with _UnmodifiableListMixin<Float32x4, Float32x4List, Float32x4List>
+ implements Float32x4List {
+ final Float32x4List _list;
+ UnmodifiableFloat32x4ListView(Float32x4List list) : _list = list;
+
+ Float32x4List _createList(int length) => Float32x4List(length);
+}
+
+/**
+ * View of a [Float64x2List] that disallows modification.
+ */
+class UnmodifiableFloat64x2ListView extends UnmodifiableListBase<Float64x2>
+ with _UnmodifiableListMixin<Float64x2, Float64x2List, Float64x2List>
+ implements Float64x2List {
+ final Float64x2List _list;
+ UnmodifiableFloat64x2ListView(Float64x2List list) : _list = list;
+
+ Float64x2List _createList(int length) => Float64x2List(length);
+}
+
+/**
+ * View of a [Float32List] that disallows modification.
+ */
+class UnmodifiableFloat32ListView extends UnmodifiableListBase<double>
+ with _UnmodifiableListMixin<double, Float32List, Float32List>
+ implements Float32List {
+ final Float32List _list;
+ UnmodifiableFloat32ListView(Float32List list) : _list = list;
+
+ Float32List _createList(int length) => Float32List(length);
+}
+
+/**
+ * View of a [Float64List] that disallows modification.
+ */
+class UnmodifiableFloat64ListView extends UnmodifiableListBase<double>
+ with _UnmodifiableListMixin<double, Float64List, Float64List>
+ implements Float64List {
+ final Float64List _list;
+ UnmodifiableFloat64ListView(Float64List list) : _list = list;
+
+ Float64List _createList(int length) => Float64List(length);
+}
diff --git a/sdk_nnbd/lib/vmservice/asset.dart b/sdk_nnbd/lib/vmservice/asset.dart
new file mode 100644
index 0000000..d5772e2
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/asset.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+class Asset {
+ final String name;
+ final Uint8List data;
+
+ Asset(this.name, this.data);
+
+ String get mimeType {
+ var extensionStart = name.lastIndexOf('.');
+ var extension = name.substring(extensionStart + 1);
+ switch (extension) {
+ case 'html':
+ return 'text/html; charset=UTF-8';
+ case 'dart':
+ return 'application/dart; charset=UTF-8';
+ case 'js':
+ return 'application/javascript; charset=UTF-8';
+ case 'css':
+ return 'text/css; charset=UTF-8';
+ case 'gif':
+ return 'image/gif';
+ case 'png':
+ return 'image/png';
+ case 'jpg':
+ return 'image/jpeg';
+ case 'jpeg':
+ return 'image/jpeg';
+ case 'svg':
+ return 'image/svg+xml';
+ default:
+ return 'text/plain';
+ }
+ }
+
+ static Map<String, Asset> request() {
+ Uint8List tarBytes = _requestAssets();
+ if (tarBytes == null) {
+ return null;
+ }
+ List assetList = _decodeAssets(tarBytes);
+ Map<String, Asset> assets = new HashMap<String, Asset>();
+ for (int i = 0; i < assetList.length; i += 2) {
+ var a = new Asset(assetList[i], assetList[i + 1]);
+ assets[a.name] = a;
+ }
+ return assets;
+ }
+
+ String toString() => '$name ($mimeType)';
+}
+
+List _decodeAssets(Uint8List data) native "VMService_DecodeAssets";
+
+Map<String, Asset> _assets;
+Map<String, Asset> get assets {
+ if (_assets == null) {
+ try {
+ _assets = Asset.request();
+ } catch (e) {
+ print('Could not load Observatory assets: $e');
+ }
+ }
+ return _assets;
+}
diff --git a/sdk_nnbd/lib/vmservice/client.dart b/sdk_nnbd/lib/vmservice/client.dart
new file mode 100644
index 0000000..efe33c0
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/client.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+typedef void ClientServiceHandle(Message response);
+
+// A service client.
+abstract class Client {
+ final VMService service;
+ final bool sendEvents;
+
+ /// A set streamIds which describes the streams the client is connected to
+ final Set<String> streams = new Set<String>();
+
+ /// Services registered and their aliases
+ /// key: service
+ /// value: alias
+ final Map<String, String> services = new Map<String, String>();
+
+ /// Callbacks registered for service invocations set to the client
+ /// key: RPC id used for the request
+ /// value: callback that should be invoked
+ final Map<String, ClientServiceHandle> serviceHandles =
+ new Map<String, ClientServiceHandle>();
+
+ Client(this.service, {bool sendEvents: true}) : this.sendEvents = sendEvents {
+ service._addClient(this);
+ }
+
+ // Disconnects the client.
+ disconnect();
+
+ /// When implementing, call [close] when the network connection closes.
+ void close() {
+ service._removeClient(this);
+ }
+
+ /// Call to process a request. Response will be posted with 'seq'.
+ void onRequest(Message message) {
+ // In JSON-RPC 2.0 messages with and id are Request and must be answered
+ // http://www.jsonrpc.org/specification#notification
+ service.routeRequest(service, message).then(post);
+ }
+
+ void onResponse(Message message) {
+ service.routeResponse(message);
+ }
+
+ /// Call to process a notification. Response will not be posted.
+ void onNotification(Message message) {
+ // In JSON-RPC 2.0 messages without an id are Notification
+ // and should not be answered
+ // http://www.jsonrpc.org/specification#notification
+ service.routeRequest(service, message);
+ }
+
+ // Sends a result to the client. Implemented in subclasses.
+ void post(Response result);
+
+ dynamic toJson() {
+ return {};
+ }
+}
diff --git a/sdk_nnbd/lib/vmservice/constants.dart b/sdk_nnbd/lib/vmservice/constants.dart
new file mode 100644
index 0000000..914576b
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/constants.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+// These must be kept in sync with runtime/vm/service.cc.
+class Constants {
+ static const int SERVICE_EXIT_MESSAGE_ID = 0;
+ static const int ISOLATE_STARTUP_MESSAGE_ID = 1;
+ static const int ISOLATE_SHUTDOWN_MESSAGE_ID = 2;
+ static const int WEB_SERVER_CONTROL_MESSAGE_ID = 3;
+ static const int SERVER_INFO_MESSAGE_ID = 4;
+
+ /// Signals an RPC coming from native code (instead of from a websocket
+ /// connection). These calls are limited to simple request-response and do
+ /// not allow arbitrary json-rpc messages.
+ ///
+ /// The messages are an array of length 3:
+ /// (METHOD_CALL_FROM_NATIVE, String jsonRequest, PortId replyPort).
+ static const int METHOD_CALL_FROM_NATIVE = 5;
+}
diff --git a/sdk_nnbd/lib/vmservice/devfs.dart b/sdk_nnbd/lib/vmservice/devfs.dart
new file mode 100644
index 0000000..20e0573
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/devfs.dart
@@ -0,0 +1,399 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+String _encodeDevFSDisabledError(Message message) {
+ return encodeRpcError(message, kFeatureDisabled,
+ details: "DevFS is not supported by this Dart implementation");
+}
+
+String _encodeFileSystemAlreadyExistsError(Message message, String fsName) {
+ return encodeRpcError(message, kFileSystemAlreadyExists,
+ details: "${message.method}: file system '${fsName}' already exists");
+}
+
+String _encodeFileSystemDoesNotExistError(Message message, String fsName) {
+ return encodeRpcError(message, kFileSystemDoesNotExist,
+ details: "${message.method}: file system '${fsName}' does not exist");
+}
+
+class _FileSystem {
+ _FileSystem(this.name, this.uri);
+
+ final String name;
+ final Uri uri;
+
+ Uri resolvePath(String path) {
+ if (path.startsWith('/')) {
+ path = path.substring(1);
+ }
+ if (path.isEmpty) {
+ return null;
+ }
+ Uri pathUri;
+ try {
+ pathUri = new Uri.file(path);
+ } on FormatException catch (e) {
+ return null;
+ }
+
+ return resolve(pathUri);
+ }
+
+ Uri resolve(Uri pathUri) {
+ try {
+ // Make sure that this pathUri can be converted to a file path.
+ pathUri.toFilePath();
+ } on UnsupportedError catch (e) {
+ return null;
+ }
+
+ Uri resolvedUri = uri.resolveUri(pathUri);
+ if (!resolvedUri.toString().startsWith(uri.toString())) {
+ // Resolved uri must be within the filesystem's base uri.
+ return null;
+ }
+ return resolvedUri;
+ }
+
+ Map toMap() {
+ return {
+ 'type': 'FileSystem',
+ 'name': name,
+ 'uri': uri.toString(),
+ };
+ }
+}
+
+class DevFS {
+ DevFS();
+
+ Map<String, _FileSystem> _fsMap = {};
+
+ final Set _rpcNames = new Set.from([
+ '_listDevFS',
+ '_createDevFS',
+ '_deleteDevFS',
+ '_readDevFSFile',
+ '_writeDevFSFile',
+ '_writeDevFSFiles',
+ '_listDevFSFiles',
+ ]);
+
+ void cleanup() {
+ var deleteDir = VMServiceEmbedderHooks.deleteDir;
+ if (deleteDir == null) {
+ return;
+ }
+ var deletions = <Future>[];
+ for (var fs in _fsMap.values) {
+ deletions.add(deleteDir(fs.uri));
+ }
+ Future.wait(deletions);
+ _fsMap.clear();
+ }
+
+ bool shouldHandleMessage(Message message) {
+ return _rpcNames.contains(message.method);
+ }
+
+ Future<String> handleMessage(Message message) async {
+ switch (message.method) {
+ case '_listDevFS':
+ return _listDevFS(message);
+ case '_createDevFS':
+ return _createDevFS(message);
+ case '_deleteDevFS':
+ return _deleteDevFS(message);
+ case '_readDevFSFile':
+ return _readDevFSFile(message);
+ case '_writeDevFSFile':
+ return _writeDevFSFile(message);
+ case '_writeDevFSFiles':
+ return _writeDevFSFiles(message);
+ case '_listDevFSFiles':
+ return _listDevFSFiles(message);
+ default:
+ return encodeRpcError(message, kInternalError,
+ details: 'Unexpected rpc ${message.method}');
+ }
+ }
+
+ Future<String> handlePutStream(
+ Object fsName, Object path, Uri fsUri, Stream<List<int>> bytes) async {
+ // A dummy Message for error message construction.
+ Message message = new Message.forMethod('_writeDevFSFile');
+ var writeStreamFile = VMServiceEmbedderHooks.writeStreamFile;
+ if (writeStreamFile == null) {
+ return _encodeDevFSDisabledError(message);
+ }
+ if (fsName == null) {
+ return encodeMissingParamError(message, 'fsName');
+ }
+ if (fsName is! String) {
+ return encodeInvalidParamError(message, 'fsName');
+ }
+ var fs = _fsMap[fsName];
+ if (fs == null) {
+ return _encodeFileSystemDoesNotExistError(message, fsName);
+ }
+ Uri uri = fsUri;
+ if (uri == null) {
+ if (path == null) {
+ return encodeMissingParamError(message, 'path');
+ }
+ if (path is! String) {
+ return encodeInvalidParamError(message, 'path');
+ }
+ uri = fs.resolvePath(path);
+ if (uri == null) {
+ return encodeInvalidParamError(message, 'path');
+ }
+ } else {
+ uri = fs.resolve(uri);
+ if (uri == null) {
+ return encodeInvalidParamError(message, 'uri');
+ }
+ }
+ await writeStreamFile(uri, bytes);
+ return encodeSuccess(message);
+ }
+
+ Future<String> _listDevFS(Message message) async {
+ var result = {};
+ result['type'] = 'FileSystemList';
+ result['fsNames'] = _fsMap.keys.toList();
+ return encodeResult(message, result);
+ }
+
+ Future<String> _createDevFS(Message message) async {
+ var createTempDir = VMServiceEmbedderHooks.createTempDir;
+ if (createTempDir == null) {
+ return _encodeDevFSDisabledError(message);
+ }
+ var fsName = message.params['fsName'];
+ if (fsName == null) {
+ return encodeMissingParamError(message, 'fsName');
+ }
+ if (fsName is! String) {
+ return encodeInvalidParamError(message, 'fsName');
+ }
+ var fs = _fsMap[fsName];
+ if (fs != null) {
+ return _encodeFileSystemAlreadyExistsError(message, fsName);
+ }
+ var tempDir = await createTempDir(fsName);
+ fs = new _FileSystem(fsName, tempDir);
+ _fsMap[fsName] = fs;
+ return encodeResult(message, fs.toMap());
+ }
+
+ Future<String> _deleteDevFS(Message message) async {
+ var deleteDir = VMServiceEmbedderHooks.deleteDir;
+ if (deleteDir == null) {
+ return _encodeDevFSDisabledError(message);
+ }
+ var fsName = message.params['fsName'];
+ if (fsName == null) {
+ return encodeMissingParamError(message, 'fsName');
+ }
+ if (fsName is! String) {
+ return encodeInvalidParamError(message, 'fsName');
+ }
+ var fs = _fsMap.remove(fsName);
+ if (fs == null) {
+ return _encodeFileSystemDoesNotExistError(message, fsName);
+ }
+ await deleteDir(fs.uri);
+ return encodeSuccess(message);
+ }
+
+ Future<String> _readDevFSFile(Message message) async {
+ var readFile = VMServiceEmbedderHooks.readFile;
+ if (readFile == null) {
+ return _encodeDevFSDisabledError(message);
+ }
+ var fsName = message.params['fsName'];
+ if (fsName == null) {
+ return encodeMissingParamError(message, 'fsName');
+ }
+ if (fsName is! String) {
+ return encodeInvalidParamError(message, 'fsName');
+ }
+ var fs = _fsMap[fsName];
+ if (fs == null) {
+ return _encodeFileSystemDoesNotExistError(message, fsName);
+ }
+ Uri uri;
+ if (message.params['uri'] != null) {
+ try {
+ var uriParam = message.params['uri'];
+ if (uriParam is! String) {
+ return encodeInvalidParamError(message, 'uri');
+ }
+ Uri parsedUri = Uri.parse(uriParam);
+ uri = fs.resolve(parsedUri);
+ if (uri == null) {
+ return encodeInvalidParamError(message, 'uri');
+ }
+ } catch (e) {
+ return encodeInvalidParamError(message, 'uri');
+ }
+ } else {
+ var path = message.params['path'];
+ if (path == null) {
+ return encodeMissingParamError(message, 'path');
+ }
+ if (path is! String) {
+ return encodeInvalidParamError(message, 'path');
+ }
+ uri = fs.resolvePath(path);
+ if (uri == null) {
+ return encodeInvalidParamError(message, 'path');
+ }
+ }
+ try {
+ List<int> bytes = await readFile(uri);
+ var result = {'type': 'FSFile', 'fileContents': base64.encode(bytes)};
+ return encodeResult(message, result);
+ } catch (e) {
+ return encodeRpcError(message, kFileDoesNotExist,
+ details: "_readDevFSFile: $e");
+ }
+ }
+
+ Future<String> _writeDevFSFile(Message message) async {
+ var writeFile = VMServiceEmbedderHooks.writeFile;
+ if (writeFile == null) {
+ return _encodeDevFSDisabledError(message);
+ }
+ var fsName = message.params['fsName'];
+ if (fsName == null) {
+ return encodeMissingParamError(message, 'fsName');
+ }
+ if (fsName is! String) {
+ return encodeInvalidParamError(message, 'fsName');
+ }
+ var fs = _fsMap[fsName];
+ if (fs == null) {
+ return _encodeFileSystemDoesNotExistError(message, fsName);
+ }
+ Uri uri;
+ if (message.params['uri'] != null) {
+ try {
+ var uriParam = message.params['uri'];
+ if (uriParam is! String) {
+ return encodeInvalidParamError(message, 'uri');
+ }
+ Uri parsedUri = Uri.parse(uriParam);
+ uri = fs.resolve(parsedUri);
+ if (uri == null) {
+ return encodeInvalidParamError(message, 'uri');
+ }
+ } catch (e) {
+ return encodeInvalidParamError(message, 'uri');
+ }
+ } else {
+ var path = message.params['path'];
+ if (path == null) {
+ return encodeMissingParamError(message, 'path');
+ }
+ if (path is! String) {
+ return encodeInvalidParamError(message, 'path');
+ }
+ uri = fs.resolvePath(path);
+ if (uri == null) {
+ return encodeInvalidParamError(message, 'path');
+ }
+ }
+ var fileContents = message.params['fileContents'];
+ if (fileContents == null) {
+ return encodeMissingParamError(message, 'fileContents');
+ }
+ if (fileContents is! String) {
+ return encodeInvalidParamError(message, 'fileContents');
+ }
+ List<int> decodedFileContents = base64.decode(fileContents);
+
+ await writeFile(uri, decodedFileContents);
+ return encodeSuccess(message);
+ }
+
+ Future<String> _writeDevFSFiles(Message message) async {
+ var writeFile = VMServiceEmbedderHooks.writeFile;
+ if (writeFile == null) {
+ return _encodeDevFSDisabledError(message);
+ }
+ var fsName = message.params['fsName'];
+ if (fsName == null) {
+ return encodeMissingParamError(message, 'fsName');
+ }
+ if (fsName is! String) {
+ return encodeInvalidParamError(message, 'fsName');
+ }
+ var fs = _fsMap[fsName];
+ if (fs == null) {
+ return _encodeFileSystemDoesNotExistError(message, fsName);
+ }
+ var files = message.params['files'];
+ if (files == null) {
+ return encodeMissingParamError(message, 'files');
+ }
+ if (files is! List) {
+ return encodeInvalidParamError(message, 'files');
+ }
+ var uris = [];
+ for (int i = 0; i < files.length; i++) {
+ var fileInfo = files[i];
+ if (fileInfo is! List ||
+ fileInfo.length != 2 ||
+ fileInfo[0] is! String ||
+ fileInfo[1] is! String) {
+ return encodeRpcError(message, kInvalidParams,
+ details: "${message.method}: invalid 'files' parameter "
+ "at index ${i}: ${fileInfo}");
+ }
+ var uri = fs.resolvePath(fileInfo[0]);
+ if (uri == null) {
+ return encodeRpcError(message, kInvalidParams,
+ details: "${message.method}: invalid 'files' parameter "
+ "at index ${i}: ${fileInfo}");
+ }
+ uris.add(uri);
+ }
+ var pendingWrites = <Future>[];
+ for (int i = 0; i < uris.length; i++) {
+ List<int> decodedFileContents = base64.decode(files[i][1]);
+ pendingWrites.add(writeFile(uris[i], decodedFileContents));
+ }
+ await Future.wait(pendingWrites);
+ return encodeSuccess(message);
+ }
+
+ Future<String> _listDevFSFiles(Message message) async {
+ var listFiles = VMServiceEmbedderHooks.listFiles;
+ if (listFiles == null) {
+ return _encodeDevFSDisabledError(message);
+ }
+ var fsName = message.params['fsName'];
+ if (fsName == null) {
+ return encodeMissingParamError(message, 'fsName');
+ }
+ if (fsName is! String) {
+ return encodeInvalidParamError(message, 'fsName');
+ }
+ var fs = _fsMap[fsName];
+ if (fs == null) {
+ return _encodeFileSystemDoesNotExistError(message, fsName);
+ }
+ var fileList = await listFiles(fs.uri);
+ // Remove any url-encoding in the filenames.
+ for (int i = 0; i < fileList.length; i++) {
+ fileList[i]['name'] = Uri.decodeFull(fileList[i]['name']);
+ }
+ var result = {'type': 'FSFileList', 'files': fileList};
+ return encodeResult(message, result);
+ }
+}
diff --git a/sdk_nnbd/lib/vmservice/message.dart b/sdk_nnbd/lib/vmservice/message.dart
new file mode 100644
index 0000000..9e4375a
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/message.dart
@@ -0,0 +1,267 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+enum MessageType { Request, Notification, Response }
+
+class Message {
+ final Completer<Response> _completer = new Completer<Response>.sync();
+ bool get completed => _completer.isCompleted;
+
+ /// Future of response.
+ Future<Response> get response => _completer.future;
+ Client client;
+
+ // Is a notification message (no serial)
+ final MessageType type;
+
+ // Client-side identifier for this message.
+ final serial;
+
+ final String method;
+
+ final Map params = new Map();
+ final Map result = new Map();
+ final Map error = new Map();
+
+ factory Message.fromJsonRpc(Client client, Map map) {
+ if (map.containsKey('id')) {
+ final id = map['id'];
+ if (id != null && id is! num && id is! String) {
+ throw new Exception('"id" must be a number, string, or null.');
+ }
+ if (map.containsKey('method')) {
+ return new Message._fromJsonRpcRequest(client, map);
+ }
+ if (map.containsKey('result')) {
+ return new Message._fromJsonRpcResult(client, map);
+ }
+ if (map.containsKey('error')) {
+ return new Message._fromJsonRpcError(client, map);
+ }
+ } else if (map.containsKey('method')) {
+ return new Message._fromJsonRpcNotification(client, map);
+ }
+ throw new Exception('Invalid message format');
+ }
+
+ // http://www.jsonrpc.org/specification#request_object
+ Message._fromJsonRpcRequest(Client client, Map map)
+ : client = client,
+ type = MessageType.Request,
+ serial = map['id'],
+ method = map['method'] {
+ if (map['params'] != null) {
+ params.addAll(map['params']);
+ }
+ }
+
+ // http://www.jsonrpc.org/specification#notification
+ Message._fromJsonRpcNotification(Client client, Map map)
+ : client = client,
+ type = MessageType.Notification,
+ method = map['method'],
+ serial = null {
+ if (map['params'] != null) {
+ params.addAll(map['params']);
+ }
+ }
+
+ // http://www.jsonrpc.org/specification#response_object
+ Message._fromJsonRpcResult(Client client, Map map)
+ : client = client,
+ type = MessageType.Response,
+ serial = map['id'],
+ method = null {
+ result.addAll(map['result']);
+ }
+
+ // http://www.jsonrpc.org/specification#response_object
+ Message._fromJsonRpcError(Client client, Map map)
+ : client = client,
+ type = MessageType.Response,
+ serial = map['id'],
+ method = null {
+ error.addAll(map['error']);
+ }
+
+ static String _methodNameFromUri(Uri uri) {
+ if (uri == null) {
+ return '';
+ }
+ if (uri.pathSegments.length == 0) {
+ return '';
+ }
+ return uri.pathSegments[0];
+ }
+
+ Message.forMethod(String method)
+ : client = null,
+ method = method,
+ type = MessageType.Request,
+ serial = '';
+
+ Message.fromUri(this.client, Uri uri)
+ : type = MessageType.Request,
+ serial = '',
+ method = _methodNameFromUri(uri) {
+ params.addAll(uri.queryParameters);
+ }
+
+ Message.forIsolate(this.client, Uri uri, RunningIsolate isolate)
+ : type = MessageType.Request,
+ serial = '',
+ method = _methodNameFromUri(uri) {
+ params.addAll(uri.queryParameters);
+ params['isolateId'] = isolate.serviceId;
+ }
+
+ Uri toUri() {
+ return new Uri(path: method, queryParameters: params);
+ }
+
+ dynamic toJson() {
+ throw 'unsupported';
+ }
+
+ dynamic forwardToJson([Map overloads]) {
+ Map<dynamic, dynamic> json = {'jsonrpc': '2.0', 'id': serial};
+ switch (type) {
+ case MessageType.Request:
+ case MessageType.Notification:
+ json['method'] = method;
+ if (params.isNotEmpty) {
+ json['params'] = params;
+ }
+ break;
+ case MessageType.Response:
+ if (result.isNotEmpty) {
+ json['result'] = result;
+ }
+ if (error.isNotEmpty) {
+ json['error'] = error;
+ }
+ }
+ if (overloads != null) {
+ json.addAll(overloads);
+ }
+ return json;
+ }
+
+ // Calls toString on all non-String elements of [list]. We do this so all
+ // elements in the list are strings, making consumption by C++ simpler.
+ // This has a side effect that boolean literal values like true become 'true'
+ // and thus indistinguishable from the string literal 'true'.
+ List<String> _makeAllString(List list) {
+ if (list == null) {
+ return null;
+ }
+ var new_list = new List<String>(list.length);
+ for (var i = 0; i < list.length; i++) {
+ new_list[i] = list[i].toString();
+ }
+ return new_list;
+ }
+
+ Future<Response> sendToIsolate(SendPort sendPort) {
+ final receivePort = new RawReceivePort();
+ receivePort.handler = (value) {
+ receivePort.close();
+ _setResponseFromPort(value);
+ };
+ var keys = _makeAllString(params.keys.toList(growable: false));
+ var values = _makeAllString(params.values.toList(growable: false));
+ var request = new List(6)
+ ..[0] = 0 // Make room for OOB message type.
+ ..[1] = receivePort.sendPort
+ ..[2] = serial
+ ..[3] = method
+ ..[4] = keys
+ ..[5] = values;
+ if (!sendIsolateServiceMessage(sendPort, request)) {
+ receivePort.close();
+ _completer.complete(new Response.internalError(
+ 'could not send message [${serial}] to isolate'));
+ }
+ return _completer.future;
+ }
+
+ // We currently support two ways of passing parameters from Dart code to C
+ // code. The original way always converts the parameters to strings before
+ // passing them over. Our goal is to convert all C handlers to take the
+ // parameters as Dart objects but until the conversion is complete, we
+ // maintain the list of supported methods below.
+ bool _methodNeedsObjectParameters(String method) {
+ switch (method) {
+ case '_listDevFS':
+ case '_listDevFSFiles':
+ case '_createDevFS':
+ case '_deleteDevFS':
+ case '_writeDevFSFile':
+ case '_writeDevFSFiles':
+ case '_readDevFSFile':
+ case '_spawnUri':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ Future<Response> sendToVM() {
+ final receivePort = new RawReceivePort();
+ receivePort.handler = (value) {
+ receivePort.close();
+ _setResponseFromPort(value);
+ };
+ var keys = params.keys.toList(growable: false);
+ var values = params.values.toList(growable: false);
+ if (!_methodNeedsObjectParameters(method)) {
+ keys = _makeAllString(keys);
+ values = _makeAllString(values);
+ }
+
+ final request = new List(6)
+ ..[0] = 0 // Make room for OOB message type.
+ ..[1] = receivePort.sendPort
+ ..[2] = serial
+ ..[3] = method
+ ..[4] = keys
+ ..[5] = values;
+
+ if (_methodNeedsObjectParameters(method)) {
+ // We use a different method invocation path here.
+ sendObjectRootServiceMessage(request);
+ } else {
+ sendRootServiceMessage(request);
+ }
+
+ return _completer.future;
+ }
+
+ void _setResponseFromPort(dynamic response) {
+ if (response == null) {
+ // We should only have a null response for Notifications.
+ assert(type == MessageType.Notification);
+ return null;
+ }
+ _completer.complete(Response.from(response));
+ }
+
+ void setResponse(String response) {
+ _completer.complete(new Response(ResponsePayloadKind.String, response));
+ }
+
+ void setErrorResponse(int code, String details) {
+ setResponse(encodeRpcError(this, code, details: '$method: $details'));
+ }
+}
+
+bool sendIsolateServiceMessage(SendPort sp, List m)
+ native "VMService_SendIsolateServiceMessage";
+
+void sendRootServiceMessage(List m) native "VMService_SendRootServiceMessage";
+
+void sendObjectRootServiceMessage(List m)
+ native "VMService_SendObjectRootServiceMessage";
diff --git a/sdk_nnbd/lib/vmservice/message_router.dart b/sdk_nnbd/lib/vmservice/message_router.dart
new file mode 100644
index 0000000..4c1b307
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/message_router.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+abstract class MessageRouter {
+ Future<Response> routeRequest(VMService service, Message message);
+ void routeResponse(Message message);
+}
+
+enum ResponsePayloadKind {
+ /// Response payload is a Dart string.
+ String,
+
+ /// Response payload is a binary (Uint8List).
+ Binary,
+
+ /// Response payload is a string encoded as UTF8 bytes (Uint8List).
+ Utf8String,
+}
+
+class Response {
+ final ResponsePayloadKind kind;
+ final payload;
+
+ /// Construct response object with the given [payload] and [kind].
+ Response(this.kind, this.payload) {
+ assert(() {
+ switch (kind) {
+ case ResponsePayloadKind.String:
+ return payload is String;
+ case ResponsePayloadKind.Binary:
+ case ResponsePayloadKind.Utf8String:
+ return payload is Uint8List;
+ }
+ }());
+ }
+
+ /// Construct a string response from the given [value] by encoding it
+ /// as JSON.
+ Response.json(Object value)
+ : this(ResponsePayloadKind.String, json.encode(value));
+
+ factory Response.internalError(String message) {
+ return new Response.json({
+ 'type': 'ServiceError',
+ 'id': '',
+ 'kind': 'InternalError',
+ 'message': message,
+ });
+ }
+
+ /// Construct response from the response [value] which can be either:
+ /// String: a string
+ /// Binary: a Uint8List
+ /// Utf8String: a single element list containing Uint8List
+ factory Response.from(Object value) {
+ if (value is String) {
+ return new Response(ResponsePayloadKind.String, value);
+ } else if (value is Uint8List) {
+ return new Response(ResponsePayloadKind.Binary, value);
+ } else if (value is List) {
+ assert(value.length == 1);
+ return new Response(
+ ResponsePayloadKind.Utf8String, value[0] as Uint8List);
+ } else if (value is Response) {
+ return value;
+ } else {
+ throw 'Unrecognized response: ${value}';
+ }
+ }
+
+ /// Decode JSON contained in this response.
+ dynamic decodeJson() {
+ switch (kind) {
+ case ResponsePayloadKind.String:
+ return json.decode(payload);
+ case ResponsePayloadKind.Utf8String:
+ return json.fuse(utf8).decode(payload);
+ case ResponsePayloadKind.Binary:
+ throw 'Binary responses can not be decoded';
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/vmservice/named_lookup.dart b/sdk_nnbd/lib/vmservice/named_lookup.dart
new file mode 100644
index 0000000..7087c94
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/named_lookup.dart
@@ -0,0 +1,68 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+/// Set like containes which automatically generated String ids for its items
+class NamedLookup<E> extends Object with IterableMixin<E> {
+ final IdGenerator _generator;
+ final Map<String, E> _elements = new Map<String, E>();
+ final Map<E, String> _ids = new Map<E, String>();
+
+ NamedLookup({String prologue = ''})
+ : _generator = new IdGenerator(prologue: prologue);
+
+ void add(E e) {
+ final id = _generator.newId();
+ _elements[id] = e;
+ _ids[e] = id;
+ }
+
+ void remove(E e) {
+ final id = _ids.remove(e);
+ _elements.remove(id);
+ _generator.release(id);
+ }
+
+ E operator [](String id) => _elements[id];
+ String keyOf(E e) => _ids[e];
+
+ Iterator<E> get iterator => _ids.keys.iterator;
+}
+
+/// Generator for unique ids which recycles expired ones
+class IdGenerator {
+ /// Fixed initial part of the id
+ final String prologue;
+ // Ids in use
+ final Set<String> _used = new Set<String>();
+
+ /// Ids that has been released (use these before generate new ones)
+ final Set<String> _free = new Set<String>();
+
+ /// Next id to generate if no one can be recycled (first use _free);
+ int _next = 0;
+
+ IdGenerator({this.prologue = ''});
+
+ /// Returns a new Id (possibly recycled)
+ String newId() {
+ var id;
+ if (_free.isEmpty) {
+ id = prologue + (_next++).toString();
+ } else {
+ id = _free.first;
+ }
+ _free.remove(id);
+ _used.add(id);
+ return id;
+ }
+
+ /// Releases the id and mark it for recycle
+ void release(String id) {
+ if (_used.remove(id)) {
+ _free.add(id);
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/vmservice/running_isolate.dart b/sdk_nnbd/lib/vmservice/running_isolate.dart
new file mode 100644
index 0000000..8a6dd36
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/running_isolate.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+class RunningIsolate implements MessageRouter {
+ final int portId;
+ final SendPort sendPort;
+ final String name;
+
+ RunningIsolate(this.portId, this.sendPort, this.name);
+
+ String get serviceId => 'isolates/$portId';
+
+ @override
+ Future<Response> routeRequest(VMService service, Message message) {
+ // Send message to isolate.
+ return message.sendToIsolate(sendPort);
+ }
+
+ @override
+ void routeResponse(Message message) {}
+}
diff --git a/sdk_nnbd/lib/vmservice/running_isolates.dart b/sdk_nnbd/lib/vmservice/running_isolates.dart
new file mode 100644
index 0000000..24b155c
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/running_isolates.dart
@@ -0,0 +1,214 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._vmservice;
+
+class RunningIsolates implements MessageRouter {
+ final Map<int, RunningIsolate> isolates = new Map<int, RunningIsolate>();
+ int _rootPortId;
+
+ RunningIsolates();
+
+ void isolateStartup(int portId, SendPort sp, String name) {
+ if (_rootPortId == null) {
+ _rootPortId = portId;
+ }
+ var ri = new RunningIsolate(portId, sp, name);
+ isolates[portId] = ri;
+ }
+
+ void isolateShutdown(int portId, SendPort sp) {
+ if (_rootPortId == portId) {
+ _rootPortId = null;
+ }
+ isolates.remove(portId);
+ }
+
+ @override
+ Future<Response> routeRequest(VMService service, Message message) {
+ String isolateParam = message.params['isolateId'];
+ int isolateId;
+ if (!isolateParam.startsWith('isolates/')) {
+ message.setErrorResponse(
+ kInvalidParams, "invalid 'isolateId' parameter: $isolateParam");
+ return message.response;
+ }
+ isolateParam = isolateParam.substring('isolates/'.length);
+ if (isolateParam == 'root') {
+ isolateId = _rootPortId;
+ } else {
+ try {
+ isolateId = int.parse(isolateParam);
+ } catch (e) {
+ message.setErrorResponse(
+ kInvalidParams, "invalid 'isolateId' parameter: $isolateParam");
+ return message.response;
+ }
+ }
+ var isolate = isolates[isolateId];
+ if (isolate == null) {
+ // There is some chance that this isolate may have lived before,
+ // so return a sentinel rather than an error.
+ var result = {
+ 'type': 'Sentinel',
+ 'kind': 'Collected',
+ 'valueAsString': '<collected>',
+ };
+ message.setResponse(encodeResult(message, result));
+ return message.response;
+ }
+
+ if (message.method == 'evaluateInFrame' || message.method == 'evaluate') {
+ return new _Evaluator(message, isolate, service).run();
+ } else {
+ return isolate.routeRequest(service, message);
+ }
+ }
+
+ @override
+ void routeResponse(Message message) {}
+}
+
+/// Class that knows how to orchestrate expression evaluation in dart2 world.
+class _Evaluator {
+ _Evaluator(this._message, this._isolate, this._service);
+
+ Future<Response> run() async {
+ Response buildScopeResponse = await _buildScope();
+ Map<String, dynamic> responseJson = buildScopeResponse.decodeJson();
+
+ if (responseJson.containsKey('error')) {
+ return new Response.from(encodeCompilationError(
+ _message, responseJson['error']['data']['details']));
+ }
+
+ String kernelBase64;
+ try {
+ kernelBase64 = await _compileExpression(responseJson['result']);
+ } catch (e) {
+ return new Response.from(encodeCompilationError(_message, e.toString()));
+ }
+ return _evaluateCompiledExpression(kernelBase64);
+ }
+
+ Message _message;
+ RunningIsolate _isolate;
+ VMService _service;
+
+ Future<Response> _buildScope() {
+ Map<String, dynamic> params = _setupParams();
+ params['isolateId'] = _message.params['isolateId'];
+ Map buildScopeParams = {
+ 'method': '_buildExpressionEvaluationScope',
+ 'id': _message.serial,
+ 'params': params,
+ };
+ if (_message.params['scope'] != null) {
+ buildScopeParams['params']['scope'] = _message.params['scope'];
+ }
+ var buildScope =
+ new Message._fromJsonRpcRequest(_message.client, buildScopeParams);
+
+ // Decode the JSON and and insert it into the map. The map key
+ // is the request Uri.
+ return _isolate.routeRequest(_service, buildScope);
+ }
+
+ Future<String> _compileExpression(
+ Map<String, dynamic> buildScopeResponseResult) {
+ Client externalClient =
+ _service._findFirstClientThatHandlesService('compileExpression');
+
+ Map compileParams = {
+ 'isolateId': _message.params['isolateId'],
+ 'expression': _message.params['expression'],
+ 'definitions': buildScopeResponseResult['param_names'],
+ 'typeDefinitions': buildScopeResponseResult['type_params_names'],
+ 'libraryUri': buildScopeResponseResult['libraryUri'],
+ 'isStatic': buildScopeResponseResult['isStatic'],
+ };
+ dynamic klass = buildScopeResponseResult['klass'];
+ if (klass != null) {
+ compileParams['klass'] = klass;
+ }
+ if (externalClient != null) {
+ var compileExpression = new Message.forMethod('compileExpression');
+ compileExpression.client = externalClient;
+ compileExpression.params.addAll(compileParams);
+
+ final id = _service._serviceRequests.newId();
+ final oldId = _message.serial;
+ final completer = new Completer<String>();
+ externalClient.serviceHandles[id] = (Message m) {
+ if (m != null) {
+ completer.complete(json.encode(m.forwardToJson({'id': oldId})));
+ } else {
+ completer.complete(encodeRpcError(_message, kServiceDisappeared));
+ }
+ };
+ externalClient.post(new Response.json(compileExpression
+ .forwardToJson({'id': id, 'method': 'compileExpression'})));
+ return completer.future
+ .then((String s) => jsonDecode(s))
+ .then((dynamic json) {
+ Map<String, dynamic> jsonMap = json;
+ if (jsonMap.containsKey('error')) {
+ throw jsonMap['error'];
+ }
+ return jsonMap['result']['result']['kernelBytes'];
+ });
+ } else {
+ // fallback to compile using kernel service
+ Map compileExpressionParams = {
+ 'method': '_compileExpression',
+ 'id': _message.serial,
+ 'params': compileParams,
+ };
+ var compileExpression = new Message._fromJsonRpcRequest(
+ _message.client, compileExpressionParams);
+
+ return _isolate
+ .routeRequest(_service, compileExpression)
+ .then((Response response) => response.decodeJson())
+ .then((dynamic json) {
+ if (json['result'] != null) {
+ return json['result']['kernelBytes'];
+ }
+ throw json['error']['data']['details'];
+ });
+ }
+ }
+
+ Future<Response> _evaluateCompiledExpression(String kernelBase64) {
+ if (kernelBase64.isNotEmpty) {
+ Map<String, dynamic> params = _setupParams();
+ params['isolateId'] = _message.params['isolateId'];
+ params['kernelBytes'] = kernelBase64;
+ params['disableBreakpoints'] = _message.params['disableBreakpoints'];
+ Map runParams = {
+ 'method': '_evaluateCompiledExpression',
+ 'id': _message.serial,
+ 'params': params,
+ };
+ if (_message.params['scope'] != null) {
+ runParams['params']['scope'] = _message.params['scope'];
+ }
+ var runExpression =
+ new Message._fromJsonRpcRequest(_message.client, runParams);
+ return _isolate.routeRequest(_service, runExpression); // _message
+ } else {
+ // empty kernel indicates dart1 mode
+ return _isolate.routeRequest(_service, _message);
+ }
+ }
+
+ Map<String, dynamic> _setupParams() {
+ if (_message.method == 'evaluateInFrame') {
+ return <String, dynamic>{'frameIndex': _message.params['frameIndex']};
+ } else {
+ assert(_message.method == 'evaluate');
+ return <String, dynamic>{'targetId': _message.params['targetId']};
+ }
+ }
+}
diff --git a/sdk_nnbd/lib/vmservice/vmservice.dart b/sdk_nnbd/lib/vmservice/vmservice.dart
new file mode 100644
index 0000000..0c340ee
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/vmservice.dart
@@ -0,0 +1,683 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart._vmservice;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:convert';
+import 'dart:isolate';
+import 'dart:math';
+import 'dart:typed_data';
+
+part 'asset.dart';
+part 'client.dart';
+part 'devfs.dart';
+part 'constants.dart';
+part 'running_isolate.dart';
+part 'running_isolates.dart';
+part 'message.dart';
+part 'message_router.dart';
+part 'named_lookup.dart';
+
+final RawReceivePort isolateControlPort = new RawReceivePort();
+final RawReceivePort scriptLoadPort = new RawReceivePort();
+
+abstract class IsolateEmbedderData {
+ void cleanup();
+}
+
+String _makeAuthToken() {
+ final kTokenByteSize = 8;
+ Uint8List bytes = new Uint8List(kTokenByteSize);
+ Random random = new Random.secure();
+ for (int i = 0; i < kTokenByteSize; i++) {
+ bytes[i] = random.nextInt(256);
+ }
+ return base64Url.encode(bytes);
+}
+
+// The randomly generated auth token used to access the VM service.
+final String serviceAuthToken = _makeAuthToken();
+
+// This is for use by the embedder. It is a map from the isolateId to
+// anything implementing IsolateEmbedderData. When an isolate goes away,
+// the cleanup method will be invoked after being removed from the map.
+final Map<int, IsolateEmbedderData> isolateEmbedderData =
+ new Map<int, IsolateEmbedderData>();
+
+// These must be kept in sync with the declarations in vm/json_stream.h.
+const kParseError = -32700;
+const kInvalidRequest = -32600;
+const kMethodNotFound = -32601;
+const kInvalidParams = -32602;
+const kInternalError = -32603;
+
+const kExtensionError = -32000;
+
+const kFeatureDisabled = 100;
+const kCannotAddBreakpoint = 102;
+const kStreamAlreadySubscribed = 103;
+const kStreamNotSubscribed = 104;
+const kIsolateMustBeRunnable = 105;
+const kIsolateMustBePaused = 106;
+const kCannotResume = 107;
+const kIsolateIsReloading = 108;
+const kIsolateReloadBarred = 109;
+const kIsolateMustHaveReloaded = 110;
+const kServiceAlreadyRegistered = 111;
+const kServiceDisappeared = 112;
+const kExpressionCompilationError = 113;
+const kInvalidTimelineRequest = 114;
+
+// Experimental (used in private rpcs).
+const kFileSystemAlreadyExists = 1001;
+const kFileSystemDoesNotExist = 1002;
+const kFileDoesNotExist = 1003;
+
+var _errorMessages = {
+ kInvalidParams: 'Invalid params',
+ kInternalError: 'Internal error',
+ kFeatureDisabled: 'Feature is disabled',
+ kStreamAlreadySubscribed: 'Stream already subscribed',
+ kStreamNotSubscribed: 'Stream not subscribed',
+ kFileSystemAlreadyExists: 'File system already exists',
+ kFileSystemDoesNotExist: 'File system does not exist',
+ kFileDoesNotExist: 'File does not exist',
+ kServiceAlreadyRegistered: 'Service already registered',
+ kServiceDisappeared: 'Service has disappeared',
+ kExpressionCompilationError: 'Expression compilation error',
+ kInvalidTimelineRequest: 'The timeline related request could not be completed'
+ 'due to the current configuration',
+};
+
+String encodeRpcError(Message message, int code, {String details}) {
+ var response = {
+ 'jsonrpc': '2.0',
+ 'id': message.serial,
+ 'error': {
+ 'code': code,
+ 'message': _errorMessages[code],
+ },
+ };
+ if (details != null) {
+ response['error']['data'] = {
+ 'details': details,
+ };
+ }
+ return json.encode(response);
+}
+
+String encodeMissingParamError(Message message, String param) {
+ return encodeRpcError(message, kInvalidParams,
+ details: "${message.method} expects the '${param}' parameter");
+}
+
+String encodeInvalidParamError(Message message, String param) {
+ var value = message.params[param];
+ return encodeRpcError(message, kInvalidParams,
+ details: "${message.method}: invalid '${param}' parameter: ${value}");
+}
+
+String encodeCompilationError(Message message, String diagnostic) {
+ return encodeRpcError(message, kExpressionCompilationError,
+ details: diagnostic);
+}
+
+String encodeResult(Message message, Map result) {
+ var response = {
+ 'jsonrpc': '2.0',
+ 'id': message.serial,
+ 'result': result,
+ };
+ return json.encode(response);
+}
+
+String encodeSuccess(Message message) {
+ return encodeResult(message, {'type': 'Success'});
+}
+
+const shortDelay = const Duration(milliseconds: 10);
+
+/// Called when the server should be started.
+typedef Future ServerStartCallback();
+
+/// Called when the server should be stopped.
+typedef Future ServerStopCallback();
+
+/// Called when the service is exiting.
+typedef Future CleanupCallback();
+
+/// Called to create a temporary directory
+typedef Future<Uri> CreateTempDirCallback(String base);
+
+/// Called to delete a directory
+typedef Future DeleteDirCallback(Uri path);
+
+/// Called to write a file.
+typedef Future WriteFileCallback(Uri path, List<int> bytes);
+
+/// Called to write a stream into a file.
+typedef Future WriteStreamFileCallback(Uri path, Stream<List<int>> bytes);
+
+/// Called to read a file.
+typedef Future<List<int>> ReadFileCallback(Uri path);
+
+/// Called to list all files under some path.
+typedef Future<List<Map<String, dynamic>>> ListFilesCallback(Uri path);
+
+/// Called when we need information about the server.
+typedef Future<Uri> ServerInformamessage_routertionCallback();
+
+/// Called when we need information about the server.
+typedef Future<Uri> ServerInformationCallback();
+
+/// Called when we want to [enable] or disable the web server.
+typedef Future<Uri> WebServerControlCallback(bool enable);
+
+/// Hooks that are setup by the embedder.
+class VMServiceEmbedderHooks {
+ static ServerStartCallback serverStart;
+ static ServerStopCallback serverStop;
+ static CleanupCallback cleanup;
+ static CreateTempDirCallback createTempDir;
+ static DeleteDirCallback deleteDir;
+ static WriteFileCallback writeFile;
+ static WriteStreamFileCallback writeStreamFile;
+ static ReadFileCallback readFile;
+ static ListFilesCallback listFiles;
+ static ServerInformationCallback serverInformation;
+ static WebServerControlCallback webServerControl;
+}
+
+class VMService extends MessageRouter {
+ static VMService _instance;
+
+ static const serviceNamespace = 's';
+
+ /// Collection of currently connected clients.
+ final NamedLookup<Client> clients =
+ new NamedLookup<Client>(prologue: serviceNamespace);
+ final IdGenerator _serviceRequests = new IdGenerator(prologue: 'sr');
+
+ /// Collection of currently running isolates.
+ RunningIsolates runningIsolates = new RunningIsolates();
+
+ /// Flag to indicate VM service is exiting.
+ bool isExiting = false;
+
+ /// A port used to receive events from the VM.
+ final RawReceivePort eventPort;
+
+ final devfs = new DevFS();
+
+ void _addClient(Client client) {
+ assert(client.streams.isEmpty);
+ assert(client.services.isEmpty);
+ clients.add(client);
+ }
+
+ void _removeClient(Client client) {
+ final namespace = clients.keyOf(client);
+ clients.remove(client);
+ for (var streamId in client.streams) {
+ if (!_isAnyClientSubscribed(streamId)) {
+ _vmCancelStream(streamId);
+ }
+ }
+ for (var service in client.services.keys) {
+ _eventMessageHandler(
+ 'Service',
+ new Response.json({
+ 'jsonrpc': '2.0',
+ 'method': 'streamNotify',
+ 'params': {
+ 'streamId': 'Service',
+ 'event': {
+ "type": "Event",
+ "kind": "ServiceUnregistered",
+ 'timestamp': new DateTime.now().millisecondsSinceEpoch,
+ 'service': service,
+ 'method': namespace + '.' + service,
+ }
+ }
+ }));
+ }
+ // Complete all requests as failed
+ for (var handle in client.serviceHandles.values) {
+ handle(null);
+ }
+ }
+
+ void _eventMessageHandler(String streamId, Response event) {
+ for (var client in clients) {
+ if (client.sendEvents && client.streams.contains(streamId)) {
+ client.post(event);
+ }
+ }
+ }
+
+ void _controlMessageHandler(int code, int portId, SendPort sp, String name) {
+ switch (code) {
+ case Constants.ISOLATE_STARTUP_MESSAGE_ID:
+ runningIsolates.isolateStartup(portId, sp, name);
+ break;
+ case Constants.ISOLATE_SHUTDOWN_MESSAGE_ID:
+ runningIsolates.isolateShutdown(portId, sp);
+ IsolateEmbedderData ied = isolateEmbedderData.remove(portId);
+ if (ied != null) {
+ ied.cleanup();
+ }
+ break;
+ }
+ }
+
+ Future<Null> _serverMessageHandler(int code, SendPort sp, bool enable) async {
+ switch (code) {
+ case Constants.WEB_SERVER_CONTROL_MESSAGE_ID:
+ if (VMServiceEmbedderHooks.webServerControl == null) {
+ sp.send(null);
+ return;
+ }
+ Uri uri = await VMServiceEmbedderHooks.webServerControl(enable);
+ sp.send(uri);
+ break;
+ case Constants.SERVER_INFO_MESSAGE_ID:
+ if (VMServiceEmbedderHooks.serverInformation == null) {
+ sp.send(null);
+ return;
+ }
+ Uri uri = await VMServiceEmbedderHooks.serverInformation();
+ sp.send(uri);
+ break;
+ }
+ }
+
+ Future<Null> _handleNativeRpcCall(message, SendPort replyPort) async {
+ // Keep in sync with "runtime/vm/service_isolate.cc:InvokeServiceRpc".
+ Response response;
+
+ try {
+ final Message rpc = new Message.fromJsonRpc(
+ null, json.decode(utf8.decode(message as List<int>)));
+ if (rpc.type != MessageType.Request) {
+ response = new Response.internalError(
+ 'The client sent a non-request json-rpc message.');
+ } else {
+ response = await routeRequest(this, rpc);
+ }
+ } catch (exception) {
+ response = new Response.internalError(
+ 'The rpc call resulted in exception: $exception.');
+ }
+ List<int> bytes;
+ switch (response.kind) {
+ case ResponsePayloadKind.String:
+ bytes = utf8.encode(response.payload);
+ bytes = bytes is Uint8List ? bytes : new Uint8List.fromList(bytes);
+ break;
+ case ResponsePayloadKind.Binary:
+ case ResponsePayloadKind.Utf8String:
+ bytes = response.payload as Uint8List;
+ break;
+ }
+ replyPort.send(bytes);
+ }
+
+ Future _exit() async {
+ isExiting = true;
+
+ // Stop the server.
+ if (VMServiceEmbedderHooks.serverStop != null) {
+ await VMServiceEmbedderHooks.serverStop();
+ }
+
+ // Close receive ports.
+ isolateControlPort.close();
+ scriptLoadPort.close();
+
+ // Create a copy of the set as a list because client.disconnect() will
+ // alter the connected clients set.
+ var clientsList = clients.toList();
+ for (var client in clientsList) {
+ client.disconnect();
+ }
+ devfs.cleanup();
+ if (VMServiceEmbedderHooks.cleanup != null) {
+ await VMServiceEmbedderHooks.cleanup();
+ }
+
+ // Notify the VM that we have exited.
+ _onExit();
+ }
+
+ void messageHandler(message) {
+ if (message is List) {
+ if (message.length == 2) {
+ // This is an event.
+ _eventMessageHandler(message[0], new Response.from(message[1]));
+ return;
+ }
+ if (message.length == 1) {
+ // This is a control message directing the vm service to exit.
+ assert(message[0] == Constants.SERVICE_EXIT_MESSAGE_ID);
+ _exit();
+ return;
+ }
+ if (message.length == 3) {
+ final opcode = message[0];
+ if (opcode == Constants.METHOD_CALL_FROM_NATIVE) {
+ _handleNativeRpcCall(message[1], message[2]);
+ return;
+ } else {
+ // This is a message interacting with the web server.
+ assert((opcode == Constants.WEB_SERVER_CONTROL_MESSAGE_ID) ||
+ (opcode == Constants.SERVER_INFO_MESSAGE_ID));
+ _serverMessageHandler(message[0], message[1], message[2]);
+ return;
+ }
+ }
+ if (message.length == 4) {
+ // This is a message informing us of the birth or death of an
+ // isolate.
+ _controlMessageHandler(message[0], message[1], message[2], message[3]);
+ return;
+ }
+ }
+ print('Internal vm-service error: ignoring illegal message: $message');
+ }
+
+ VMService._internal() : eventPort = isolateControlPort {
+ eventPort.handler = messageHandler;
+ }
+
+ factory VMService() {
+ if (VMService._instance == null) {
+ VMService._instance = new VMService._internal();
+ _onStart();
+ }
+ return _instance;
+ }
+
+ bool _isAnyClientSubscribed(String streamId) {
+ for (var client in clients) {
+ if (client.streams.contains(streamId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Client _findFirstClientThatHandlesService(String service) {
+ if (clients != null) {
+ for (Client c in clients) {
+ if (c.services.containsKey(service)) {
+ return c;
+ }
+ }
+ }
+ return null;
+ }
+
+ static const kServiceStream = 'Service';
+ static const serviceStreams = const [kServiceStream];
+
+ Future<String> _streamListen(Message message) async {
+ var client = message.client;
+ var streamId = message.params['streamId'];
+
+ if (client.streams.contains(streamId)) {
+ return encodeRpcError(message, kStreamAlreadySubscribed);
+ }
+ if (!_isAnyClientSubscribed(streamId)) {
+ if (!serviceStreams.contains(streamId) && !_vmListenStream(streamId)) {
+ return encodeRpcError(message, kInvalidParams,
+ details: "streamListen: invalid 'streamId' parameter: ${streamId}");
+ }
+ }
+
+ // Some streams can generate events or side effects after registration
+ switch (streamId) {
+ case kServiceStream:
+ for (Client c in clients) {
+ if (c == client) continue;
+ for (String service in c.services.keys) {
+ _sendServiceRegisteredEvent(c, service, target: client);
+ }
+ }
+ ;
+ break;
+ }
+
+ client.streams.add(streamId);
+ return encodeSuccess(message);
+ }
+
+ Future<String> _streamCancel(Message message) async {
+ var client = message.client;
+ var streamId = message.params['streamId'];
+
+ if (!client.streams.contains(streamId)) {
+ return encodeRpcError(message, kStreamNotSubscribed);
+ }
+ client.streams.remove(streamId);
+ if (!serviceStreams.contains(streamId) &&
+ !_isAnyClientSubscribed(streamId)) {
+ _vmCancelStream(streamId);
+ }
+
+ return encodeSuccess(message);
+ }
+
+ static bool _hasNamespace(String method) =>
+ method.contains('.') &&
+ _getNamespace(method).startsWith(serviceNamespace);
+ static String _getNamespace(String method) => method.split('.').first;
+ static String _getMethod(String method) => method.split('.').last;
+
+ Future<String> _registerService(Message message) async {
+ final client = message.client;
+ final service = message.params['service'];
+ final alias = message.params['alias'];
+
+ if (service is! String || service == '') {
+ return encodeRpcError(message, kInvalidParams,
+ details: "registerService: invalid 'service' parameter: ${service}");
+ }
+ if (alias is! String || alias == '') {
+ return encodeRpcError(message, kInvalidParams,
+ details: "registerService: invalid 'alias' parameter: ${alias}");
+ }
+ if (client.services.containsKey(service)) {
+ return encodeRpcError(message, kServiceAlreadyRegistered);
+ }
+ client.services[service] = alias;
+
+ bool removed;
+ try {
+ // Do not send streaming events to the client which registers the service
+ removed = client.streams.remove(kServiceStream);
+ await _sendServiceRegisteredEvent(client, service);
+ } finally {
+ if (removed) client.streams.add(kServiceStream);
+ }
+
+ return encodeSuccess(message);
+ }
+
+ _sendServiceRegisteredEvent(Client client, String service,
+ {Client target}) async {
+ final namespace = clients.keyOf(client);
+ final alias = client.services[service];
+ final event = new Response.json({
+ 'jsonrpc': '2.0',
+ 'method': 'streamNotify',
+ 'params': {
+ 'streamId': kServiceStream,
+ 'event': {
+ "type": "Event",
+ "kind": "ServiceRegistered",
+ 'timestamp': new DateTime.now().millisecondsSinceEpoch,
+ 'service': service,
+ 'method': namespace + '.' + service,
+ 'alias': alias
+ }
+ }
+ });
+ if (target == null) {
+ _eventMessageHandler(kServiceStream, event);
+ } else {
+ target.post(event);
+ }
+ }
+
+ Future<String> _handleService(Message message) async {
+ final namespace = _getNamespace(message.method);
+ final method = _getMethod(message.method);
+ final client = clients[namespace];
+ if (client != null) {
+ if (client.services.containsKey(method)) {
+ final id = _serviceRequests.newId();
+ final oldId = message.serial;
+ final completer = new Completer<String>();
+ client.serviceHandles[id] = (Message m) {
+ if (m != null) {
+ completer.complete(json.encode(m.forwardToJson({'id': oldId})));
+ } else {
+ completer.complete(encodeRpcError(message, kServiceDisappeared));
+ }
+ };
+ client.post(new Response.json(
+ message.forwardToJson({'id': id, 'method': method})));
+ return completer.future;
+ }
+ }
+ return encodeRpcError(message, kMethodNotFound,
+ details: "Unknown service: ${message.method}");
+ }
+
+ Future<String> _spawnUri(Message message) async {
+ var token = message.params['token'];
+ if (token == null) {
+ return encodeMissingParamError(message, 'token');
+ }
+ if (token is! String) {
+ return encodeInvalidParamError(message, 'token');
+ }
+ var uri = message.params['uri'];
+ if (uri == null) {
+ return encodeMissingParamError(message, 'uri');
+ }
+ if (uri is! String) {
+ return encodeInvalidParamError(message, 'uri');
+ }
+ var args = message.params['args'];
+ var argsOfString = new List<String>();
+ if (args != null) {
+ if (args is! List) {
+ return encodeInvalidParamError(message, 'args');
+ }
+ for (var arg in args) {
+ if (arg is! String) {
+ return encodeInvalidParamError(message, 'args');
+ }
+ argsOfString.add(arg);
+ }
+ }
+ var msg = message.params['message'];
+
+ Isolate.spawnUri(Uri.parse(uri), argsOfString, msg).then((isolate) {
+ _spawnUriNotify(isolate.controlPort, token);
+ }).catchError((e) {
+ _spawnUriNotify(e.toString(), token);
+ });
+
+ return encodeSuccess(message);
+ }
+
+ Future<Response> routeRequest(VMService _, Message message) async {
+ final response = await _routeRequestImpl(message);
+ if (response == null) {
+ // We should only have a null response for Notifications.
+ assert(message.type == MessageType.Notification);
+ return null;
+ }
+ return new Response.from(response);
+ }
+
+ Future _routeRequestImpl(Message message) async {
+ try {
+ if (message.completed) {
+ return await message.response;
+ }
+ if (message.method == 'streamListen') {
+ return await _streamListen(message);
+ }
+ if (message.method == 'streamCancel') {
+ return await _streamCancel(message);
+ }
+ if (message.method == 'registerService') {
+ return await _registerService(message);
+ }
+ if (message.method == '_spawnUri') {
+ return await _spawnUri(message);
+ }
+ if (devfs.shouldHandleMessage(message)) {
+ return await devfs.handleMessage(message);
+ }
+ if (_hasNamespace(message.method)) {
+ return await _handleService(message);
+ }
+ if (message.params['isolateId'] != null) {
+ return await runningIsolates.routeRequest(this, message);
+ }
+ return await message.sendToVM();
+ } catch (e, st) {
+ message.setErrorResponse(kInternalError, 'Unexpected exception:$e\n$st');
+ return message.response;
+ }
+ }
+
+ void routeResponse(message) {
+ final client = message.client;
+ if (client.serviceHandles.containsKey(message.serial)) {
+ client.serviceHandles.remove(message.serial)(message);
+ _serviceRequests.release(message.serial);
+ }
+ }
+}
+
+@pragma("vm:entry-point", "call")
+RawReceivePort boot() {
+ // Return the port we expect isolate control messages on.
+ return isolateControlPort;
+}
+
+@pragma("vm:entry-point", !const bool.fromEnvironment("dart.vm.product"))
+void _registerIsolate(int port_id, SendPort sp, String name) {
+ var service = new VMService();
+ service.runningIsolates.isolateStartup(port_id, sp, name);
+}
+
+/// Notify the VM that the service is running.
+void _onStart() native "VMService_OnStart";
+
+/// Notify the VM that the service is no longer running.
+void _onExit() native "VMService_OnExit";
+
+/// Notify the VM that the server's address has changed.
+void onServerAddressChange(String address)
+ native "VMService_OnServerAddressChange";
+
+/// Subscribe to a service stream.
+bool _vmListenStream(String streamId) native "VMService_ListenStream";
+
+/// Cancel a subscription to a service stream.
+void _vmCancelStream(String streamId) native "VMService_CancelStream";
+
+/// Get the bytes to the tar archive.
+Uint8List _requestAssets() native "VMService_RequestAssets";
+
+/// Notify the vm service that an isolate has been spawned via rpc.
+void _spawnUriNotify(obj, String token) native "VMService_spawnUriNotify";
diff --git a/sdk_nnbd/lib/vmservice/vmservice_sources.gni b/sdk_nnbd/lib/vmservice/vmservice_sources.gni
new file mode 100644
index 0000000..b8cf5bf
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice/vmservice_sources.gni
@@ -0,0 +1,19 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Sources that make up the library "dart:_vmservice".
+vmservice_sdk_sources = [
+ "vmservice.dart",
+
+ # The above file needs to be first as it imports required libraries.
+ "asset.dart",
+ "client.dart",
+ "constants.dart",
+ "devfs.dart",
+ "running_isolate.dart",
+ "running_isolates.dart",
+ "message.dart",
+ "message_router.dart",
+ "named_lookup.dart",
+]
diff --git a/sdk_nnbd/lib/vmservice_libraries.json b/sdk_nnbd/lib/vmservice_libraries.json
new file mode 100644
index 0000000..c25ffe5
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice_libraries.json
@@ -0,0 +1,12 @@
+{
+ "vm": {
+ "libraries": {
+ "vmservice_io": {
+ "uri": "../../runtime/bin/vmservice/vmservice_io.dart"
+ },
+ "_vmservice": {
+ "uri": "vmservice/vmservice.dart"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/sdk_nnbd/lib/vmservice_libraries.yaml b/sdk_nnbd/lib/vmservice_libraries.yaml
new file mode 100644
index 0000000..737e361
--- /dev/null
+++ b/sdk_nnbd/lib/vmservice_libraries.yaml
@@ -0,0 +1,20 @@
+# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Note: if you edit this file, you must also edit libraries.json in this
+# directory:
+#
+# python ./tools/yaml2json.py sdk/lib/vmservice_libraries.yaml sdk/lib/vmservice_libraries.json
+#
+# We currently have several different files that needs to be updated when
+# changing libraries, sources, and patch files. See
+# https://github.com/dart-lang/sdk/issues/28836.
+
+vm:
+ libraries:
+ _vmservice:
+ uri: "vmservice/vmservice.dart"
+
+ vmservice_io:
+ uri: "../../runtime/bin/vmservice/vmservice_io.dart"
diff --git a/sdk_nnbd/lib/wasm/wasm.dart b/sdk_nnbd/lib/wasm/wasm.dart
new file mode 100644
index 0000000..edf0887
--- /dev/null
+++ b/sdk_nnbd/lib/wasm/wasm.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// {@category VM}
+/// {@nodoc}
+library dart.wasm;
+
+int callWasm(String name, int arg) {
+ return _callWasm(name, arg);
+}
+
+external int _callWasm(String name, int arg);
diff --git a/sdk_nnbd/lib/wasm/wasm_sources.gni b/sdk_nnbd/lib/wasm/wasm_sources.gni
new file mode 100644
index 0000000..dcd359a
--- /dev/null
+++ b/sdk_nnbd/lib/wasm/wasm_sources.gni
@@ -0,0 +1,7 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+wasm_sdk_sources = [
+ "wasm.dart",
+]
diff --git a/sdk_nnbd/lib/web_audio/dart2js/web_audio_dart2js.dart b/sdk_nnbd/lib/web_audio/dart2js/web_audio_dart2js.dart
new file mode 100644
index 0000000..ef2ee67
--- /dev/null
+++ b/sdk_nnbd/lib/web_audio/dart2js/web_audio_dart2js.dart
@@ -0,0 +1,1246 @@
+/**
+ * High-fidelity audio programming in the browser.
+ *
+ * {@category Web}
+ */
+library dart.dom.web_audio;
+
+import 'dart:async';
+import 'dart:collection' hide LinkedList, LinkedListEntry;
+import 'dart:_internal' show FixedLengthListMixin;
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:_native_typed_data';
+import 'dart:typed_data';
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show Interceptor;
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:audio library.
+
+import 'dart:_js_helper'
+ show
+ Creates,
+ JavaScriptIndexingBehavior,
+ JSName,
+ Native,
+ Returns,
+ convertDartClosureToJS;
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AnalyserNode,RealtimeAnalyserNode")
+class AnalyserNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory AnalyserNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AnalyserNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return AnalyserNode._create_1(context, options_1);
+ }
+ return AnalyserNode._create_2(context);
+ }
+ static AnalyserNode _create_1(context, options) =>
+ JS('AnalyserNode', 'new AnalyserNode(#,#)', context, options);
+ static AnalyserNode _create_2(context) =>
+ JS('AnalyserNode', 'new AnalyserNode(#)', context);
+
+ int fftSize;
+
+ final int frequencyBinCount;
+
+ num maxDecibels;
+
+ num minDecibels;
+
+ num smoothingTimeConstant;
+
+ void getByteFrequencyData(Uint8List array) native;
+
+ void getByteTimeDomainData(Uint8List array) native;
+
+ void getFloatFrequencyData(Float32List array) native;
+
+ void getFloatTimeDomainData(Float32List array) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioBuffer")
+class AudioBuffer extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AudioBuffer._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AudioBuffer(Map options) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return AudioBuffer._create_1(options_1);
+ }
+ static AudioBuffer _create_1(options) =>
+ JS('AudioBuffer', 'new AudioBuffer(#)', options);
+
+ final num duration;
+
+ final int length;
+
+ final int numberOfChannels;
+
+ final num sampleRate;
+
+ void copyFromChannel(Float32List destination, int channelNumber,
+ [int startInChannel]) native;
+
+ void copyToChannel(Float32List source, int channelNumber,
+ [int startInChannel]) native;
+
+ Float32List getChannelData(int channelIndex) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@Native("AudioBufferSourceNode")
+class AudioBufferSourceNode extends AudioScheduledSourceNode {
+ // To suppress missing implicit constructor warnings.
+ factory AudioBufferSourceNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AudioBufferSourceNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return AudioBufferSourceNode._create_1(context, options_1);
+ }
+ return AudioBufferSourceNode._create_2(context);
+ }
+ static AudioBufferSourceNode _create_1(context, options) => JS(
+ 'AudioBufferSourceNode',
+ 'new AudioBufferSourceNode(#,#)',
+ context,
+ options);
+ static AudioBufferSourceNode _create_2(context) =>
+ JS('AudioBufferSourceNode', 'new AudioBufferSourceNode(#)', context);
+
+ AudioBuffer buffer;
+
+ final AudioParam detune;
+
+ bool loop;
+
+ num loopEnd;
+
+ num loopStart;
+
+ final AudioParam playbackRate;
+
+ void start([num when, num grainOffset, num grainDuration]) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@Native("AudioContext,webkitAudioContext")
+class AudioContext extends BaseAudioContext {
+ // To suppress missing implicit constructor warnings.
+ factory AudioContext._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported =>
+ JS('bool', '!!(window.AudioContext || window.webkitAudioContext)');
+
+ final num baseLatency;
+
+ Future close() => promiseToFuture(JS("", "#.close()", this));
+
+ Map getOutputTimestamp() {
+ return convertNativeToDart_Dictionary(_getOutputTimestamp_1());
+ }
+
+ @JSName('getOutputTimestamp')
+ _getOutputTimestamp_1() native;
+
+ Future suspend() => promiseToFuture(JS("", "#.suspend()", this));
+
+ factory AudioContext() => JS('AudioContext',
+ 'new (window.AudioContext || window.webkitAudioContext)()');
+
+ GainNode createGain() {
+ if (JS('bool', '#.createGain !== undefined', this)) {
+ return JS('GainNode', '#.createGain()', this);
+ } else {
+ return JS('GainNode', '#.createGainNode()', this);
+ }
+ }
+
+ ScriptProcessorNode createScriptProcessor(
+ [int bufferSize, int numberOfInputChannels, int numberOfOutputChannels]) {
+ var function = JS(
+ '=Object',
+ '#.createScriptProcessor || '
+ '#.createJavaScriptNode',
+ this,
+ this);
+ if (numberOfOutputChannels != null) {
+ return JS('ScriptProcessorNode', '#.call(#, #, #, #)', function, this,
+ bufferSize, numberOfInputChannels, numberOfOutputChannels);
+ } else if (numberOfInputChannels != null) {
+ return JS('ScriptProcessorNode', '#.call(#, #, #)', function, this,
+ bufferSize, numberOfInputChannels);
+ } else if (bufferSize != null) {
+ return JS(
+ 'ScriptProcessorNode', '#.call(#, #)', function, this, bufferSize);
+ } else {
+ return JS('ScriptProcessorNode', '#.call(#)', function, this);
+ }
+ }
+
+ @JSName('decodeAudioData')
+ Future _decodeAudioData(ByteBuffer audioData,
+ [DecodeSuccessCallback successCallback,
+ DecodeErrorCallback errorCallback]) native;
+
+ Future<AudioBuffer> decodeAudioData(ByteBuffer audioData,
+ [DecodeSuccessCallback successCallback,
+ DecodeErrorCallback errorCallback]) {
+ if (successCallback != null && errorCallback != null) {
+ return _decodeAudioData(audioData, successCallback, errorCallback);
+ }
+
+ var completer = new Completer<AudioBuffer>();
+ _decodeAudioData(audioData, (value) {
+ completer.complete(value);
+ }, (error) {
+ if (error == null) {
+ completer.completeError('');
+ } else {
+ completer.completeError(error);
+ }
+ });
+ return completer.future;
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioDestinationNode")
+class AudioDestinationNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory AudioDestinationNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int maxChannelCount;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioListener")
+class AudioListener extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AudioListener._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final AudioParam forwardX;
+
+ final AudioParam forwardY;
+
+ final AudioParam forwardZ;
+
+ final AudioParam positionX;
+
+ final AudioParam positionY;
+
+ final AudioParam positionZ;
+
+ final AudioParam upX;
+
+ final AudioParam upY;
+
+ final AudioParam upZ;
+
+ void setOrientation(num x, num y, num z, num xUp, num yUp, num zUp) native;
+
+ void setPosition(num x, num y, num z) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioNode")
+class AudioNode extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory AudioNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int channelCount;
+
+ String channelCountMode;
+
+ String channelInterpretation;
+
+ final BaseAudioContext context;
+
+ final int numberOfInputs;
+
+ final int numberOfOutputs;
+
+ @JSName('connect')
+ AudioNode _connect(destination, [int output, int input]) native;
+
+ void disconnect([destination_OR_output, int output, int input]) native;
+
+ void connectNode(AudioNode destination, [int output = 0, int input = 0]) {
+ _connect(destination, output, input);
+ }
+
+ void connectParam(AudioParam destination, [int output = 0]) {
+ _connect(destination, output);
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioParam")
+class AudioParam extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AudioParam._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num defaultValue;
+
+ final num maxValue;
+
+ final num minValue;
+
+ num value;
+
+ AudioParam cancelAndHoldAtTime(num startTime) native;
+
+ AudioParam cancelScheduledValues(num startTime) native;
+
+ AudioParam exponentialRampToValueAtTime(num value, num time) native;
+
+ AudioParam linearRampToValueAtTime(num value, num time) native;
+
+ AudioParam setTargetAtTime(num target, num time, num timeConstant) native;
+
+ AudioParam setValueAtTime(num value, num time) native;
+
+ AudioParam setValueCurveAtTime(List<num> values, num time, num duration)
+ native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioParamMap")
+class AudioParamMap extends Interceptor with MapMixin<String, dynamic> {
+ // To suppress missing implicit constructor warnings.
+ factory AudioParamMap._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Map _getItem(String key) =>
+ convertNativeToDart_Dictionary(JS('', '#.get(#)', this, key));
+
+ void addAll(Map<String, dynamic> other) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ bool containsValue(dynamic value) => values.any((e) => e == value);
+
+ bool containsKey(dynamic key) => _getItem(key) != null;
+
+ Map operator [](dynamic key) => _getItem(key);
+
+ void forEach(void f(String key, dynamic value)) {
+ var entries = JS('', '#.entries()', this);
+ while (true) {
+ var entry = JS('', '#.next()', entries);
+ if (JS('bool', '#.done', entry)) return;
+ f(JS('String', '#.value[0]', entry),
+ convertNativeToDart_Dictionary(JS('', '#.value[1]', entry)));
+ }
+ }
+
+ Iterable<String> get keys {
+ final keys = <String>[];
+ forEach((k, v) => keys.add(k));
+ return keys;
+ }
+
+ Iterable<Map> get values {
+ final values = <Map>[];
+ forEach((k, v) => values.add(v));
+ return values;
+ }
+
+ int get length => JS('int', '#.size', this);
+
+ bool get isEmpty => length == 0;
+
+ bool get isNotEmpty => !isEmpty;
+
+ void operator []=(String key, dynamic value) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ dynamic putIfAbsent(String key, dynamic ifAbsent()) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String remove(dynamic key) {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void clear() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioProcessingEvent")
+class AudioProcessingEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory AudioProcessingEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AudioProcessingEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return AudioProcessingEvent._create_1(type, eventInitDict_1);
+ }
+ static AudioProcessingEvent _create_1(type, eventInitDict) => JS(
+ 'AudioProcessingEvent',
+ 'new AudioProcessingEvent(#,#)',
+ type,
+ eventInitDict);
+
+ final AudioBuffer inputBuffer;
+
+ final AudioBuffer outputBuffer;
+
+ final num playbackTime;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioScheduledSourceNode")
+class AudioScheduledSourceNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory AudioScheduledSourceNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> endedEvent =
+ const EventStreamProvider<Event>('ended');
+
+ @JSName('start')
+ void start2([num when]) native;
+
+ void stop([num when]) native;
+
+ Stream<Event> get onEnded => endedEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioTrack")
+class AudioTrack extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AudioTrack._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ bool enabled;
+
+ final String id;
+
+ final String kind;
+
+ final String label;
+
+ final String language;
+
+ final SourceBuffer sourceBuffer;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioTrackList")
+class AudioTrackList extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory AudioTrackList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const EventStreamProvider<Event> changeEvent =
+ const EventStreamProvider<Event>('change');
+
+ final int length;
+
+ AudioTrack __getter__(int index) native;
+
+ AudioTrack getTrackById(String id) native;
+
+ Stream<Event> get onChange => changeEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioWorkletGlobalScope")
+class AudioWorkletGlobalScope extends WorkletGlobalScope {
+ // To suppress missing implicit constructor warnings.
+ factory AudioWorkletGlobalScope._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num currentTime;
+
+ final num sampleRate;
+
+ void registerProcessor(String name, Object processorConstructor) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioWorkletNode")
+class AudioWorkletNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory AudioWorkletNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory AudioWorkletNode(BaseAudioContext context, String name,
+ [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return AudioWorkletNode._create_1(context, name, options_1);
+ }
+ return AudioWorkletNode._create_2(context, name);
+ }
+ static AudioWorkletNode _create_1(context, name, options) => JS(
+ 'AudioWorkletNode',
+ 'new AudioWorkletNode(#,#,#)',
+ context,
+ name,
+ options);
+ static AudioWorkletNode _create_2(context, name) =>
+ JS('AudioWorkletNode', 'new AudioWorkletNode(#,#)', context, name);
+
+ final AudioParamMap parameters;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("AudioWorkletProcessor")
+class AudioWorkletProcessor extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AudioWorkletProcessor._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BaseAudioContext")
+class BaseAudioContext extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory BaseAudioContext._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final num currentTime;
+
+ final AudioDestinationNode destination;
+
+ final AudioListener listener;
+
+ final num sampleRate;
+
+ final String state;
+
+ AnalyserNode createAnalyser() native;
+
+ BiquadFilterNode createBiquadFilter() native;
+
+ AudioBuffer createBuffer(
+ int numberOfChannels, int numberOfFrames, num sampleRate) native;
+
+ AudioBufferSourceNode createBufferSource() native;
+
+ ChannelMergerNode createChannelMerger([int numberOfInputs]) native;
+
+ ChannelSplitterNode createChannelSplitter([int numberOfOutputs]) native;
+
+ ConstantSourceNode createConstantSource() native;
+
+ ConvolverNode createConvolver() native;
+
+ DelayNode createDelay([num maxDelayTime]) native;
+
+ DynamicsCompressorNode createDynamicsCompressor() native;
+
+ GainNode createGain() native;
+
+ @JSName('createIIRFilter')
+ IirFilterNode createIirFilter(List<num> feedForward, List<num> feedBack)
+ native;
+
+ MediaElementAudioSourceNode createMediaElementSource(
+ MediaElement mediaElement) native;
+
+ MediaStreamAudioDestinationNode createMediaStreamDestination() native;
+
+ MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream)
+ native;
+
+ OscillatorNode createOscillator() native;
+
+ PannerNode createPanner() native;
+
+ PeriodicWave createPeriodicWave(List<num> real, List<num> imag,
+ [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return _createPeriodicWave_1(real, imag, options_1);
+ }
+ return _createPeriodicWave_2(real, imag);
+ }
+
+ @JSName('createPeriodicWave')
+ PeriodicWave _createPeriodicWave_1(List<num> real, List<num> imag, options)
+ native;
+ @JSName('createPeriodicWave')
+ PeriodicWave _createPeriodicWave_2(List<num> real, List<num> imag) native;
+
+ ScriptProcessorNode createScriptProcessor(
+ [int bufferSize,
+ int numberOfInputChannels,
+ int numberOfOutputChannels]) native;
+
+ StereoPannerNode createStereoPanner() native;
+
+ WaveShaperNode createWaveShaper() native;
+
+ Future<AudioBuffer> decodeAudioData(ByteBuffer audioData,
+ [DecodeSuccessCallback successCallback,
+ DecodeErrorCallback errorCallback]) =>
+ promiseToFuture<AudioBuffer>(JS("", "#.decodeAudioData(#, #, #)", this,
+ audioData, successCallback, errorCallback));
+
+ Future resume() => promiseToFuture(JS("", "#.resume()", this));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("BiquadFilterNode")
+class BiquadFilterNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory BiquadFilterNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory BiquadFilterNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return BiquadFilterNode._create_1(context, options_1);
+ }
+ return BiquadFilterNode._create_2(context);
+ }
+ static BiquadFilterNode _create_1(context, options) =>
+ JS('BiquadFilterNode', 'new BiquadFilterNode(#,#)', context, options);
+ static BiquadFilterNode _create_2(context) =>
+ JS('BiquadFilterNode', 'new BiquadFilterNode(#)', context);
+
+ final AudioParam Q;
+
+ final AudioParam detune;
+
+ final AudioParam frequency;
+
+ final AudioParam gain;
+
+ String type;
+
+ void getFrequencyResponse(Float32List frequencyHz, Float32List magResponse,
+ Float32List phaseResponse) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ChannelMergerNode,AudioChannelMerger")
+class ChannelMergerNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory ChannelMergerNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ChannelMergerNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return ChannelMergerNode._create_1(context, options_1);
+ }
+ return ChannelMergerNode._create_2(context);
+ }
+ static ChannelMergerNode _create_1(context, options) =>
+ JS('ChannelMergerNode', 'new ChannelMergerNode(#,#)', context, options);
+ static ChannelMergerNode _create_2(context) =>
+ JS('ChannelMergerNode', 'new ChannelMergerNode(#)', context);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ChannelSplitterNode,AudioChannelSplitter")
+class ChannelSplitterNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory ChannelSplitterNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ChannelSplitterNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return ChannelSplitterNode._create_1(context, options_1);
+ }
+ return ChannelSplitterNode._create_2(context);
+ }
+ static ChannelSplitterNode _create_1(context, options) => JS(
+ 'ChannelSplitterNode', 'new ChannelSplitterNode(#,#)', context, options);
+ static ChannelSplitterNode _create_2(context) =>
+ JS('ChannelSplitterNode', 'new ChannelSplitterNode(#)', context);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ConstantSourceNode")
+class ConstantSourceNode extends AudioScheduledSourceNode {
+ // To suppress missing implicit constructor warnings.
+ factory ConstantSourceNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ConstantSourceNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return ConstantSourceNode._create_1(context, options_1);
+ }
+ return ConstantSourceNode._create_2(context);
+ }
+ static ConstantSourceNode _create_1(context, options) =>
+ JS('ConstantSourceNode', 'new ConstantSourceNode(#,#)', context, options);
+ static ConstantSourceNode _create_2(context) =>
+ JS('ConstantSourceNode', 'new ConstantSourceNode(#)', context);
+
+ final AudioParam offset;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ConvolverNode")
+class ConvolverNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory ConvolverNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ConvolverNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return ConvolverNode._create_1(context, options_1);
+ }
+ return ConvolverNode._create_2(context);
+ }
+ static ConvolverNode _create_1(context, options) =>
+ JS('ConvolverNode', 'new ConvolverNode(#,#)', context, options);
+ static ConvolverNode _create_2(context) =>
+ JS('ConvolverNode', 'new ConvolverNode(#)', context);
+
+ AudioBuffer buffer;
+
+ bool normalize;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DelayNode")
+class DelayNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory DelayNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DelayNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return DelayNode._create_1(context, options_1);
+ }
+ return DelayNode._create_2(context);
+ }
+ static DelayNode _create_1(context, options) =>
+ JS('DelayNode', 'new DelayNode(#,#)', context, options);
+ static DelayNode _create_2(context) =>
+ JS('DelayNode', 'new DelayNode(#)', context);
+
+ final AudioParam delayTime;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("DynamicsCompressorNode")
+class DynamicsCompressorNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory DynamicsCompressorNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory DynamicsCompressorNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return DynamicsCompressorNode._create_1(context, options_1);
+ }
+ return DynamicsCompressorNode._create_2(context);
+ }
+ static DynamicsCompressorNode _create_1(context, options) => JS(
+ 'DynamicsCompressorNode',
+ 'new DynamicsCompressorNode(#,#)',
+ context,
+ options);
+ static DynamicsCompressorNode _create_2(context) =>
+ JS('DynamicsCompressorNode', 'new DynamicsCompressorNode(#)', context);
+
+ final AudioParam attack;
+
+ final AudioParam knee;
+
+ final AudioParam ratio;
+
+ final num reduction;
+
+ final AudioParam release;
+
+ final AudioParam threshold;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("GainNode,AudioGainNode")
+class GainNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory GainNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory GainNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return GainNode._create_1(context, options_1);
+ }
+ return GainNode._create_2(context);
+ }
+ static GainNode _create_1(context, options) =>
+ JS('GainNode', 'new GainNode(#,#)', context, options);
+ static GainNode _create_2(context) =>
+ JS('GainNode', 'new GainNode(#)', context);
+
+ final AudioParam gain;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("IIRFilterNode")
+class IirFilterNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory IirFilterNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory IirFilterNode(BaseAudioContext context, Map options) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return IirFilterNode._create_1(context, options_1);
+ }
+ static IirFilterNode _create_1(context, options) =>
+ JS('IirFilterNode', 'new IIRFilterNode(#,#)', context, options);
+
+ void getFrequencyResponse(Float32List frequencyHz, Float32List magResponse,
+ Float32List phaseResponse) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaElementAudioSourceNode")
+class MediaElementAudioSourceNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory MediaElementAudioSourceNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MediaElementAudioSourceNode(BaseAudioContext context, Map options) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return MediaElementAudioSourceNode._create_1(context, options_1);
+ }
+ static MediaElementAudioSourceNode _create_1(context, options) => JS(
+ 'MediaElementAudioSourceNode',
+ 'new MediaElementAudioSourceNode(#,#)',
+ context,
+ options);
+
+ final MediaElement mediaElement;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaStreamAudioDestinationNode")
+class MediaStreamAudioDestinationNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory MediaStreamAudioDestinationNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MediaStreamAudioDestinationNode(BaseAudioContext context,
+ [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return MediaStreamAudioDestinationNode._create_1(context, options_1);
+ }
+ return MediaStreamAudioDestinationNode._create_2(context);
+ }
+ static MediaStreamAudioDestinationNode _create_1(context, options) => JS(
+ 'MediaStreamAudioDestinationNode',
+ 'new MediaStreamAudioDestinationNode(#,#)',
+ context,
+ options);
+ static MediaStreamAudioDestinationNode _create_2(context) => JS(
+ 'MediaStreamAudioDestinationNode',
+ 'new MediaStreamAudioDestinationNode(#)',
+ context);
+
+ final MediaStream stream;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("MediaStreamAudioSourceNode")
+class MediaStreamAudioSourceNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory MediaStreamAudioSourceNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory MediaStreamAudioSourceNode(BaseAudioContext context, Map options) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return MediaStreamAudioSourceNode._create_1(context, options_1);
+ }
+ static MediaStreamAudioSourceNode _create_1(context, options) => JS(
+ 'MediaStreamAudioSourceNode',
+ 'new MediaStreamAudioSourceNode(#,#)',
+ context,
+ options);
+
+ final MediaStream mediaStream;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OfflineAudioCompletionEvent")
+class OfflineAudioCompletionEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory OfflineAudioCompletionEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory OfflineAudioCompletionEvent(String type, Map eventInitDict) {
+ var eventInitDict_1 = convertDartToNative_Dictionary(eventInitDict);
+ return OfflineAudioCompletionEvent._create_1(type, eventInitDict_1);
+ }
+ static OfflineAudioCompletionEvent _create_1(type, eventInitDict) => JS(
+ 'OfflineAudioCompletionEvent',
+ 'new OfflineAudioCompletionEvent(#,#)',
+ type,
+ eventInitDict);
+
+ final AudioBuffer renderedBuffer;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OfflineAudioContext")
+class OfflineAudioContext extends BaseAudioContext {
+ // To suppress missing implicit constructor warnings.
+ factory OfflineAudioContext._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory OfflineAudioContext(numberOfChannels_OR_options,
+ [int numberOfFrames, num sampleRate]) {
+ if ((sampleRate is num) &&
+ (numberOfFrames is int) &&
+ (numberOfChannels_OR_options is int)) {
+ return OfflineAudioContext._create_1(
+ numberOfChannels_OR_options, numberOfFrames, sampleRate);
+ }
+ if ((numberOfChannels_OR_options is Map) &&
+ numberOfFrames == null &&
+ sampleRate == null) {
+ var options_1 =
+ convertDartToNative_Dictionary(numberOfChannels_OR_options);
+ return OfflineAudioContext._create_2(options_1);
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+ static OfflineAudioContext _create_1(
+ numberOfChannels_OR_options, numberOfFrames, sampleRate) =>
+ JS('OfflineAudioContext', 'new OfflineAudioContext(#,#,#)',
+ numberOfChannels_OR_options, numberOfFrames, sampleRate);
+ static OfflineAudioContext _create_2(numberOfChannels_OR_options) => JS(
+ 'OfflineAudioContext',
+ 'new OfflineAudioContext(#)',
+ numberOfChannels_OR_options);
+
+ final int length;
+
+ Future<AudioBuffer> startRendering() =>
+ promiseToFuture<AudioBuffer>(JS("", "#.startRendering()", this));
+
+ @JSName('suspend')
+ Future suspendFor(num suspendTime) =>
+ promiseToFuture(JS("", "#.suspendFor(#)", this, suspendTime));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OscillatorNode,Oscillator")
+class OscillatorNode extends AudioScheduledSourceNode {
+ // To suppress missing implicit constructor warnings.
+ factory OscillatorNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory OscillatorNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return OscillatorNode._create_1(context, options_1);
+ }
+ return OscillatorNode._create_2(context);
+ }
+ static OscillatorNode _create_1(context, options) =>
+ JS('OscillatorNode', 'new OscillatorNode(#,#)', context, options);
+ static OscillatorNode _create_2(context) =>
+ JS('OscillatorNode', 'new OscillatorNode(#)', context);
+
+ final AudioParam detune;
+
+ final AudioParam frequency;
+
+ String type;
+
+ void setPeriodicWave(PeriodicWave periodicWave) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PannerNode,AudioPannerNode,webkitAudioPannerNode")
+class PannerNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory PannerNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PannerNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return PannerNode._create_1(context, options_1);
+ }
+ return PannerNode._create_2(context);
+ }
+ static PannerNode _create_1(context, options) =>
+ JS('PannerNode', 'new PannerNode(#,#)', context, options);
+ static PannerNode _create_2(context) =>
+ JS('PannerNode', 'new PannerNode(#)', context);
+
+ num coneInnerAngle;
+
+ num coneOuterAngle;
+
+ num coneOuterGain;
+
+ String distanceModel;
+
+ num maxDistance;
+
+ final AudioParam orientationX;
+
+ final AudioParam orientationY;
+
+ final AudioParam orientationZ;
+
+ String panningModel;
+
+ final AudioParam positionX;
+
+ final AudioParam positionY;
+
+ final AudioParam positionZ;
+
+ num refDistance;
+
+ num rolloffFactor;
+
+ void setOrientation(num x, num y, num z) native;
+
+ void setPosition(num x, num y, num z) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("PeriodicWave")
+class PeriodicWave extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory PeriodicWave._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory PeriodicWave(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return PeriodicWave._create_1(context, options_1);
+ }
+ return PeriodicWave._create_2(context);
+ }
+ static PeriodicWave _create_1(context, options) =>
+ JS('PeriodicWave', 'new PeriodicWave(#,#)', context, options);
+ static PeriodicWave _create_2(context) =>
+ JS('PeriodicWave', 'new PeriodicWave(#)', context);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ScriptProcessorNode,JavaScriptAudioNode")
+class ScriptProcessorNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory ScriptProcessorNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /**
+ * Static factory designed to expose `audioprocess` events to event
+ * handlers that are not necessarily instances of [ScriptProcessorNode].
+ *
+ * See [EventStreamProvider] for usage information.
+ */
+ static const EventStreamProvider<AudioProcessingEvent> audioProcessEvent =
+ const EventStreamProvider<AudioProcessingEvent>('audioprocess');
+
+ final int bufferSize;
+
+ void setEventListener(EventListener eventListener) native;
+
+ /// Stream of `audioprocess` events handled by this [ScriptProcessorNode].
+/**
+ * Get a Stream that fires events when AudioProcessingEvents occur.
+ * This particular stream is special in that it only allows one listener to a
+ * given stream. Converting the returned Stream [asBroadcast] will likely ruin
+ * the soft-real-time properties which which these events are fired and can
+ * be processed.
+ */
+ Stream<AudioProcessingEvent> get onAudioProcess =>
+ audioProcessEvent.forTarget(this);
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("StereoPannerNode")
+class StereoPannerNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory StereoPannerNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory StereoPannerNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return StereoPannerNode._create_1(context, options_1);
+ }
+ return StereoPannerNode._create_2(context);
+ }
+ static StereoPannerNode _create_1(context, options) =>
+ JS('StereoPannerNode', 'new StereoPannerNode(#,#)', context, options);
+ static StereoPannerNode _create_2(context) =>
+ JS('StereoPannerNode', 'new StereoPannerNode(#)', context);
+
+ final AudioParam pan;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WaveShaperNode")
+class WaveShaperNode extends AudioNode {
+ // To suppress missing implicit constructor warnings.
+ factory WaveShaperNode._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory WaveShaperNode(BaseAudioContext context, [Map options]) {
+ if (options != null) {
+ var options_1 = convertDartToNative_Dictionary(options);
+ return WaveShaperNode._create_1(context, options_1);
+ }
+ return WaveShaperNode._create_2(context);
+ }
+ static WaveShaperNode _create_1(context, options) =>
+ JS('WaveShaperNode', 'new WaveShaperNode(#,#)', context, options);
+ static WaveShaperNode _create_2(context) =>
+ JS('WaveShaperNode', 'new WaveShaperNode(#)', context);
+
+ Float32List curve;
+
+ String oversample;
+}
diff --git a/sdk_nnbd/lib/web_gl/dart2js/web_gl_dart2js.dart b/sdk_nnbd/lib/web_gl/dart2js/web_gl_dart2js.dart
new file mode 100644
index 0000000..80e36b1
--- /dev/null
+++ b/sdk_nnbd/lib/web_gl/dart2js/web_gl_dart2js.dart
@@ -0,0 +1,4174 @@
+/**
+ * 3D programming in the browser.
+ *
+ * {@category Web}
+ */
+library dart.dom.web_gl;
+
+import 'dart:async';
+import 'dart:collection' hide LinkedList, LinkedListEntry;
+import 'dart:_internal' show FixedLengthListMixin;
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:_native_typed_data';
+import 'dart:typed_data';
+import 'dart:_js_helper'
+ show Creates, JSName, Native, Returns, convertDartClosureToJS;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show Interceptor, JSExtendableArray;
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:web_gl library.
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("WebGLActiveInfo")
+class ActiveInfo extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ActiveInfo._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final String name;
+
+ final int size;
+
+ final int type;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("ANGLEInstancedArrays,ANGLE_instanced_arrays")
+class AngleInstancedArrays extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory AngleInstancedArrays._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
+
+ @JSName('drawArraysInstancedANGLE')
+ void drawArraysInstancedAngle(int mode, int first, int count, int primcount)
+ native;
+
+ @JSName('drawElementsInstancedANGLE')
+ void drawElementsInstancedAngle(
+ int mode, int count, int type, int offset, int primcount) native;
+
+ @JSName('vertexAttribDivisorANGLE')
+ void vertexAttribDivisorAngle(int index, int divisor) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("WebGLBuffer")
+class Buffer extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Buffer._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCanvas")
+class Canvas extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Canvas._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('canvas')
+ final CanvasElement canvas;
+
+ @JSName('canvas')
+ final OffscreenCanvas offscreenCanvas;
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLColorBufferFloat")
+class ColorBufferFloat extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ColorBufferFloat._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTextureASTC")
+class CompressedTextureAstc extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CompressedTextureAstc._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int COMPRESSED_RGBA_ASTC_10x10_KHR = 0x93BB;
+
+ static const int COMPRESSED_RGBA_ASTC_10x5_KHR = 0x93B8;
+
+ static const int COMPRESSED_RGBA_ASTC_10x6_KHR = 0x93B9;
+
+ static const int COMPRESSED_RGBA_ASTC_10x8_KHR = 0x93BA;
+
+ static const int COMPRESSED_RGBA_ASTC_12x10_KHR = 0x93BC;
+
+ static const int COMPRESSED_RGBA_ASTC_12x12_KHR = 0x93BD;
+
+ static const int COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0;
+
+ static const int COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1;
+
+ static const int COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2;
+
+ static const int COMPRESSED_RGBA_ASTC_6x5_KHR = 0x93B3;
+
+ static const int COMPRESSED_RGBA_ASTC_6x6_KHR = 0x93B4;
+
+ static const int COMPRESSED_RGBA_ASTC_8x5_KHR = 0x93B5;
+
+ static const int COMPRESSED_RGBA_ASTC_8x6_KHR = 0x93B6;
+
+ static const int COMPRESSED_RGBA_ASTC_8x8_KHR = 0x93B7;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x93DB;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 0x93D8;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 0x93D9;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 0x93DA;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 0x93D1;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 0x93D2;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 0x93D3;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 0x93D4;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 0x93D5;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 0x93D6;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 0x93D7;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTextureATC,WEBGL_compressed_texture_atc")
+class CompressedTextureAtc extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CompressedTextureAtc._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL = 0x8C93;
+
+ static const int COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE;
+
+ static const int COMPRESSED_RGB_ATC_WEBGL = 0x8C92;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTextureETC1,WEBGL_compressed_texture_etc1")
+class CompressedTextureETC1 extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CompressedTextureETC1._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int COMPRESSED_RGB_ETC1_WEBGL = 0x8D64;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTextureETC")
+class CompressedTextureEtc extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CompressedTextureEtc._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int COMPRESSED_R11_EAC = 0x9270;
+
+ static const int COMPRESSED_RG11_EAC = 0x9272;
+
+ static const int COMPRESSED_RGB8_ETC2 = 0x9274;
+
+ static const int COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276;
+
+ static const int COMPRESSED_RGBA8_ETC2_EAC = 0x9278;
+
+ static const int COMPRESSED_SIGNED_R11_EAC = 0x9271;
+
+ static const int COMPRESSED_SIGNED_RG11_EAC = 0x9273;
+
+ static const int COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279;
+
+ static const int COMPRESSED_SRGB8_ETC2 = 0x9275;
+
+ static const int COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTexturePVRTC,WEBGL_compressed_texture_pvrtc")
+class CompressedTexturePvrtc extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CompressedTexturePvrtc._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03;
+
+ static const int COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
+
+ static const int COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01;
+
+ static const int COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTextureS3TC,WEBGL_compressed_texture_s3tc")
+class CompressedTextureS3TC extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CompressedTextureS3TC._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
+
+ static const int COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
+
+ static const int COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
+
+ static const int COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLCompressedTextureS3TCsRGB")
+class CompressedTextureS3TCsRgb extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory CompressedTextureS3TCsRgb._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D;
+
+ static const int COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E;
+
+ static const int COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F;
+
+ static const int COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("WebGLContextEvent")
+class ContextEvent extends Event {
+ // To suppress missing implicit constructor warnings.
+ factory ContextEvent._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ factory ContextEvent(String type, [Map eventInit]) {
+ if (eventInit != null) {
+ var eventInit_1 = convertDartToNative_Dictionary(eventInit);
+ return ContextEvent._create_1(type, eventInit_1);
+ }
+ return ContextEvent._create_2(type);
+ }
+ static ContextEvent _create_1(type, eventInit) =>
+ JS('ContextEvent', 'new WebGLContextEvent(#,#)', type, eventInit);
+ static ContextEvent _create_2(type) =>
+ JS('ContextEvent', 'new WebGLContextEvent(#)', type);
+
+ final String statusMessage;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLDebugRendererInfo,WEBGL_debug_renderer_info")
+class DebugRendererInfo extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DebugRendererInfo._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int UNMASKED_RENDERER_WEBGL = 0x9246;
+
+ static const int UNMASKED_VENDOR_WEBGL = 0x9245;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLDebugShaders,WEBGL_debug_shaders")
+class DebugShaders extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DebugShaders._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ String getTranslatedShaderSource(Shader shader) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLDepthTexture,WEBGL_depth_texture")
+class DepthTexture extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DepthTexture._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int UNSIGNED_INT_24_8_WEBGL = 0x84FA;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLDrawBuffers,WEBGL_draw_buffers")
+class DrawBuffers extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory DrawBuffers._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('drawBuffersWEBGL')
+ void drawBuffersWebgl(List<int> buffers) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTsRGB,EXT_sRGB")
+class EXTsRgb extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory EXTsRgb._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT = 0x8210;
+
+ static const int SRGB8_ALPHA8_EXT = 0x8C43;
+
+ static const int SRGB_ALPHA_EXT = 0x8C42;
+
+ static const int SRGB_EXT = 0x8C40;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTBlendMinMax,EXT_blend_minmax")
+class ExtBlendMinMax extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ExtBlendMinMax._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int MAX_EXT = 0x8008;
+
+ static const int MIN_EXT = 0x8007;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTColorBufferFloat")
+class ExtColorBufferFloat extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ExtColorBufferFloat._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTColorBufferHalfFloat")
+class ExtColorBufferHalfFloat extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ExtColorBufferHalfFloat._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTDisjointTimerQuery")
+class ExtDisjointTimerQuery extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ExtDisjointTimerQuery._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int CURRENT_QUERY_EXT = 0x8865;
+
+ static const int GPU_DISJOINT_EXT = 0x8FBB;
+
+ static const int QUERY_COUNTER_BITS_EXT = 0x8864;
+
+ static const int QUERY_RESULT_AVAILABLE_EXT = 0x8867;
+
+ static const int QUERY_RESULT_EXT = 0x8866;
+
+ static const int TIMESTAMP_EXT = 0x8E28;
+
+ static const int TIME_ELAPSED_EXT = 0x88BF;
+
+ @JSName('beginQueryEXT')
+ void beginQueryExt(int target, TimerQueryExt query) native;
+
+ @JSName('createQueryEXT')
+ TimerQueryExt createQueryExt() native;
+
+ @JSName('deleteQueryEXT')
+ void deleteQueryExt(TimerQueryExt query) native;
+
+ @JSName('endQueryEXT')
+ void endQueryExt(int target) native;
+
+ @JSName('getQueryEXT')
+ Object getQueryExt(int target, int pname) native;
+
+ @JSName('getQueryObjectEXT')
+ Object getQueryObjectExt(TimerQueryExt query, int pname) native;
+
+ @JSName('isQueryEXT')
+ bool isQueryExt(TimerQueryExt query) native;
+
+ @JSName('queryCounterEXT')
+ void queryCounterExt(TimerQueryExt query, int target) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTDisjointTimerQueryWebGL2")
+class ExtDisjointTimerQueryWebGL2 extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ExtDisjointTimerQueryWebGL2._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int GPU_DISJOINT_EXT = 0x8FBB;
+
+ static const int QUERY_COUNTER_BITS_EXT = 0x8864;
+
+ static const int TIMESTAMP_EXT = 0x8E28;
+
+ static const int TIME_ELAPSED_EXT = 0x88BF;
+
+ @JSName('queryCounterEXT')
+ void queryCounterExt(Query query, int target) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTFragDepth,EXT_frag_depth")
+class ExtFragDepth extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ExtFragDepth._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTShaderTextureLOD,EXT_shader_texture_lod")
+class ExtShaderTextureLod extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ExtShaderTextureLod._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("EXTTextureFilterAnisotropic,EXT_texture_filter_anisotropic")
+class ExtTextureFilterAnisotropic extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ExtTextureFilterAnisotropic._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
+
+ static const int TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("WebGLFramebuffer")
+class Framebuffer extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Framebuffer._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLGetBufferSubDataAsync")
+class GetBufferSubDataAsync extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory GetBufferSubDataAsync._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ Future getBufferSubDataAsync(int target, int srcByteOffset, TypedData dstData,
+ [int dstOffset, int length]) =>
+ promiseToFuture(JS("", "#.getBufferSubDataAsync(#, #, #, #, #)", this,
+ target, srcByteOffset, dstData, dstOffset, length));
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLLoseContext,WebGLExtensionLoseContext,WEBGL_lose_context")
+class LoseContext extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory LoseContext._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ void loseContext() native;
+
+ void restoreContext() native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESElementIndexUint,OES_element_index_uint")
+class OesElementIndexUint extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory OesElementIndexUint._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESStandardDerivatives,OES_standard_derivatives")
+class OesStandardDerivatives extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory OesStandardDerivatives._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESTextureFloat,OES_texture_float")
+class OesTextureFloat extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory OesTextureFloat._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESTextureFloatLinear,OES_texture_float_linear")
+class OesTextureFloatLinear extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory OesTextureFloatLinear._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESTextureHalfFloat,OES_texture_half_float")
+class OesTextureHalfFloat extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory OesTextureHalfFloat._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int HALF_FLOAT_OES = 0x8D61;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESTextureHalfFloatLinear,OES_texture_half_float_linear")
+class OesTextureHalfFloatLinear extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory OesTextureHalfFloatLinear._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("OESVertexArrayObject,OES_vertex_array_object")
+class OesVertexArrayObject extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory OesVertexArrayObject._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int VERTEX_ARRAY_BINDING_OES = 0x85B5;
+
+ @JSName('bindVertexArrayOES')
+ void bindVertexArray(VertexArrayObjectOes arrayObject) native;
+
+ @JSName('createVertexArrayOES')
+ VertexArrayObjectOes createVertexArray() native;
+
+ @JSName('deleteVertexArrayOES')
+ void deleteVertexArray(VertexArrayObjectOes arrayObject) native;
+
+ @JSName('isVertexArrayOES')
+ bool isVertexArray(VertexArrayObjectOes arrayObject) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("WebGLProgram")
+class Program extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Program._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLQuery")
+class Query extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Query._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Unstable()
+@Native("WebGLRenderbuffer")
+class Renderbuffer extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Renderbuffer._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@Unstable()
+@Native("WebGLRenderingContext")
+class RenderingContext extends Interceptor implements CanvasRenderingContext {
+ // To suppress missing implicit constructor warnings.
+ factory RenderingContext._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => JS('bool', '!!(window.WebGLRenderingContext)');
+
+ final CanvasElement canvas;
+
+ // From WebGLRenderingContextBase
+
+ final int drawingBufferHeight;
+
+ final int drawingBufferWidth;
+
+ void activeTexture(int texture) native;
+
+ void attachShader(Program program, Shader shader) native;
+
+ void bindAttribLocation(Program program, int index, String name) native;
+
+ void bindBuffer(int target, Buffer buffer) native;
+
+ void bindFramebuffer(int target, Framebuffer framebuffer) native;
+
+ void bindRenderbuffer(int target, Renderbuffer renderbuffer) native;
+
+ void bindTexture(int target, Texture texture) native;
+
+ void blendColor(num red, num green, num blue, num alpha) native;
+
+ void blendEquation(int mode) native;
+
+ void blendEquationSeparate(int modeRGB, int modeAlpha) native;
+
+ void blendFunc(int sfactor, int dfactor) native;
+
+ void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha)
+ native;
+
+ void bufferData(int target, data_OR_size, int usage) native;
+
+ void bufferSubData(int target, int offset, data) native;
+
+ int checkFramebufferStatus(int target) native;
+
+ void clear(int mask) native;
+
+ void clearColor(num red, num green, num blue, num alpha) native;
+
+ void clearDepth(num depth) native;
+
+ void clearStencil(int s) native;
+
+ void colorMask(bool red, bool green, bool blue, bool alpha) native;
+
+ Future commit() => promiseToFuture(JS("", "#.commit()", this));
+
+ void compileShader(Shader shader) native;
+
+ void compressedTexImage2D(int target, int level, int internalformat,
+ int width, int height, int border, TypedData data) native;
+
+ void compressedTexSubImage2D(int target, int level, int xoffset, int yoffset,
+ int width, int height, int format, TypedData data) native;
+
+ void copyTexImage2D(int target, int level, int internalformat, int x, int y,
+ int width, int height, int border) native;
+
+ void copyTexSubImage2D(int target, int level, int xoffset, int yoffset, int x,
+ int y, int width, int height) native;
+
+ Buffer createBuffer() native;
+
+ Framebuffer createFramebuffer() native;
+
+ Program createProgram() native;
+
+ Renderbuffer createRenderbuffer() native;
+
+ Shader createShader(int type) native;
+
+ Texture createTexture() native;
+
+ void cullFace(int mode) native;
+
+ void deleteBuffer(Buffer buffer) native;
+
+ void deleteFramebuffer(Framebuffer framebuffer) native;
+
+ void deleteProgram(Program program) native;
+
+ void deleteRenderbuffer(Renderbuffer renderbuffer) native;
+
+ void deleteShader(Shader shader) native;
+
+ void deleteTexture(Texture texture) native;
+
+ void depthFunc(int func) native;
+
+ void depthMask(bool flag) native;
+
+ void depthRange(num zNear, num zFar) native;
+
+ void detachShader(Program program, Shader shader) native;
+
+ void disable(int cap) native;
+
+ void disableVertexAttribArray(int index) native;
+
+ void drawArrays(int mode, int first, int count) native;
+
+ void drawElements(int mode, int count, int type, int offset) native;
+
+ void enable(int cap) native;
+
+ void enableVertexAttribArray(int index) native;
+
+ void finish() native;
+
+ void flush() native;
+
+ void framebufferRenderbuffer(int target, int attachment,
+ int renderbuffertarget, Renderbuffer renderbuffer) native;
+
+ void framebufferTexture2D(int target, int attachment, int textarget,
+ Texture texture, int level) native;
+
+ void frontFace(int mode) native;
+
+ void generateMipmap(int target) native;
+
+ ActiveInfo getActiveAttrib(Program program, int index) native;
+
+ ActiveInfo getActiveUniform(Program program, int index) native;
+
+ List<Shader> getAttachedShaders(Program program) native;
+
+ int getAttribLocation(Program program, String name) native;
+
+ @Creates('int|Null')
+ @Returns('int|Null')
+ Object getBufferParameter(int target, int pname) native;
+
+ @Creates('ContextAttributes|Null')
+ Map getContextAttributes() {
+ return convertNativeToDart_Dictionary(_getContextAttributes_1());
+ }
+
+ @JSName('getContextAttributes')
+ @Creates('ContextAttributes|Null')
+ _getContextAttributes_1() native;
+
+ int getError() native;
+
+ Object getExtension(String name) native;
+
+ @Creates('int|Renderbuffer|Texture|Null')
+ @Returns('int|Renderbuffer|Texture|Null')
+ Object getFramebufferAttachmentParameter(
+ int target, int attachment, int pname) native;
+
+ @Creates(
+ 'Null|num|String|bool|JSExtendableArray|NativeFloat32List|NativeInt32List|NativeUint32List|Framebuffer|Renderbuffer|Texture')
+ @Returns(
+ 'Null|num|String|bool|JSExtendableArray|NativeFloat32List|NativeInt32List|NativeUint32List|Framebuffer|Renderbuffer|Texture')
+ Object getParameter(int pname) native;
+
+ String getProgramInfoLog(Program program) native;
+
+ @Creates('int|bool|Null')
+ @Returns('int|bool|Null')
+ Object getProgramParameter(Program program, int pname) native;
+
+ @Creates('int|Null')
+ @Returns('int|Null')
+ Object getRenderbufferParameter(int target, int pname) native;
+
+ String getShaderInfoLog(Shader shader) native;
+
+ @Creates('int|bool|Null')
+ @Returns('int|bool|Null')
+ Object getShaderParameter(Shader shader, int pname) native;
+
+ ShaderPrecisionFormat getShaderPrecisionFormat(
+ int shadertype, int precisiontype) native;
+
+ String getShaderSource(Shader shader) native;
+
+ List<String> getSupportedExtensions() native;
+
+ @Creates('int|Null')
+ @Returns('int|Null')
+ Object getTexParameter(int target, int pname) native;
+
+ @Creates(
+ 'Null|num|String|bool|JSExtendableArray|NativeFloat32List|NativeInt32List|NativeUint32List')
+ @Returns(
+ 'Null|num|String|bool|JSExtendableArray|NativeFloat32List|NativeInt32List|NativeUint32List')
+ Object getUniform(Program program, UniformLocation location) native;
+
+ UniformLocation getUniformLocation(Program program, String name) native;
+
+ @Creates('Null|num|bool|NativeFloat32List|Buffer')
+ @Returns('Null|num|bool|NativeFloat32List|Buffer')
+ Object getVertexAttrib(int index, int pname) native;
+
+ int getVertexAttribOffset(int index, int pname) native;
+
+ void hint(int target, int mode) native;
+
+ bool isBuffer(Buffer buffer) native;
+
+ bool isContextLost() native;
+
+ bool isEnabled(int cap) native;
+
+ bool isFramebuffer(Framebuffer framebuffer) native;
+
+ bool isProgram(Program program) native;
+
+ bool isRenderbuffer(Renderbuffer renderbuffer) native;
+
+ bool isShader(Shader shader) native;
+
+ bool isTexture(Texture texture) native;
+
+ void lineWidth(num width) native;
+
+ void linkProgram(Program program) native;
+
+ void pixelStorei(int pname, int param) native;
+
+ void polygonOffset(num factor, num units) native;
+
+ @JSName('readPixels')
+ void _readPixels(int x, int y, int width, int height, int format, int type,
+ TypedData pixels) native;
+
+ void renderbufferStorage(
+ int target, int internalformat, int width, int height) native;
+
+ void sampleCoverage(num value, bool invert) native;
+
+ void scissor(int x, int y, int width, int height) native;
+
+ void shaderSource(Shader shader, String string) native;
+
+ void stencilFunc(int func, int ref, int mask) native;
+
+ void stencilFuncSeparate(int face, int func, int ref, int mask) native;
+
+ void stencilMask(int mask) native;
+
+ void stencilMaskSeparate(int face, int mask) native;
+
+ void stencilOp(int fail, int zfail, int zpass) native;
+
+ void stencilOpSeparate(int face, int fail, int zfail, int zpass) native;
+
+ void texImage2D(
+ int target,
+ int level,
+ int internalformat,
+ int format_OR_width,
+ int height_OR_type,
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video,
+ [int format,
+ int type,
+ TypedData pixels]) {
+ if (type != null &&
+ format != null &&
+ (bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video is int)) {
+ _texImage2D_1(
+ target,
+ level,
+ internalformat,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video,
+ format,
+ type,
+ pixels);
+ return;
+ }
+ if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video is ImageData) &&
+ format == null &&
+ type == null &&
+ pixels == null) {
+ var pixels_1 = convertDartToNative_ImageData(
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+ _texImage2D_2(target, level, internalformat, format_OR_width,
+ height_OR_type, pixels_1);
+ return;
+ }
+ if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+ is ImageElement) &&
+ format == null &&
+ type == null &&
+ pixels == null) {
+ _texImage2D_3(
+ target,
+ level,
+ internalformat,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+ is CanvasElement) &&
+ format == null &&
+ type == null &&
+ pixels == null) {
+ _texImage2D_4(
+ target,
+ level,
+ internalformat,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+ is VideoElement) &&
+ format == null &&
+ type == null &&
+ pixels == null) {
+ _texImage2D_5(
+ target,
+ level,
+ internalformat,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+ is ImageBitmap) &&
+ format == null &&
+ type == null &&
+ pixels == null) {
+ _texImage2D_6(
+ target,
+ level,
+ internalformat,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('texImage2D')
+ void _texImage2D_1(target, level, internalformat, width, height, int border,
+ format, type, TypedData pixels) native;
+ @JSName('texImage2D')
+ void _texImage2D_2(target, level, internalformat, format, type, pixels)
+ native;
+ @JSName('texImage2D')
+ void _texImage2D_3(
+ target, level, internalformat, format, type, ImageElement image) native;
+ @JSName('texImage2D')
+ void _texImage2D_4(
+ target, level, internalformat, format, type, CanvasElement canvas) native;
+ @JSName('texImage2D')
+ void _texImage2D_5(
+ target, level, internalformat, format, type, VideoElement video) native;
+ @JSName('texImage2D')
+ void _texImage2D_6(
+ target, level, internalformat, format, type, ImageBitmap bitmap) native;
+
+ void texParameterf(int target, int pname, num param) native;
+
+ void texParameteri(int target, int pname, int param) native;
+
+ void texSubImage2D(
+ int target,
+ int level,
+ int xoffset,
+ int yoffset,
+ int format_OR_width,
+ int height_OR_type,
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video,
+ [int type,
+ TypedData pixels]) {
+ if (type != null &&
+ (bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video is int)) {
+ _texSubImage2D_1(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video,
+ type,
+ pixels);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video is ImageData) &&
+ type == null &&
+ pixels == null) {
+ var pixels_1 = convertDartToNative_ImageData(
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+ _texSubImage2D_2(target, level, xoffset, yoffset, format_OR_width,
+ height_OR_type, pixels_1);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+ is ImageElement) &&
+ type == null &&
+ pixels == null) {
+ _texSubImage2D_3(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+ is CanvasElement) &&
+ type == null &&
+ pixels == null) {
+ _texSubImage2D_4(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+ is VideoElement) &&
+ type == null &&
+ pixels == null) {
+ _texSubImage2D_5(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+ is ImageBitmap) &&
+ type == null &&
+ pixels == null) {
+ _texSubImage2D_6(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('texSubImage2D')
+ void _texSubImage2D_1(target, level, xoffset, yoffset, width, height,
+ int format, type, TypedData pixels) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D_2(target, level, xoffset, yoffset, format, type, pixels)
+ native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D_3(
+ target, level, xoffset, yoffset, format, type, ImageElement image) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D_4(target, level, xoffset, yoffset, format, type,
+ CanvasElement canvas) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D_5(
+ target, level, xoffset, yoffset, format, type, VideoElement video) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D_6(
+ target, level, xoffset, yoffset, format, type, ImageBitmap bitmap) native;
+
+ void uniform1f(UniformLocation location, num x) native;
+
+ void uniform1fv(UniformLocation location, v) native;
+
+ void uniform1i(UniformLocation location, int x) native;
+
+ void uniform1iv(UniformLocation location, v) native;
+
+ void uniform2f(UniformLocation location, num x, num y) native;
+
+ void uniform2fv(UniformLocation location, v) native;
+
+ void uniform2i(UniformLocation location, int x, int y) native;
+
+ void uniform2iv(UniformLocation location, v) native;
+
+ void uniform3f(UniformLocation location, num x, num y, num z) native;
+
+ void uniform3fv(UniformLocation location, v) native;
+
+ void uniform3i(UniformLocation location, int x, int y, int z) native;
+
+ void uniform3iv(UniformLocation location, v) native;
+
+ void uniform4f(UniformLocation location, num x, num y, num z, num w) native;
+
+ void uniform4fv(UniformLocation location, v) native;
+
+ void uniform4i(UniformLocation location, int x, int y, int z, int w) native;
+
+ void uniform4iv(UniformLocation location, v) native;
+
+ void uniformMatrix2fv(UniformLocation location, bool transpose, array) native;
+
+ void uniformMatrix3fv(UniformLocation location, bool transpose, array) native;
+
+ void uniformMatrix4fv(UniformLocation location, bool transpose, array) native;
+
+ void useProgram(Program program) native;
+
+ void validateProgram(Program program) native;
+
+ void vertexAttrib1f(int indx, num x) native;
+
+ void vertexAttrib1fv(int indx, values) native;
+
+ void vertexAttrib2f(int indx, num x, num y) native;
+
+ void vertexAttrib2fv(int indx, values) native;
+
+ void vertexAttrib3f(int indx, num x, num y, num z) native;
+
+ void vertexAttrib3fv(int indx, values) native;
+
+ void vertexAttrib4f(int indx, num x, num y, num z, num w) native;
+
+ void vertexAttrib4fv(int indx, values) native;
+
+ void vertexAttribPointer(int indx, int size, int type, bool normalized,
+ int stride, int offset) native;
+
+ void viewport(int x, int y, int width, int height) native;
+
+ void readPixels(int x, int y, int width, int height, int format, int type,
+ TypedData pixels) {
+ _readPixels(x, y, width, height, format, type, pixels);
+ }
+
+ /**
+ * Sets the currently bound texture to [data].
+ *
+ * [data] can be either an [ImageElement], a
+ * [CanvasElement], a [VideoElement], [TypedData] or an [ImageData] object.
+ *
+ * This is deprecated in favor of [texImage2D].
+ */
+ @Deprecated("Use texImage2D")
+ void texImage2DUntyped(int targetTexture, int levelOfDetail,
+ int internalFormat, int format, int type, data) {
+ texImage2D(
+ targetTexture, levelOfDetail, internalFormat, format, type, data);
+ }
+
+ /**
+ * Sets the currently bound texture to [data].
+ *
+ * This is deprecated in favour of [texImage2D].
+ */
+ @Deprecated("Use texImage2D")
+ void texImage2DTyped(int targetTexture, int levelOfDetail, int internalFormat,
+ int width, int height, int border, int format, int type, TypedData data) {
+ texImage2D(targetTexture, levelOfDetail, internalFormat, width, height,
+ border, format, type, data);
+ }
+
+ /**
+ * Updates a sub-rectangle of the currently bound texture to [data].
+ *
+ * [data] can be either an [ImageElement], a
+ * [CanvasElement], a [VideoElement], [TypedData] or an [ImageData] object.
+ *
+ */
+ @Deprecated("Use texSubImage2D")
+ void texSubImage2DUntyped(int targetTexture, int levelOfDetail, int xOffset,
+ int yOffset, int format, int type, data) {
+ texSubImage2D(
+ targetTexture, levelOfDetail, xOffset, yOffset, format, type, data);
+ }
+
+ /**
+ * Updates a sub-rectangle of the currently bound texture to [data].
+ */
+ @Deprecated("Use texSubImage2D")
+ void texSubImage2DTyped(
+ int targetTexture,
+ int levelOfDetail,
+ int xOffset,
+ int yOffset,
+ int width,
+ int height,
+ int border,
+ int format,
+ int type,
+ TypedData data) {
+ texSubImage2D(targetTexture, levelOfDetail, xOffset, yOffset, width, height,
+ format, type, data);
+ }
+
+ /**
+ * Set the bufferData to [data].
+ */
+ @Deprecated("Use bufferData")
+ void bufferDataTyped(int target, TypedData data, int usage) {
+ bufferData(target, data, usage);
+ }
+
+ /**
+ * Set the bufferSubData to [data].
+ */
+ @Deprecated("Use bufferSubData")
+ void bufferSubDataTyped(int target, int offset, TypedData data) {
+ bufferSubData(target, offset, data);
+ }
+}
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGL2RenderingContext")
+class RenderingContext2 extends Interceptor
+ implements _WebGL2RenderingContextBase, _WebGLRenderingContextBase {
+ // To suppress missing implicit constructor warnings.
+ factory RenderingContext2._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final Canvas canvas;
+
+ // From WebGL2RenderingContextBase
+
+ void beginQuery(int target, Query query) native;
+
+ void beginTransformFeedback(int primitiveMode) native;
+
+ void bindBufferBase(int target, int index, Buffer buffer) native;
+
+ void bindBufferRange(
+ int target, int index, Buffer buffer, int offset, int size) native;
+
+ void bindSampler(int unit, Sampler sampler) native;
+
+ void bindTransformFeedback(int target, TransformFeedback feedback) native;
+
+ void bindVertexArray(VertexArrayObject vertexArray) native;
+
+ void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0,
+ int dstY0, int dstX1, int dstY1, int mask, int filter) native;
+
+ @JSName('bufferData')
+ void bufferData2(int target, TypedData srcData, int usage, int srcOffset,
+ [int length]) native;
+
+ @JSName('bufferSubData')
+ void bufferSubData2(
+ int target, int dstByteOffset, TypedData srcData, int srcOffset,
+ [int length]) native;
+
+ void clearBufferfi(int buffer, int drawbuffer, num depth, int stencil) native;
+
+ void clearBufferfv(int buffer, int drawbuffer, value, [int srcOffset]) native;
+
+ void clearBufferiv(int buffer, int drawbuffer, value, [int srcOffset]) native;
+
+ void clearBufferuiv(int buffer, int drawbuffer, value, [int srcOffset])
+ native;
+
+ int clientWaitSync(Sync sync, int flags, int timeout) native;
+
+ @JSName('compressedTexImage2D')
+ void compressedTexImage2D2(int target, int level, int internalformat,
+ int width, int height, int border, TypedData data, int srcOffset,
+ [int srcLengthOverride]) native;
+
+ @JSName('compressedTexImage2D')
+ void compressedTexImage2D3(int target, int level, int internalformat,
+ int width, int height, int border, int imageSize, int offset) native;
+
+ void compressedTexImage3D(int target, int level, int internalformat,
+ int width, int height, int depth, int border, TypedData data,
+ [int srcOffset, int srcLengthOverride]) native;
+
+ @JSName('compressedTexImage3D')
+ void compressedTexImage3D2(
+ int target,
+ int level,
+ int internalformat,
+ int width,
+ int height,
+ int depth,
+ int border,
+ int imageSize,
+ int offset) native;
+
+ @JSName('compressedTexSubImage2D')
+ void compressedTexSubImage2D2(int target, int level, int xoffset, int yoffset,
+ int width, int height, int format, TypedData data, int srcOffset,
+ [int srcLengthOverride]) native;
+
+ @JSName('compressedTexSubImage2D')
+ void compressedTexSubImage2D3(int target, int level, int xoffset, int yoffset,
+ int width, int height, int format, int imageSize, int offset) native;
+
+ void compressedTexSubImage3D(int target, int level, int xoffset, int yoffset,
+ int zoffset, int width, int height, int depth, int format, TypedData data,
+ [int srcOffset, int srcLengthOverride]) native;
+
+ @JSName('compressedTexSubImage3D')
+ void compressedTexSubImage3D2(
+ int target,
+ int level,
+ int xoffset,
+ int yoffset,
+ int zoffset,
+ int width,
+ int height,
+ int depth,
+ int format,
+ int imageSize,
+ int offset) native;
+
+ void copyBufferSubData(int readTarget, int writeTarget, int readOffset,
+ int writeOffset, int size) native;
+
+ void copyTexSubImage3D(int target, int level, int xoffset, int yoffset,
+ int zoffset, int x, int y, int width, int height) native;
+
+ Query createQuery() native;
+
+ Sampler createSampler() native;
+
+ TransformFeedback createTransformFeedback() native;
+
+ VertexArrayObject createVertexArray() native;
+
+ void deleteQuery(Query query) native;
+
+ void deleteSampler(Sampler sampler) native;
+
+ void deleteSync(Sync sync) native;
+
+ void deleteTransformFeedback(TransformFeedback feedback) native;
+
+ void deleteVertexArray(VertexArrayObject vertexArray) native;
+
+ void drawArraysInstanced(int mode, int first, int count, int instanceCount)
+ native;
+
+ void drawBuffers(List<int> buffers) native;
+
+ void drawElementsInstanced(
+ int mode, int count, int type, int offset, int instanceCount) native;
+
+ void drawRangeElements(
+ int mode, int start, int end, int count, int type, int offset) native;
+
+ void endQuery(int target) native;
+
+ void endTransformFeedback() native;
+
+ Sync fenceSync(int condition, int flags) native;
+
+ void framebufferTextureLayer(
+ int target, int attachment, Texture texture, int level, int layer) native;
+
+ String getActiveUniformBlockName(Program program, int uniformBlockIndex)
+ native;
+
+ Object getActiveUniformBlockParameter(
+ Program program, int uniformBlockIndex, int pname) native;
+
+ Object getActiveUniforms(Program program, List<int> uniformIndices, int pname)
+ native;
+
+ void getBufferSubData(int target, int srcByteOffset, TypedData dstData,
+ [int dstOffset, int length]) native;
+
+ int getFragDataLocation(Program program, String name) native;
+
+ Object getIndexedParameter(int target, int index) native;
+
+ Object getInternalformatParameter(int target, int internalformat, int pname)
+ native;
+
+ Object getQuery(int target, int pname) native;
+
+ Object getQueryParameter(Query query, int pname) native;
+
+ Object getSamplerParameter(Sampler sampler, int pname) native;
+
+ Object getSyncParameter(Sync sync, int pname) native;
+
+ ActiveInfo getTransformFeedbackVarying(Program program, int index) native;
+
+ int getUniformBlockIndex(Program program, String uniformBlockName) native;
+
+ List<int> getUniformIndices(Program program, List<String> uniformNames) {
+ List uniformNames_1 = convertDartToNative_StringArray(uniformNames);
+ return _getUniformIndices_1(program, uniformNames_1);
+ }
+
+ @JSName('getUniformIndices')
+ List<int> _getUniformIndices_1(Program program, List uniformNames) native;
+
+ void invalidateFramebuffer(int target, List<int> attachments) native;
+
+ void invalidateSubFramebuffer(int target, List<int> attachments, int x, int y,
+ int width, int height) native;
+
+ bool isQuery(Query query) native;
+
+ bool isSampler(Sampler sampler) native;
+
+ bool isSync(Sync sync) native;
+
+ bool isTransformFeedback(TransformFeedback feedback) native;
+
+ bool isVertexArray(VertexArrayObject vertexArray) native;
+
+ void pauseTransformFeedback() native;
+
+ void readBuffer(int mode) native;
+
+ @JSName('readPixels')
+ void readPixels2(int x, int y, int width, int height, int format, int type,
+ dstData_OR_offset,
+ [int offset]) native;
+
+ void renderbufferStorageMultisample(int target, int samples,
+ int internalformat, int width, int height) native;
+
+ void resumeTransformFeedback() native;
+
+ void samplerParameterf(Sampler sampler, int pname, num param) native;
+
+ void samplerParameteri(Sampler sampler, int pname, int param) native;
+
+ void texImage2D2(
+ int target,
+ int level,
+ int internalformat,
+ int width,
+ int height,
+ int border,
+ int format,
+ int type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video,
+ [int srcOffset]) {
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is int) &&
+ srcOffset == null) {
+ _texImage2D2_1(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is ImageData) &&
+ srcOffset == null) {
+ var data_1 = convertDartToNative_ImageData(
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+ _texImage2D2_2(target, level, internalformat, width, height, border,
+ format, type, data_1);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is ImageElement) &&
+ srcOffset == null) {
+ _texImage2D2_3(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is CanvasElement) &&
+ srcOffset == null) {
+ _texImage2D2_4(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is VideoElement) &&
+ srcOffset == null) {
+ _texImage2D2_5(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is ImageBitmap) &&
+ srcOffset == null) {
+ _texImage2D2_6(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+ return;
+ }
+ if (srcOffset != null &&
+ (bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is TypedData)) {
+ _texImage2D2_7(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video,
+ srcOffset);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('texImage2D')
+ void _texImage2D2_1(target, level, internalformat, width, height, border,
+ format, type, int offset) native;
+ @JSName('texImage2D')
+ void _texImage2D2_2(target, level, internalformat, width, height, border,
+ format, type, data) native;
+ @JSName('texImage2D')
+ void _texImage2D2_3(target, level, internalformat, width, height, border,
+ format, type, ImageElement image) native;
+ @JSName('texImage2D')
+ void _texImage2D2_4(target, level, internalformat, width, height, border,
+ format, type, CanvasElement canvas) native;
+ @JSName('texImage2D')
+ void _texImage2D2_5(target, level, internalformat, width, height, border,
+ format, type, VideoElement video) native;
+ @JSName('texImage2D')
+ void _texImage2D2_6(target, level, internalformat, width, height, border,
+ format, type, ImageBitmap bitmap) native;
+ @JSName('texImage2D')
+ void _texImage2D2_7(target, level, internalformat, width, height, border,
+ format, type, TypedData srcData, srcOffset) native;
+
+ void texImage3D(
+ int target,
+ int level,
+ int internalformat,
+ int width,
+ int height,
+ int depth,
+ int border,
+ int format,
+ int type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video,
+ [int srcOffset]) {
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is int) &&
+ srcOffset == null) {
+ _texImage3D_1(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ depth,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is ImageData) &&
+ srcOffset == null) {
+ var data_1 = convertDartToNative_ImageData(
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ _texImage3D_2(target, level, internalformat, width, height, depth, border,
+ format, type, data_1);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is ImageElement) &&
+ srcOffset == null) {
+ _texImage3D_3(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ depth,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is CanvasElement) &&
+ srcOffset == null) {
+ _texImage3D_4(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ depth,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is VideoElement) &&
+ srcOffset == null) {
+ _texImage3D_5(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ depth,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is ImageBitmap) &&
+ srcOffset == null) {
+ _texImage3D_6(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ depth,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is TypedData ||
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video ==
+ null) &&
+ srcOffset == null) {
+ _texImage3D_7(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ depth,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ return;
+ }
+ if (srcOffset != null &&
+ (bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is TypedData)) {
+ _texImage3D_8(
+ target,
+ level,
+ internalformat,
+ width,
+ height,
+ depth,
+ border,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video,
+ srcOffset);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('texImage3D')
+ void _texImage3D_1(target, level, internalformat, width, height, depth,
+ border, format, type, int offset) native;
+ @JSName('texImage3D')
+ void _texImage3D_2(target, level, internalformat, width, height, depth,
+ border, format, type, data) native;
+ @JSName('texImage3D')
+ void _texImage3D_3(target, level, internalformat, width, height, depth,
+ border, format, type, ImageElement image) native;
+ @JSName('texImage3D')
+ void _texImage3D_4(target, level, internalformat, width, height, depth,
+ border, format, type, CanvasElement canvas) native;
+ @JSName('texImage3D')
+ void _texImage3D_5(target, level, internalformat, width, height, depth,
+ border, format, type, VideoElement video) native;
+ @JSName('texImage3D')
+ void _texImage3D_6(target, level, internalformat, width, height, depth,
+ border, format, type, ImageBitmap bitmap) native;
+ @JSName('texImage3D')
+ void _texImage3D_7(target, level, internalformat, width, height, depth,
+ border, format, type, TypedData pixels) native;
+ @JSName('texImage3D')
+ void _texImage3D_8(target, level, internalformat, width, height, depth,
+ border, format, type, TypedData pixels, srcOffset) native;
+
+ void texStorage2D(
+ int target, int levels, int internalformat, int width, int height) native;
+
+ void texStorage3D(int target, int levels, int internalformat, int width,
+ int height, int depth) native;
+
+ void texSubImage2D2(
+ int target,
+ int level,
+ int xoffset,
+ int yoffset,
+ int width,
+ int height,
+ int format,
+ int type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video,
+ [int srcOffset]) {
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is int) &&
+ srcOffset == null) {
+ _texSubImage2D2_1(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ width,
+ height,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is ImageData) &&
+ srcOffset == null) {
+ var data_1 = convertDartToNative_ImageData(
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+ _texSubImage2D2_2(
+ target, level, xoffset, yoffset, width, height, format, type, data_1);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is ImageElement) &&
+ srcOffset == null) {
+ _texSubImage2D2_3(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ width,
+ height,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is CanvasElement) &&
+ srcOffset == null) {
+ _texSubImage2D2_4(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ width,
+ height,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is VideoElement) &&
+ srcOffset == null) {
+ _texSubImage2D2_5(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ width,
+ height,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is ImageBitmap) &&
+ srcOffset == null) {
+ _texSubImage2D2_6(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ width,
+ height,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video);
+ return;
+ }
+ if (srcOffset != null &&
+ (bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video
+ is TypedData)) {
+ _texSubImage2D2_7(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ width,
+ height,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_srcData_OR_video,
+ srcOffset);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('texSubImage2D')
+ void _texSubImage2D2_1(target, level, xoffset, yoffset, width, height, format,
+ type, int offset) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D2_2(target, level, xoffset, yoffset, width, height, format,
+ type, data) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D2_3(target, level, xoffset, yoffset, width, height, format,
+ type, ImageElement image) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D2_4(target, level, xoffset, yoffset, width, height, format,
+ type, CanvasElement canvas) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D2_5(target, level, xoffset, yoffset, width, height, format,
+ type, VideoElement video) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D2_6(target, level, xoffset, yoffset, width, height, format,
+ type, ImageBitmap bitmap) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D2_7(target, level, xoffset, yoffset, width, height, format,
+ type, TypedData srcData, srcOffset) native;
+
+ void texSubImage3D(
+ int target,
+ int level,
+ int xoffset,
+ int yoffset,
+ int zoffset,
+ int width,
+ int height,
+ int depth,
+ int format,
+ int type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video,
+ [int srcOffset]) {
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is int) &&
+ srcOffset == null) {
+ _texSubImage3D_1(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ zoffset,
+ width,
+ height,
+ depth,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is ImageData) &&
+ srcOffset == null) {
+ var data_1 = convertDartToNative_ImageData(
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ _texSubImage3D_2(target, level, xoffset, yoffset, zoffset, width, height,
+ depth, format, type, data_1);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is ImageElement) &&
+ srcOffset == null) {
+ _texSubImage3D_3(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ zoffset,
+ width,
+ height,
+ depth,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is CanvasElement) &&
+ srcOffset == null) {
+ _texSubImage3D_4(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ zoffset,
+ width,
+ height,
+ depth,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is VideoElement) &&
+ srcOffset == null) {
+ _texSubImage3D_5(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ zoffset,
+ width,
+ height,
+ depth,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is ImageBitmap) &&
+ srcOffset == null) {
+ _texSubImage3D_6(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ zoffset,
+ width,
+ height,
+ depth,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is TypedData) &&
+ srcOffset == null) {
+ _texSubImage3D_7(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ zoffset,
+ width,
+ height,
+ depth,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video);
+ return;
+ }
+ if (srcOffset != null &&
+ (bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video
+ is TypedData)) {
+ _texSubImage3D_8(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ zoffset,
+ width,
+ height,
+ depth,
+ format,
+ type,
+ bitmap_OR_canvas_OR_data_OR_image_OR_offset_OR_pixels_OR_video,
+ srcOffset);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('texSubImage3D')
+ void _texSubImage3D_1(target, level, xoffset, yoffset, zoffset, width, height,
+ depth, format, type, int offset) native;
+ @JSName('texSubImage3D')
+ void _texSubImage3D_2(target, level, xoffset, yoffset, zoffset, width, height,
+ depth, format, type, data) native;
+ @JSName('texSubImage3D')
+ void _texSubImage3D_3(target, level, xoffset, yoffset, zoffset, width, height,
+ depth, format, type, ImageElement image) native;
+ @JSName('texSubImage3D')
+ void _texSubImage3D_4(target, level, xoffset, yoffset, zoffset, width, height,
+ depth, format, type, CanvasElement canvas) native;
+ @JSName('texSubImage3D')
+ void _texSubImage3D_5(target, level, xoffset, yoffset, zoffset, width, height,
+ depth, format, type, VideoElement video) native;
+ @JSName('texSubImage3D')
+ void _texSubImage3D_6(target, level, xoffset, yoffset, zoffset, width, height,
+ depth, format, type, ImageBitmap bitmap) native;
+ @JSName('texSubImage3D')
+ void _texSubImage3D_7(target, level, xoffset, yoffset, zoffset, width, height,
+ depth, format, type, TypedData pixels) native;
+ @JSName('texSubImage3D')
+ void _texSubImage3D_8(target, level, xoffset, yoffset, zoffset, width, height,
+ depth, format, type, TypedData pixels, srcOffset) native;
+
+ void transformFeedbackVaryings(
+ Program program, List<String> varyings, int bufferMode) {
+ List varyings_1 = convertDartToNative_StringArray(varyings);
+ _transformFeedbackVaryings_1(program, varyings_1, bufferMode);
+ return;
+ }
+
+ @JSName('transformFeedbackVaryings')
+ void _transformFeedbackVaryings_1(Program program, List varyings, bufferMode)
+ native;
+
+ @JSName('uniform1fv')
+ void uniform1fv2(UniformLocation location, v, int srcOffset, [int srcLength])
+ native;
+
+ @JSName('uniform1iv')
+ void uniform1iv2(UniformLocation location, v, int srcOffset, [int srcLength])
+ native;
+
+ void uniform1ui(UniformLocation location, int v0) native;
+
+ void uniform1uiv(UniformLocation location, v, [int srcOffset, int srcLength])
+ native;
+
+ @JSName('uniform2fv')
+ void uniform2fv2(UniformLocation location, v, int srcOffset, [int srcLength])
+ native;
+
+ @JSName('uniform2iv')
+ void uniform2iv2(UniformLocation location, v, int srcOffset, [int srcLength])
+ native;
+
+ void uniform2ui(UniformLocation location, int v0, int v1) native;
+
+ void uniform2uiv(UniformLocation location, v, [int srcOffset, int srcLength])
+ native;
+
+ @JSName('uniform3fv')
+ void uniform3fv2(UniformLocation location, v, int srcOffset, [int srcLength])
+ native;
+
+ @JSName('uniform3iv')
+ void uniform3iv2(UniformLocation location, v, int srcOffset, [int srcLength])
+ native;
+
+ void uniform3ui(UniformLocation location, int v0, int v1, int v2) native;
+
+ void uniform3uiv(UniformLocation location, v, [int srcOffset, int srcLength])
+ native;
+
+ @JSName('uniform4fv')
+ void uniform4fv2(UniformLocation location, v, int srcOffset, [int srcLength])
+ native;
+
+ @JSName('uniform4iv')
+ void uniform4iv2(UniformLocation location, v, int srcOffset, [int srcLength])
+ native;
+
+ void uniform4ui(UniformLocation location, int v0, int v1, int v2, int v3)
+ native;
+
+ void uniform4uiv(UniformLocation location, v, [int srcOffset, int srcLength])
+ native;
+
+ void uniformBlockBinding(
+ Program program, int uniformBlockIndex, int uniformBlockBinding) native;
+
+ @JSName('uniformMatrix2fv')
+ void uniformMatrix2fv2(
+ UniformLocation location, bool transpose, array, int srcOffset,
+ [int srcLength]) native;
+
+ void uniformMatrix2x3fv(UniformLocation location, bool transpose, value,
+ [int srcOffset, int srcLength]) native;
+
+ void uniformMatrix2x4fv(UniformLocation location, bool transpose, value,
+ [int srcOffset, int srcLength]) native;
+
+ @JSName('uniformMatrix3fv')
+ void uniformMatrix3fv2(
+ UniformLocation location, bool transpose, array, int srcOffset,
+ [int srcLength]) native;
+
+ void uniformMatrix3x2fv(UniformLocation location, bool transpose, value,
+ [int srcOffset, int srcLength]) native;
+
+ void uniformMatrix3x4fv(UniformLocation location, bool transpose, value,
+ [int srcOffset, int srcLength]) native;
+
+ @JSName('uniformMatrix4fv')
+ void uniformMatrix4fv2(
+ UniformLocation location, bool transpose, array, int srcOffset,
+ [int srcLength]) native;
+
+ void uniformMatrix4x2fv(UniformLocation location, bool transpose, value,
+ [int srcOffset, int srcLength]) native;
+
+ void uniformMatrix4x3fv(UniformLocation location, bool transpose, value,
+ [int srcOffset, int srcLength]) native;
+
+ void vertexAttribDivisor(int index, int divisor) native;
+
+ void vertexAttribI4i(int index, int x, int y, int z, int w) native;
+
+ void vertexAttribI4iv(int index, v) native;
+
+ void vertexAttribI4ui(int index, int x, int y, int z, int w) native;
+
+ void vertexAttribI4uiv(int index, v) native;
+
+ void vertexAttribIPointer(
+ int index, int size, int type, int stride, int offset) native;
+
+ void waitSync(Sync sync, int flags, int timeout) native;
+
+ // From WebGLRenderingContextBase
+
+ final int drawingBufferHeight;
+
+ final int drawingBufferWidth;
+
+ void activeTexture(int texture) native;
+
+ void attachShader(Program program, Shader shader) native;
+
+ void bindAttribLocation(Program program, int index, String name) native;
+
+ void bindBuffer(int target, Buffer buffer) native;
+
+ void bindFramebuffer(int target, Framebuffer framebuffer) native;
+
+ void bindRenderbuffer(int target, Renderbuffer renderbuffer) native;
+
+ void bindTexture(int target, Texture texture) native;
+
+ void blendColor(num red, num green, num blue, num alpha) native;
+
+ void blendEquation(int mode) native;
+
+ void blendEquationSeparate(int modeRGB, int modeAlpha) native;
+
+ void blendFunc(int sfactor, int dfactor) native;
+
+ void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha)
+ native;
+
+ void bufferData(int target, data_OR_size, int usage) native;
+
+ void bufferSubData(int target, int offset, data) native;
+
+ int checkFramebufferStatus(int target) native;
+
+ void clear(int mask) native;
+
+ void clearColor(num red, num green, num blue, num alpha) native;
+
+ void clearDepth(num depth) native;
+
+ void clearStencil(int s) native;
+
+ void colorMask(bool red, bool green, bool blue, bool alpha) native;
+
+ Future commit() => promiseToFuture(JS("", "#.commit()", this));
+
+ void compileShader(Shader shader) native;
+
+ void compressedTexImage2D(int target, int level, int internalformat,
+ int width, int height, int border, TypedData data) native;
+
+ void compressedTexSubImage2D(int target, int level, int xoffset, int yoffset,
+ int width, int height, int format, TypedData data) native;
+
+ void copyTexImage2D(int target, int level, int internalformat, int x, int y,
+ int width, int height, int border) native;
+
+ void copyTexSubImage2D(int target, int level, int xoffset, int yoffset, int x,
+ int y, int width, int height) native;
+
+ Buffer createBuffer() native;
+
+ Framebuffer createFramebuffer() native;
+
+ Program createProgram() native;
+
+ Renderbuffer createRenderbuffer() native;
+
+ Shader createShader(int type) native;
+
+ Texture createTexture() native;
+
+ void cullFace(int mode) native;
+
+ void deleteBuffer(Buffer buffer) native;
+
+ void deleteFramebuffer(Framebuffer framebuffer) native;
+
+ void deleteProgram(Program program) native;
+
+ void deleteRenderbuffer(Renderbuffer renderbuffer) native;
+
+ void deleteShader(Shader shader) native;
+
+ void deleteTexture(Texture texture) native;
+
+ void depthFunc(int func) native;
+
+ void depthMask(bool flag) native;
+
+ void depthRange(num zNear, num zFar) native;
+
+ void detachShader(Program program, Shader shader) native;
+
+ void disable(int cap) native;
+
+ void disableVertexAttribArray(int index) native;
+
+ void drawArrays(int mode, int first, int count) native;
+
+ void drawElements(int mode, int count, int type, int offset) native;
+
+ void enable(int cap) native;
+
+ void enableVertexAttribArray(int index) native;
+
+ void finish() native;
+
+ void flush() native;
+
+ void framebufferRenderbuffer(int target, int attachment,
+ int renderbuffertarget, Renderbuffer renderbuffer) native;
+
+ void framebufferTexture2D(int target, int attachment, int textarget,
+ Texture texture, int level) native;
+
+ void frontFace(int mode) native;
+
+ void generateMipmap(int target) native;
+
+ ActiveInfo getActiveAttrib(Program program, int index) native;
+
+ ActiveInfo getActiveUniform(Program program, int index) native;
+
+ List<Shader> getAttachedShaders(Program program) native;
+
+ int getAttribLocation(Program program, String name) native;
+
+ Object getBufferParameter(int target, int pname) native;
+
+ Map getContextAttributes() {
+ return convertNativeToDart_Dictionary(_getContextAttributes_1());
+ }
+
+ @JSName('getContextAttributes')
+ _getContextAttributes_1() native;
+
+ int getError() native;
+
+ Object getExtension(String name) native;
+
+ Object getFramebufferAttachmentParameter(
+ int target, int attachment, int pname) native;
+
+ Object getParameter(int pname) native;
+
+ String getProgramInfoLog(Program program) native;
+
+ Object getProgramParameter(Program program, int pname) native;
+
+ Object getRenderbufferParameter(int target, int pname) native;
+
+ String getShaderInfoLog(Shader shader) native;
+
+ Object getShaderParameter(Shader shader, int pname) native;
+
+ ShaderPrecisionFormat getShaderPrecisionFormat(
+ int shadertype, int precisiontype) native;
+
+ String getShaderSource(Shader shader) native;
+
+ List<String> getSupportedExtensions() native;
+
+ Object getTexParameter(int target, int pname) native;
+
+ Object getUniform(Program program, UniformLocation location) native;
+
+ UniformLocation getUniformLocation(Program program, String name) native;
+
+ Object getVertexAttrib(int index, int pname) native;
+
+ int getVertexAttribOffset(int index, int pname) native;
+
+ void hint(int target, int mode) native;
+
+ bool isBuffer(Buffer buffer) native;
+
+ bool isContextLost() native;
+
+ bool isEnabled(int cap) native;
+
+ bool isFramebuffer(Framebuffer framebuffer) native;
+
+ bool isProgram(Program program) native;
+
+ bool isRenderbuffer(Renderbuffer renderbuffer) native;
+
+ bool isShader(Shader shader) native;
+
+ bool isTexture(Texture texture) native;
+
+ void lineWidth(num width) native;
+
+ void linkProgram(Program program) native;
+
+ void pixelStorei(int pname, int param) native;
+
+ void polygonOffset(num factor, num units) native;
+
+ @JSName('readPixels')
+ void _readPixels(int x, int y, int width, int height, int format, int type,
+ TypedData pixels) native;
+
+ void renderbufferStorage(
+ int target, int internalformat, int width, int height) native;
+
+ void sampleCoverage(num value, bool invert) native;
+
+ void scissor(int x, int y, int width, int height) native;
+
+ void shaderSource(Shader shader, String string) native;
+
+ void stencilFunc(int func, int ref, int mask) native;
+
+ void stencilFuncSeparate(int face, int func, int ref, int mask) native;
+
+ void stencilMask(int mask) native;
+
+ void stencilMaskSeparate(int face, int mask) native;
+
+ void stencilOp(int fail, int zfail, int zpass) native;
+
+ void stencilOpSeparate(int face, int fail, int zfail, int zpass) native;
+
+ void texImage2D(
+ int target,
+ int level,
+ int internalformat,
+ int format_OR_width,
+ int height_OR_type,
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video,
+ [int format,
+ int type,
+ TypedData pixels]) {
+ if (type != null &&
+ format != null &&
+ (bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video is int)) {
+ _texImage2D_1(
+ target,
+ level,
+ internalformat,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video,
+ format,
+ type,
+ pixels);
+ return;
+ }
+ if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video is ImageData) &&
+ format == null &&
+ type == null &&
+ pixels == null) {
+ var pixels_1 = convertDartToNative_ImageData(
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+ _texImage2D_2(target, level, internalformat, format_OR_width,
+ height_OR_type, pixels_1);
+ return;
+ }
+ if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+ is ImageElement) &&
+ format == null &&
+ type == null &&
+ pixels == null) {
+ _texImage2D_3(
+ target,
+ level,
+ internalformat,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+ is CanvasElement) &&
+ format == null &&
+ type == null &&
+ pixels == null) {
+ _texImage2D_4(
+ target,
+ level,
+ internalformat,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+ is VideoElement) &&
+ format == null &&
+ type == null &&
+ pixels == null) {
+ _texImage2D_5(
+ target,
+ level,
+ internalformat,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video
+ is ImageBitmap) &&
+ format == null &&
+ type == null &&
+ pixels == null) {
+ _texImage2D_6(
+ target,
+ level,
+ internalformat,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_border_OR_canvas_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('texImage2D')
+ void _texImage2D_1(target, level, internalformat, width, height, int border,
+ format, type, TypedData pixels) native;
+ @JSName('texImage2D')
+ void _texImage2D_2(target, level, internalformat, format, type, pixels)
+ native;
+ @JSName('texImage2D')
+ void _texImage2D_3(
+ target, level, internalformat, format, type, ImageElement image) native;
+ @JSName('texImage2D')
+ void _texImage2D_4(
+ target, level, internalformat, format, type, CanvasElement canvas) native;
+ @JSName('texImage2D')
+ void _texImage2D_5(
+ target, level, internalformat, format, type, VideoElement video) native;
+ @JSName('texImage2D')
+ void _texImage2D_6(
+ target, level, internalformat, format, type, ImageBitmap bitmap) native;
+
+ void texParameterf(int target, int pname, num param) native;
+
+ void texParameteri(int target, int pname, int param) native;
+
+ void texSubImage2D(
+ int target,
+ int level,
+ int xoffset,
+ int yoffset,
+ int format_OR_width,
+ int height_OR_type,
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video,
+ [int type,
+ TypedData pixels]) {
+ if (type != null &&
+ (bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video is int)) {
+ _texSubImage2D_1(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video,
+ type,
+ pixels);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video is ImageData) &&
+ type == null &&
+ pixels == null) {
+ var pixels_1 = convertDartToNative_ImageData(
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+ _texSubImage2D_2(target, level, xoffset, yoffset, format_OR_width,
+ height_OR_type, pixels_1);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+ is ImageElement) &&
+ type == null &&
+ pixels == null) {
+ _texSubImage2D_3(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+ is CanvasElement) &&
+ type == null &&
+ pixels == null) {
+ _texSubImage2D_4(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+ is VideoElement) &&
+ type == null &&
+ pixels == null) {
+ _texSubImage2D_5(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ if ((bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video
+ is ImageBitmap) &&
+ type == null &&
+ pixels == null) {
+ _texSubImage2D_6(
+ target,
+ level,
+ xoffset,
+ yoffset,
+ format_OR_width,
+ height_OR_type,
+ bitmap_OR_canvas_OR_format_OR_image_OR_pixels_OR_video);
+ return;
+ }
+ throw new ArgumentError("Incorrect number or type of arguments");
+ }
+
+ @JSName('texSubImage2D')
+ void _texSubImage2D_1(target, level, xoffset, yoffset, width, height,
+ int format, type, TypedData pixels) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D_2(target, level, xoffset, yoffset, format, type, pixels)
+ native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D_3(
+ target, level, xoffset, yoffset, format, type, ImageElement image) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D_4(target, level, xoffset, yoffset, format, type,
+ CanvasElement canvas) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D_5(
+ target, level, xoffset, yoffset, format, type, VideoElement video) native;
+ @JSName('texSubImage2D')
+ void _texSubImage2D_6(
+ target, level, xoffset, yoffset, format, type, ImageBitmap bitmap) native;
+
+ void uniform1f(UniformLocation location, num x) native;
+
+ void uniform1fv(UniformLocation location, v) native;
+
+ void uniform1i(UniformLocation location, int x) native;
+
+ void uniform1iv(UniformLocation location, v) native;
+
+ void uniform2f(UniformLocation location, num x, num y) native;
+
+ void uniform2fv(UniformLocation location, v) native;
+
+ void uniform2i(UniformLocation location, int x, int y) native;
+
+ void uniform2iv(UniformLocation location, v) native;
+
+ void uniform3f(UniformLocation location, num x, num y, num z) native;
+
+ void uniform3fv(UniformLocation location, v) native;
+
+ void uniform3i(UniformLocation location, int x, int y, int z) native;
+
+ void uniform3iv(UniformLocation location, v) native;
+
+ void uniform4f(UniformLocation location, num x, num y, num z, num w) native;
+
+ void uniform4fv(UniformLocation location, v) native;
+
+ void uniform4i(UniformLocation location, int x, int y, int z, int w) native;
+
+ void uniform4iv(UniformLocation location, v) native;
+
+ void uniformMatrix2fv(UniformLocation location, bool transpose, array) native;
+
+ void uniformMatrix3fv(UniformLocation location, bool transpose, array) native;
+
+ void uniformMatrix4fv(UniformLocation location, bool transpose, array) native;
+
+ void useProgram(Program program) native;
+
+ void validateProgram(Program program) native;
+
+ void vertexAttrib1f(int indx, num x) native;
+
+ void vertexAttrib1fv(int indx, values) native;
+
+ void vertexAttrib2f(int indx, num x, num y) native;
+
+ void vertexAttrib2fv(int indx, values) native;
+
+ void vertexAttrib3f(int indx, num x, num y, num z) native;
+
+ void vertexAttrib3fv(int indx, values) native;
+
+ void vertexAttrib4f(int indx, num x, num y, num z, num w) native;
+
+ void vertexAttrib4fv(int indx, values) native;
+
+ void vertexAttribPointer(int indx, int size, int type, bool normalized,
+ int stride, int offset) native;
+
+ void viewport(int x, int y, int width, int height) native;
+
+ void readPixels(int x, int y, int width, int height, int format, int type,
+ TypedData pixels) {
+ _readPixels(x, y, width, height, format, type, pixels);
+ }
+}
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLSampler")
+class Sampler extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Sampler._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLShader")
+class Shader extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Shader._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLShaderPrecisionFormat")
+class ShaderPrecisionFormat extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory ShaderPrecisionFormat._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int precision;
+
+ final int rangeMax;
+
+ final int rangeMin;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLSync")
+class Sync extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Sync._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLTexture")
+class Texture extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory Texture._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final bool lastUploadedVideoFrameWasSkipped;
+
+ final int lastUploadedVideoHeight;
+
+ final num lastUploadedVideoTimestamp;
+
+ final int lastUploadedVideoWidth;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLTimerQueryEXT")
+class TimerQueryExt extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory TimerQueryExt._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLTransformFeedback")
+class TransformFeedback extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory TransformFeedback._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLUniformLocation")
+class UniformLocation extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory UniformLocation._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLVertexArrayObject")
+class VertexArrayObject extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VertexArrayObject._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGLVertexArrayObjectOES")
+class VertexArrayObjectOes extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory VertexArrayObjectOes._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Amalgamation of the WebGL constants from the IDL interfaces in
+/// WebGLRenderingContextBase, WebGL2RenderingContextBase, & WebGLDrawBuffers.
+/// Because the RenderingContextBase interfaces are hidden they would be
+/// replicated in more than one class (e.g., RenderingContext and
+/// RenderingContext2) to prevent that duplication these 600+ constants are
+/// defined in one abstract class (WebGL).
+@Native("WebGL")
+abstract class WebGL {
+ // To suppress missing implicit constructor warnings.
+ factory WebGL._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int ACTIVE_ATTRIBUTES = 0x8B89;
+
+ static const int ACTIVE_TEXTURE = 0x84E0;
+
+ static const int ACTIVE_UNIFORMS = 0x8B86;
+
+ static const int ACTIVE_UNIFORM_BLOCKS = 0x8A36;
+
+ static const int ALIASED_LINE_WIDTH_RANGE = 0x846E;
+
+ static const int ALIASED_POINT_SIZE_RANGE = 0x846D;
+
+ static const int ALPHA = 0x1906;
+
+ static const int ALPHA_BITS = 0x0D55;
+
+ static const int ALREADY_SIGNALED = 0x911A;
+
+ static const int ALWAYS = 0x0207;
+
+ static const int ANY_SAMPLES_PASSED = 0x8C2F;
+
+ static const int ANY_SAMPLES_PASSED_CONSERVATIVE = 0x8D6A;
+
+ static const int ARRAY_BUFFER = 0x8892;
+
+ static const int ARRAY_BUFFER_BINDING = 0x8894;
+
+ static const int ATTACHED_SHADERS = 0x8B85;
+
+ static const int BACK = 0x0405;
+
+ static const int BLEND = 0x0BE2;
+
+ static const int BLEND_COLOR = 0x8005;
+
+ static const int BLEND_DST_ALPHA = 0x80CA;
+
+ static const int BLEND_DST_RGB = 0x80C8;
+
+ static const int BLEND_EQUATION = 0x8009;
+
+ static const int BLEND_EQUATION_ALPHA = 0x883D;
+
+ static const int BLEND_EQUATION_RGB = 0x8009;
+
+ static const int BLEND_SRC_ALPHA = 0x80CB;
+
+ static const int BLEND_SRC_RGB = 0x80C9;
+
+ static const int BLUE_BITS = 0x0D54;
+
+ static const int BOOL = 0x8B56;
+
+ static const int BOOL_VEC2 = 0x8B57;
+
+ static const int BOOL_VEC3 = 0x8B58;
+
+ static const int BOOL_VEC4 = 0x8B59;
+
+ static const int BROWSER_DEFAULT_WEBGL = 0x9244;
+
+ static const int BUFFER_SIZE = 0x8764;
+
+ static const int BUFFER_USAGE = 0x8765;
+
+ static const int BYTE = 0x1400;
+
+ static const int CCW = 0x0901;
+
+ static const int CLAMP_TO_EDGE = 0x812F;
+
+ static const int COLOR = 0x1800;
+
+ static const int COLOR_ATTACHMENT0 = 0x8CE0;
+
+ static const int COLOR_ATTACHMENT0_WEBGL = 0x8CE0;
+
+ static const int COLOR_ATTACHMENT1 = 0x8CE1;
+
+ static const int COLOR_ATTACHMENT10 = 0x8CEA;
+
+ static const int COLOR_ATTACHMENT10_WEBGL = 0x8CEA;
+
+ static const int COLOR_ATTACHMENT11 = 0x8CEB;
+
+ static const int COLOR_ATTACHMENT11_WEBGL = 0x8CEB;
+
+ static const int COLOR_ATTACHMENT12 = 0x8CEC;
+
+ static const int COLOR_ATTACHMENT12_WEBGL = 0x8CEC;
+
+ static const int COLOR_ATTACHMENT13 = 0x8CED;
+
+ static const int COLOR_ATTACHMENT13_WEBGL = 0x8CED;
+
+ static const int COLOR_ATTACHMENT14 = 0x8CEE;
+
+ static const int COLOR_ATTACHMENT14_WEBGL = 0x8CEE;
+
+ static const int COLOR_ATTACHMENT15 = 0x8CEF;
+
+ static const int COLOR_ATTACHMENT15_WEBGL = 0x8CEF;
+
+ static const int COLOR_ATTACHMENT1_WEBGL = 0x8CE1;
+
+ static const int COLOR_ATTACHMENT2 = 0x8CE2;
+
+ static const int COLOR_ATTACHMENT2_WEBGL = 0x8CE2;
+
+ static const int COLOR_ATTACHMENT3 = 0x8CE3;
+
+ static const int COLOR_ATTACHMENT3_WEBGL = 0x8CE3;
+
+ static const int COLOR_ATTACHMENT4 = 0x8CE4;
+
+ static const int COLOR_ATTACHMENT4_WEBGL = 0x8CE4;
+
+ static const int COLOR_ATTACHMENT5 = 0x8CE5;
+
+ static const int COLOR_ATTACHMENT5_WEBGL = 0x8CE5;
+
+ static const int COLOR_ATTACHMENT6 = 0x8CE6;
+
+ static const int COLOR_ATTACHMENT6_WEBGL = 0x8CE6;
+
+ static const int COLOR_ATTACHMENT7 = 0x8CE7;
+
+ static const int COLOR_ATTACHMENT7_WEBGL = 0x8CE7;
+
+ static const int COLOR_ATTACHMENT8 = 0x8CE8;
+
+ static const int COLOR_ATTACHMENT8_WEBGL = 0x8CE8;
+
+ static const int COLOR_ATTACHMENT9 = 0x8CE9;
+
+ static const int COLOR_ATTACHMENT9_WEBGL = 0x8CE9;
+
+ static const int COLOR_BUFFER_BIT = 0x00004000;
+
+ static const int COLOR_CLEAR_VALUE = 0x0C22;
+
+ static const int COLOR_WRITEMASK = 0x0C23;
+
+ static const int COMPARE_REF_TO_TEXTURE = 0x884E;
+
+ static const int COMPILE_STATUS = 0x8B81;
+
+ static const int COMPRESSED_TEXTURE_FORMATS = 0x86A3;
+
+ static const int CONDITION_SATISFIED = 0x911C;
+
+ static const int CONSTANT_ALPHA = 0x8003;
+
+ static const int CONSTANT_COLOR = 0x8001;
+
+ static const int CONTEXT_LOST_WEBGL = 0x9242;
+
+ static const int COPY_READ_BUFFER = 0x8F36;
+
+ static const int COPY_READ_BUFFER_BINDING = 0x8F36;
+
+ static const int COPY_WRITE_BUFFER = 0x8F37;
+
+ static const int COPY_WRITE_BUFFER_BINDING = 0x8F37;
+
+ static const int CULL_FACE = 0x0B44;
+
+ static const int CULL_FACE_MODE = 0x0B45;
+
+ static const int CURRENT_PROGRAM = 0x8B8D;
+
+ static const int CURRENT_QUERY = 0x8865;
+
+ static const int CURRENT_VERTEX_ATTRIB = 0x8626;
+
+ static const int CW = 0x0900;
+
+ static const int DECR = 0x1E03;
+
+ static const int DECR_WRAP = 0x8508;
+
+ static const int DELETE_STATUS = 0x8B80;
+
+ static const int DEPTH = 0x1801;
+
+ static const int DEPTH24_STENCIL8 = 0x88F0;
+
+ static const int DEPTH32F_STENCIL8 = 0x8CAD;
+
+ static const int DEPTH_ATTACHMENT = 0x8D00;
+
+ static const int DEPTH_BITS = 0x0D56;
+
+ static const int DEPTH_BUFFER_BIT = 0x00000100;
+
+ static const int DEPTH_CLEAR_VALUE = 0x0B73;
+
+ static const int DEPTH_COMPONENT = 0x1902;
+
+ static const int DEPTH_COMPONENT16 = 0x81A5;
+
+ static const int DEPTH_COMPONENT24 = 0x81A6;
+
+ static const int DEPTH_COMPONENT32F = 0x8CAC;
+
+ static const int DEPTH_FUNC = 0x0B74;
+
+ static const int DEPTH_RANGE = 0x0B70;
+
+ static const int DEPTH_STENCIL = 0x84F9;
+
+ static const int DEPTH_STENCIL_ATTACHMENT = 0x821A;
+
+ static const int DEPTH_TEST = 0x0B71;
+
+ static const int DEPTH_WRITEMASK = 0x0B72;
+
+ static const int DITHER = 0x0BD0;
+
+ static const int DONT_CARE = 0x1100;
+
+ static const int DRAW_BUFFER0 = 0x8825;
+
+ static const int DRAW_BUFFER0_WEBGL = 0x8825;
+
+ static const int DRAW_BUFFER1 = 0x8826;
+
+ static const int DRAW_BUFFER10 = 0x882F;
+
+ static const int DRAW_BUFFER10_WEBGL = 0x882F;
+
+ static const int DRAW_BUFFER11 = 0x8830;
+
+ static const int DRAW_BUFFER11_WEBGL = 0x8830;
+
+ static const int DRAW_BUFFER12 = 0x8831;
+
+ static const int DRAW_BUFFER12_WEBGL = 0x8831;
+
+ static const int DRAW_BUFFER13 = 0x8832;
+
+ static const int DRAW_BUFFER13_WEBGL = 0x8832;
+
+ static const int DRAW_BUFFER14 = 0x8833;
+
+ static const int DRAW_BUFFER14_WEBGL = 0x8833;
+
+ static const int DRAW_BUFFER15 = 0x8834;
+
+ static const int DRAW_BUFFER15_WEBGL = 0x8834;
+
+ static const int DRAW_BUFFER1_WEBGL = 0x8826;
+
+ static const int DRAW_BUFFER2 = 0x8827;
+
+ static const int DRAW_BUFFER2_WEBGL = 0x8827;
+
+ static const int DRAW_BUFFER3 = 0x8828;
+
+ static const int DRAW_BUFFER3_WEBGL = 0x8828;
+
+ static const int DRAW_BUFFER4 = 0x8829;
+
+ static const int DRAW_BUFFER4_WEBGL = 0x8829;
+
+ static const int DRAW_BUFFER5 = 0x882A;
+
+ static const int DRAW_BUFFER5_WEBGL = 0x882A;
+
+ static const int DRAW_BUFFER6 = 0x882B;
+
+ static const int DRAW_BUFFER6_WEBGL = 0x882B;
+
+ static const int DRAW_BUFFER7 = 0x882C;
+
+ static const int DRAW_BUFFER7_WEBGL = 0x882C;
+
+ static const int DRAW_BUFFER8 = 0x882D;
+
+ static const int DRAW_BUFFER8_WEBGL = 0x882D;
+
+ static const int DRAW_BUFFER9 = 0x882E;
+
+ static const int DRAW_BUFFER9_WEBGL = 0x882E;
+
+ static const int DRAW_FRAMEBUFFER = 0x8CA9;
+
+ static const int DRAW_FRAMEBUFFER_BINDING = 0x8CA6;
+
+ static const int DST_ALPHA = 0x0304;
+
+ static const int DST_COLOR = 0x0306;
+
+ static const int DYNAMIC_COPY = 0x88EA;
+
+ static const int DYNAMIC_DRAW = 0x88E8;
+
+ static const int DYNAMIC_READ = 0x88E9;
+
+ static const int ELEMENT_ARRAY_BUFFER = 0x8893;
+
+ static const int ELEMENT_ARRAY_BUFFER_BINDING = 0x8895;
+
+ static const int EQUAL = 0x0202;
+
+ static const int FASTEST = 0x1101;
+
+ static const int FLOAT = 0x1406;
+
+ static const int FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD;
+
+ static const int FLOAT_MAT2 = 0x8B5A;
+
+ static const int FLOAT_MAT2x3 = 0x8B65;
+
+ static const int FLOAT_MAT2x4 = 0x8B66;
+
+ static const int FLOAT_MAT3 = 0x8B5B;
+
+ static const int FLOAT_MAT3x2 = 0x8B67;
+
+ static const int FLOAT_MAT3x4 = 0x8B68;
+
+ static const int FLOAT_MAT4 = 0x8B5C;
+
+ static const int FLOAT_MAT4x2 = 0x8B69;
+
+ static const int FLOAT_MAT4x3 = 0x8B6A;
+
+ static const int FLOAT_VEC2 = 0x8B50;
+
+ static const int FLOAT_VEC3 = 0x8B51;
+
+ static const int FLOAT_VEC4 = 0x8B52;
+
+ static const int FRAGMENT_SHADER = 0x8B30;
+
+ static const int FRAGMENT_SHADER_DERIVATIVE_HINT = 0x8B8B;
+
+ static const int FRAMEBUFFER = 0x8D40;
+
+ static const int FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE = 0x8215;
+
+ static const int FRAMEBUFFER_ATTACHMENT_BLUE_SIZE = 0x8214;
+
+ static const int FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING = 0x8210;
+
+ static const int FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE = 0x8211;
+
+ static const int FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE = 0x8216;
+
+ static const int FRAMEBUFFER_ATTACHMENT_GREEN_SIZE = 0x8213;
+
+ static const int FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1;
+
+ static const int FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0;
+
+ static const int FRAMEBUFFER_ATTACHMENT_RED_SIZE = 0x8212;
+
+ static const int FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE = 0x8217;
+
+ static const int FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3;
+
+ static const int FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER = 0x8CD4;
+
+ static const int FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2;
+
+ static const int FRAMEBUFFER_BINDING = 0x8CA6;
+
+ static const int FRAMEBUFFER_COMPLETE = 0x8CD5;
+
+ static const int FRAMEBUFFER_DEFAULT = 0x8218;
+
+ static const int FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6;
+
+ static const int FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9;
+
+ static const int FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7;
+
+ static const int FRAMEBUFFER_INCOMPLETE_MULTISAMPLE = 0x8D56;
+
+ static const int FRAMEBUFFER_UNSUPPORTED = 0x8CDD;
+
+ static const int FRONT = 0x0404;
+
+ static const int FRONT_AND_BACK = 0x0408;
+
+ static const int FRONT_FACE = 0x0B46;
+
+ static const int FUNC_ADD = 0x8006;
+
+ static const int FUNC_REVERSE_SUBTRACT = 0x800B;
+
+ static const int FUNC_SUBTRACT = 0x800A;
+
+ static const int GENERATE_MIPMAP_HINT = 0x8192;
+
+ static const int GEQUAL = 0x0206;
+
+ static const int GREATER = 0x0204;
+
+ static const int GREEN_BITS = 0x0D53;
+
+ static const int HALF_FLOAT = 0x140B;
+
+ static const int HIGH_FLOAT = 0x8DF2;
+
+ static const int HIGH_INT = 0x8DF5;
+
+ static const int IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B;
+
+ static const int IMPLEMENTATION_COLOR_READ_TYPE = 0x8B9A;
+
+ static const int INCR = 0x1E02;
+
+ static const int INCR_WRAP = 0x8507;
+
+ static const int INT = 0x1404;
+
+ static const int INTERLEAVED_ATTRIBS = 0x8C8C;
+
+ static const int INT_2_10_10_10_REV = 0x8D9F;
+
+ static const int INT_SAMPLER_2D = 0x8DCA;
+
+ static const int INT_SAMPLER_2D_ARRAY = 0x8DCF;
+
+ static const int INT_SAMPLER_3D = 0x8DCB;
+
+ static const int INT_SAMPLER_CUBE = 0x8DCC;
+
+ static const int INT_VEC2 = 0x8B53;
+
+ static const int INT_VEC3 = 0x8B54;
+
+ static const int INT_VEC4 = 0x8B55;
+
+ static const int INVALID_ENUM = 0x0500;
+
+ static const int INVALID_FRAMEBUFFER_OPERATION = 0x0506;
+
+ static const int INVALID_INDEX = 0xFFFFFFFF;
+
+ static const int INVALID_OPERATION = 0x0502;
+
+ static const int INVALID_VALUE = 0x0501;
+
+ static const int INVERT = 0x150A;
+
+ static const int KEEP = 0x1E00;
+
+ static const int LEQUAL = 0x0203;
+
+ static const int LESS = 0x0201;
+
+ static const int LINEAR = 0x2601;
+
+ static const int LINEAR_MIPMAP_LINEAR = 0x2703;
+
+ static const int LINEAR_MIPMAP_NEAREST = 0x2701;
+
+ static const int LINES = 0x0001;
+
+ static const int LINE_LOOP = 0x0002;
+
+ static const int LINE_STRIP = 0x0003;
+
+ static const int LINE_WIDTH = 0x0B21;
+
+ static const int LINK_STATUS = 0x8B82;
+
+ static const int LOW_FLOAT = 0x8DF0;
+
+ static const int LOW_INT = 0x8DF3;
+
+ static const int LUMINANCE = 0x1909;
+
+ static const int LUMINANCE_ALPHA = 0x190A;
+
+ static const int MAX = 0x8008;
+
+ static const int MAX_3D_TEXTURE_SIZE = 0x8073;
+
+ static const int MAX_ARRAY_TEXTURE_LAYERS = 0x88FF;
+
+ static const int MAX_CLIENT_WAIT_TIMEOUT_WEBGL = 0x9247;
+
+ static const int MAX_COLOR_ATTACHMENTS = 0x8CDF;
+
+ static const int MAX_COLOR_ATTACHMENTS_WEBGL = 0x8CDF;
+
+ static const int MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS = 0x8A33;
+
+ static const int MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D;
+
+ static const int MAX_COMBINED_UNIFORM_BLOCKS = 0x8A2E;
+
+ static const int MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS = 0x8A31;
+
+ static const int MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C;
+
+ static const int MAX_DRAW_BUFFERS = 0x8824;
+
+ static const int MAX_DRAW_BUFFERS_WEBGL = 0x8824;
+
+ static const int MAX_ELEMENTS_INDICES = 0x80E9;
+
+ static const int MAX_ELEMENTS_VERTICES = 0x80E8;
+
+ static const int MAX_ELEMENT_INDEX = 0x8D6B;
+
+ static const int MAX_FRAGMENT_INPUT_COMPONENTS = 0x9125;
+
+ static const int MAX_FRAGMENT_UNIFORM_BLOCKS = 0x8A2D;
+
+ static const int MAX_FRAGMENT_UNIFORM_COMPONENTS = 0x8B49;
+
+ static const int MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD;
+
+ static const int MAX_PROGRAM_TEXEL_OFFSET = 0x8905;
+
+ static const int MAX_RENDERBUFFER_SIZE = 0x84E8;
+
+ static const int MAX_SAMPLES = 0x8D57;
+
+ static const int MAX_SERVER_WAIT_TIMEOUT = 0x9111;
+
+ static const int MAX_TEXTURE_IMAGE_UNITS = 0x8872;
+
+ static const int MAX_TEXTURE_LOD_BIAS = 0x84FD;
+
+ static const int MAX_TEXTURE_SIZE = 0x0D33;
+
+ static const int MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = 0x8C8A;
+
+ static const int MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 0x8C8B;
+
+ static const int MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS = 0x8C80;
+
+ static const int MAX_UNIFORM_BLOCK_SIZE = 0x8A30;
+
+ static const int MAX_UNIFORM_BUFFER_BINDINGS = 0x8A2F;
+
+ static const int MAX_VARYING_COMPONENTS = 0x8B4B;
+
+ static const int MAX_VARYING_VECTORS = 0x8DFC;
+
+ static const int MAX_VERTEX_ATTRIBS = 0x8869;
+
+ static const int MAX_VERTEX_OUTPUT_COMPONENTS = 0x9122;
+
+ static const int MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C;
+
+ static const int MAX_VERTEX_UNIFORM_BLOCKS = 0x8A2B;
+
+ static const int MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A;
+
+ static const int MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB;
+
+ static const int MAX_VIEWPORT_DIMS = 0x0D3A;
+
+ static const int MEDIUM_FLOAT = 0x8DF1;
+
+ static const int MEDIUM_INT = 0x8DF4;
+
+ static const int MIN = 0x8007;
+
+ static const int MIN_PROGRAM_TEXEL_OFFSET = 0x8904;
+
+ static const int MIRRORED_REPEAT = 0x8370;
+
+ static const int NEAREST = 0x2600;
+
+ static const int NEAREST_MIPMAP_LINEAR = 0x2702;
+
+ static const int NEAREST_MIPMAP_NEAREST = 0x2700;
+
+ static const int NEVER = 0x0200;
+
+ static const int NICEST = 0x1102;
+
+ static const int NONE = 0;
+
+ static const int NOTEQUAL = 0x0205;
+
+ static const int NO_ERROR = 0;
+
+ static const int OBJECT_TYPE = 0x9112;
+
+ static const int ONE = 1;
+
+ static const int ONE_MINUS_CONSTANT_ALPHA = 0x8004;
+
+ static const int ONE_MINUS_CONSTANT_COLOR = 0x8002;
+
+ static const int ONE_MINUS_DST_ALPHA = 0x0305;
+
+ static const int ONE_MINUS_DST_COLOR = 0x0307;
+
+ static const int ONE_MINUS_SRC_ALPHA = 0x0303;
+
+ static const int ONE_MINUS_SRC_COLOR = 0x0301;
+
+ static const int OUT_OF_MEMORY = 0x0505;
+
+ static const int PACK_ALIGNMENT = 0x0D05;
+
+ static const int PACK_ROW_LENGTH = 0x0D02;
+
+ static const int PACK_SKIP_PIXELS = 0x0D04;
+
+ static const int PACK_SKIP_ROWS = 0x0D03;
+
+ static const int PIXEL_PACK_BUFFER = 0x88EB;
+
+ static const int PIXEL_PACK_BUFFER_BINDING = 0x88ED;
+
+ static const int PIXEL_UNPACK_BUFFER = 0x88EC;
+
+ static const int PIXEL_UNPACK_BUFFER_BINDING = 0x88EF;
+
+ static const int POINTS = 0x0000;
+
+ static const int POLYGON_OFFSET_FACTOR = 0x8038;
+
+ static const int POLYGON_OFFSET_FILL = 0x8037;
+
+ static const int POLYGON_OFFSET_UNITS = 0x2A00;
+
+ static const int QUERY_RESULT = 0x8866;
+
+ static const int QUERY_RESULT_AVAILABLE = 0x8867;
+
+ static const int R11F_G11F_B10F = 0x8C3A;
+
+ static const int R16F = 0x822D;
+
+ static const int R16I = 0x8233;
+
+ static const int R16UI = 0x8234;
+
+ static const int R32F = 0x822E;
+
+ static const int R32I = 0x8235;
+
+ static const int R32UI = 0x8236;
+
+ static const int R8 = 0x8229;
+
+ static const int R8I = 0x8231;
+
+ static const int R8UI = 0x8232;
+
+ static const int R8_SNORM = 0x8F94;
+
+ static const int RASTERIZER_DISCARD = 0x8C89;
+
+ static const int READ_BUFFER = 0x0C02;
+
+ static const int READ_FRAMEBUFFER = 0x8CA8;
+
+ static const int READ_FRAMEBUFFER_BINDING = 0x8CAA;
+
+ static const int RED = 0x1903;
+
+ static const int RED_BITS = 0x0D52;
+
+ static const int RED_INTEGER = 0x8D94;
+
+ static const int RENDERBUFFER = 0x8D41;
+
+ static const int RENDERBUFFER_ALPHA_SIZE = 0x8D53;
+
+ static const int RENDERBUFFER_BINDING = 0x8CA7;
+
+ static const int RENDERBUFFER_BLUE_SIZE = 0x8D52;
+
+ static const int RENDERBUFFER_DEPTH_SIZE = 0x8D54;
+
+ static const int RENDERBUFFER_GREEN_SIZE = 0x8D51;
+
+ static const int RENDERBUFFER_HEIGHT = 0x8D43;
+
+ static const int RENDERBUFFER_INTERNAL_FORMAT = 0x8D44;
+
+ static const int RENDERBUFFER_RED_SIZE = 0x8D50;
+
+ static const int RENDERBUFFER_SAMPLES = 0x8CAB;
+
+ static const int RENDERBUFFER_STENCIL_SIZE = 0x8D55;
+
+ static const int RENDERBUFFER_WIDTH = 0x8D42;
+
+ static const int RENDERER = 0x1F01;
+
+ static const int REPEAT = 0x2901;
+
+ static const int REPLACE = 0x1E01;
+
+ static const int RG = 0x8227;
+
+ static const int RG16F = 0x822F;
+
+ static const int RG16I = 0x8239;
+
+ static const int RG16UI = 0x823A;
+
+ static const int RG32F = 0x8230;
+
+ static const int RG32I = 0x823B;
+
+ static const int RG32UI = 0x823C;
+
+ static const int RG8 = 0x822B;
+
+ static const int RG8I = 0x8237;
+
+ static const int RG8UI = 0x8238;
+
+ static const int RG8_SNORM = 0x8F95;
+
+ static const int RGB = 0x1907;
+
+ static const int RGB10_A2 = 0x8059;
+
+ static const int RGB10_A2UI = 0x906F;
+
+ static const int RGB16F = 0x881B;
+
+ static const int RGB16I = 0x8D89;
+
+ static const int RGB16UI = 0x8D77;
+
+ static const int RGB32F = 0x8815;
+
+ static const int RGB32I = 0x8D83;
+
+ static const int RGB32UI = 0x8D71;
+
+ static const int RGB565 = 0x8D62;
+
+ static const int RGB5_A1 = 0x8057;
+
+ static const int RGB8 = 0x8051;
+
+ static const int RGB8I = 0x8D8F;
+
+ static const int RGB8UI = 0x8D7D;
+
+ static const int RGB8_SNORM = 0x8F96;
+
+ static const int RGB9_E5 = 0x8C3D;
+
+ static const int RGBA = 0x1908;
+
+ static const int RGBA16F = 0x881A;
+
+ static const int RGBA16I = 0x8D88;
+
+ static const int RGBA16UI = 0x8D76;
+
+ static const int RGBA32F = 0x8814;
+
+ static const int RGBA32I = 0x8D82;
+
+ static const int RGBA32UI = 0x8D70;
+
+ static const int RGBA4 = 0x8056;
+
+ static const int RGBA8 = 0x8058;
+
+ static const int RGBA8I = 0x8D8E;
+
+ static const int RGBA8UI = 0x8D7C;
+
+ static const int RGBA8_SNORM = 0x8F97;
+
+ static const int RGBA_INTEGER = 0x8D99;
+
+ static const int RGB_INTEGER = 0x8D98;
+
+ static const int RG_INTEGER = 0x8228;
+
+ static const int SAMPLER_2D = 0x8B5E;
+
+ static const int SAMPLER_2D_ARRAY = 0x8DC1;
+
+ static const int SAMPLER_2D_ARRAY_SHADOW = 0x8DC4;
+
+ static const int SAMPLER_2D_SHADOW = 0x8B62;
+
+ static const int SAMPLER_3D = 0x8B5F;
+
+ static const int SAMPLER_BINDING = 0x8919;
+
+ static const int SAMPLER_CUBE = 0x8B60;
+
+ static const int SAMPLER_CUBE_SHADOW = 0x8DC5;
+
+ static const int SAMPLES = 0x80A9;
+
+ static const int SAMPLE_ALPHA_TO_COVERAGE = 0x809E;
+
+ static const int SAMPLE_BUFFERS = 0x80A8;
+
+ static const int SAMPLE_COVERAGE = 0x80A0;
+
+ static const int SAMPLE_COVERAGE_INVERT = 0x80AB;
+
+ static const int SAMPLE_COVERAGE_VALUE = 0x80AA;
+
+ static const int SCISSOR_BOX = 0x0C10;
+
+ static const int SCISSOR_TEST = 0x0C11;
+
+ static const int SEPARATE_ATTRIBS = 0x8C8D;
+
+ static const int SHADER_TYPE = 0x8B4F;
+
+ static const int SHADING_LANGUAGE_VERSION = 0x8B8C;
+
+ static const int SHORT = 0x1402;
+
+ static const int SIGNALED = 0x9119;
+
+ static const int SIGNED_NORMALIZED = 0x8F9C;
+
+ static const int SRC_ALPHA = 0x0302;
+
+ static const int SRC_ALPHA_SATURATE = 0x0308;
+
+ static const int SRC_COLOR = 0x0300;
+
+ static const int SRGB = 0x8C40;
+
+ static const int SRGB8 = 0x8C41;
+
+ static const int SRGB8_ALPHA8 = 0x8C43;
+
+ static const int STATIC_COPY = 0x88E6;
+
+ static const int STATIC_DRAW = 0x88E4;
+
+ static const int STATIC_READ = 0x88E5;
+
+ static const int STENCIL = 0x1802;
+
+ static const int STENCIL_ATTACHMENT = 0x8D20;
+
+ static const int STENCIL_BACK_FAIL = 0x8801;
+
+ static const int STENCIL_BACK_FUNC = 0x8800;
+
+ static const int STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802;
+
+ static const int STENCIL_BACK_PASS_DEPTH_PASS = 0x8803;
+
+ static const int STENCIL_BACK_REF = 0x8CA3;
+
+ static const int STENCIL_BACK_VALUE_MASK = 0x8CA4;
+
+ static const int STENCIL_BACK_WRITEMASK = 0x8CA5;
+
+ static const int STENCIL_BITS = 0x0D57;
+
+ static const int STENCIL_BUFFER_BIT = 0x00000400;
+
+ static const int STENCIL_CLEAR_VALUE = 0x0B91;
+
+ static const int STENCIL_FAIL = 0x0B94;
+
+ static const int STENCIL_FUNC = 0x0B92;
+
+ static const int STENCIL_INDEX8 = 0x8D48;
+
+ static const int STENCIL_PASS_DEPTH_FAIL = 0x0B95;
+
+ static const int STENCIL_PASS_DEPTH_PASS = 0x0B96;
+
+ static const int STENCIL_REF = 0x0B97;
+
+ static const int STENCIL_TEST = 0x0B90;
+
+ static const int STENCIL_VALUE_MASK = 0x0B93;
+
+ static const int STENCIL_WRITEMASK = 0x0B98;
+
+ static const int STREAM_COPY = 0x88E2;
+
+ static const int STREAM_DRAW = 0x88E0;
+
+ static const int STREAM_READ = 0x88E1;
+
+ static const int SUBPIXEL_BITS = 0x0D50;
+
+ static const int SYNC_CONDITION = 0x9113;
+
+ static const int SYNC_FENCE = 0x9116;
+
+ static const int SYNC_FLAGS = 0x9115;
+
+ static const int SYNC_FLUSH_COMMANDS_BIT = 0x00000001;
+
+ static const int SYNC_GPU_COMMANDS_COMPLETE = 0x9117;
+
+ static const int SYNC_STATUS = 0x9114;
+
+ static const int TEXTURE = 0x1702;
+
+ static const int TEXTURE0 = 0x84C0;
+
+ static const int TEXTURE1 = 0x84C1;
+
+ static const int TEXTURE10 = 0x84CA;
+
+ static const int TEXTURE11 = 0x84CB;
+
+ static const int TEXTURE12 = 0x84CC;
+
+ static const int TEXTURE13 = 0x84CD;
+
+ static const int TEXTURE14 = 0x84CE;
+
+ static const int TEXTURE15 = 0x84CF;
+
+ static const int TEXTURE16 = 0x84D0;
+
+ static const int TEXTURE17 = 0x84D1;
+
+ static const int TEXTURE18 = 0x84D2;
+
+ static const int TEXTURE19 = 0x84D3;
+
+ static const int TEXTURE2 = 0x84C2;
+
+ static const int TEXTURE20 = 0x84D4;
+
+ static const int TEXTURE21 = 0x84D5;
+
+ static const int TEXTURE22 = 0x84D6;
+
+ static const int TEXTURE23 = 0x84D7;
+
+ static const int TEXTURE24 = 0x84D8;
+
+ static const int TEXTURE25 = 0x84D9;
+
+ static const int TEXTURE26 = 0x84DA;
+
+ static const int TEXTURE27 = 0x84DB;
+
+ static const int TEXTURE28 = 0x84DC;
+
+ static const int TEXTURE29 = 0x84DD;
+
+ static const int TEXTURE3 = 0x84C3;
+
+ static const int TEXTURE30 = 0x84DE;
+
+ static const int TEXTURE31 = 0x84DF;
+
+ static const int TEXTURE4 = 0x84C4;
+
+ static const int TEXTURE5 = 0x84C5;
+
+ static const int TEXTURE6 = 0x84C6;
+
+ static const int TEXTURE7 = 0x84C7;
+
+ static const int TEXTURE8 = 0x84C8;
+
+ static const int TEXTURE9 = 0x84C9;
+
+ static const int TEXTURE_2D = 0x0DE1;
+
+ static const int TEXTURE_2D_ARRAY = 0x8C1A;
+
+ static const int TEXTURE_3D = 0x806F;
+
+ static const int TEXTURE_BASE_LEVEL = 0x813C;
+
+ static const int TEXTURE_BINDING_2D = 0x8069;
+
+ static const int TEXTURE_BINDING_2D_ARRAY = 0x8C1D;
+
+ static const int TEXTURE_BINDING_3D = 0x806A;
+
+ static const int TEXTURE_BINDING_CUBE_MAP = 0x8514;
+
+ static const int TEXTURE_COMPARE_FUNC = 0x884D;
+
+ static const int TEXTURE_COMPARE_MODE = 0x884C;
+
+ static const int TEXTURE_CUBE_MAP = 0x8513;
+
+ static const int TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516;
+
+ static const int TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518;
+
+ static const int TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A;
+
+ static const int TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515;
+
+ static const int TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517;
+
+ static const int TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519;
+
+ static const int TEXTURE_IMMUTABLE_FORMAT = 0x912F;
+
+ static const int TEXTURE_IMMUTABLE_LEVELS = 0x82DF;
+
+ static const int TEXTURE_MAG_FILTER = 0x2800;
+
+ static const int TEXTURE_MAX_LEVEL = 0x813D;
+
+ static const int TEXTURE_MAX_LOD = 0x813B;
+
+ static const int TEXTURE_MIN_FILTER = 0x2801;
+
+ static const int TEXTURE_MIN_LOD = 0x813A;
+
+ static const int TEXTURE_WRAP_R = 0x8072;
+
+ static const int TEXTURE_WRAP_S = 0x2802;
+
+ static const int TEXTURE_WRAP_T = 0x2803;
+
+ static const int TIMEOUT_EXPIRED = 0x911B;
+
+ static const int TIMEOUT_IGNORED = -1;
+
+ static const int TRANSFORM_FEEDBACK = 0x8E22;
+
+ static const int TRANSFORM_FEEDBACK_ACTIVE = 0x8E24;
+
+ static const int TRANSFORM_FEEDBACK_BINDING = 0x8E25;
+
+ static const int TRANSFORM_FEEDBACK_BUFFER = 0x8C8E;
+
+ static const int TRANSFORM_FEEDBACK_BUFFER_BINDING = 0x8C8F;
+
+ static const int TRANSFORM_FEEDBACK_BUFFER_MODE = 0x8C7F;
+
+ static const int TRANSFORM_FEEDBACK_BUFFER_SIZE = 0x8C85;
+
+ static const int TRANSFORM_FEEDBACK_BUFFER_START = 0x8C84;
+
+ static const int TRANSFORM_FEEDBACK_PAUSED = 0x8E23;
+
+ static const int TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = 0x8C88;
+
+ static const int TRANSFORM_FEEDBACK_VARYINGS = 0x8C83;
+
+ static const int TRIANGLES = 0x0004;
+
+ static const int TRIANGLE_FAN = 0x0006;
+
+ static const int TRIANGLE_STRIP = 0x0005;
+
+ static const int UNIFORM_ARRAY_STRIDE = 0x8A3C;
+
+ static const int UNIFORM_BLOCK_ACTIVE_UNIFORMS = 0x8A42;
+
+ static const int UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES = 0x8A43;
+
+ static const int UNIFORM_BLOCK_BINDING = 0x8A3F;
+
+ static const int UNIFORM_BLOCK_DATA_SIZE = 0x8A40;
+
+ static const int UNIFORM_BLOCK_INDEX = 0x8A3A;
+
+ static const int UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = 0x8A46;
+
+ static const int UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER = 0x8A44;
+
+ static const int UNIFORM_BUFFER = 0x8A11;
+
+ static const int UNIFORM_BUFFER_BINDING = 0x8A28;
+
+ static const int UNIFORM_BUFFER_OFFSET_ALIGNMENT = 0x8A34;
+
+ static const int UNIFORM_BUFFER_SIZE = 0x8A2A;
+
+ static const int UNIFORM_BUFFER_START = 0x8A29;
+
+ static const int UNIFORM_IS_ROW_MAJOR = 0x8A3E;
+
+ static const int UNIFORM_MATRIX_STRIDE = 0x8A3D;
+
+ static const int UNIFORM_OFFSET = 0x8A3B;
+
+ static const int UNIFORM_SIZE = 0x8A38;
+
+ static const int UNIFORM_TYPE = 0x8A37;
+
+ static const int UNPACK_ALIGNMENT = 0x0CF5;
+
+ static const int UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243;
+
+ static const int UNPACK_FLIP_Y_WEBGL = 0x9240;
+
+ static const int UNPACK_IMAGE_HEIGHT = 0x806E;
+
+ static const int UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241;
+
+ static const int UNPACK_ROW_LENGTH = 0x0CF2;
+
+ static const int UNPACK_SKIP_IMAGES = 0x806D;
+
+ static const int UNPACK_SKIP_PIXELS = 0x0CF4;
+
+ static const int UNPACK_SKIP_ROWS = 0x0CF3;
+
+ static const int UNSIGNALED = 0x9118;
+
+ static const int UNSIGNED_BYTE = 0x1401;
+
+ static const int UNSIGNED_INT = 0x1405;
+
+ static const int UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B;
+
+ static const int UNSIGNED_INT_24_8 = 0x84FA;
+
+ static const int UNSIGNED_INT_2_10_10_10_REV = 0x8368;
+
+ static const int UNSIGNED_INT_5_9_9_9_REV = 0x8C3E;
+
+ static const int UNSIGNED_INT_SAMPLER_2D = 0x8DD2;
+
+ static const int UNSIGNED_INT_SAMPLER_2D_ARRAY = 0x8DD7;
+
+ static const int UNSIGNED_INT_SAMPLER_3D = 0x8DD3;
+
+ static const int UNSIGNED_INT_SAMPLER_CUBE = 0x8DD4;
+
+ static const int UNSIGNED_INT_VEC2 = 0x8DC6;
+
+ static const int UNSIGNED_INT_VEC3 = 0x8DC7;
+
+ static const int UNSIGNED_INT_VEC4 = 0x8DC8;
+
+ static const int UNSIGNED_NORMALIZED = 0x8C17;
+
+ static const int UNSIGNED_SHORT = 0x1403;
+
+ static const int UNSIGNED_SHORT_4_4_4_4 = 0x8033;
+
+ static const int UNSIGNED_SHORT_5_5_5_1 = 0x8034;
+
+ static const int UNSIGNED_SHORT_5_6_5 = 0x8363;
+
+ static const int VALIDATE_STATUS = 0x8B83;
+
+ static const int VENDOR = 0x1F00;
+
+ static const int VERSION = 0x1F02;
+
+ static const int VERTEX_ARRAY_BINDING = 0x85B5;
+
+ static const int VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F;
+
+ static const int VERTEX_ATTRIB_ARRAY_DIVISOR = 0x88FE;
+
+ static const int VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622;
+
+ static const int VERTEX_ATTRIB_ARRAY_INTEGER = 0x88FD;
+
+ static const int VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A;
+
+ static const int VERTEX_ATTRIB_ARRAY_POINTER = 0x8645;
+
+ static const int VERTEX_ATTRIB_ARRAY_SIZE = 0x8623;
+
+ static const int VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624;
+
+ static const int VERTEX_ATTRIB_ARRAY_TYPE = 0x8625;
+
+ static const int VERTEX_SHADER = 0x8B31;
+
+ static const int VIEWPORT = 0x0BA2;
+
+ static const int WAIT_FAILED = 0x911D;
+
+ static const int ZERO = 0;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("WebGL2RenderingContextBase")
+abstract class _WebGL2RenderingContextBase extends Interceptor
+ implements _WebGLRenderingContextBase {
+ // To suppress missing implicit constructor warnings.
+ factory _WebGL2RenderingContextBase._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ // From WebGLRenderingContextBase
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class _WebGLRenderingContextBase extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory _WebGLRenderingContextBase._() {
+ throw new UnsupportedError("Not supported");
+ }
+}
diff --git a/sdk_nnbd/lib/web_sql/dart2js/web_sql_dart2js.dart b/sdk_nnbd/lib/web_sql/dart2js/web_sql_dart2js.dart
new file mode 100644
index 0000000..0f703f9
--- /dev/null
+++ b/sdk_nnbd/lib/web_sql/dart2js/web_sql_dart2js.dart
@@ -0,0 +1,306 @@
+/**
+ * An API for storing data in the browser that can be queried with SQL.
+ *
+ * **Caution:** this specification is no longer actively maintained by the Web
+ * Applications Working Group and may be removed at any time.
+ * See [the W3C Web SQL Database specification](http://www.w3.org/TR/webdatabase/)
+ * for more information.
+ *
+ * The [dart:indexed_db] APIs is a recommended alternatives.
+ *
+ * {@category Web}
+ */
+library dart.dom.web_sql;
+
+import 'dart:async';
+import 'dart:collection' hide LinkedList, LinkedListEntry;
+import 'dart:_internal' show FixedLengthListMixin;
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:_foreign_helper' show JS;
+import 'dart:_interceptors' show Interceptor;
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:audio library.
+
+import 'dart:_js_helper'
+ show
+ applyExtension,
+ convertDartClosureToJS,
+ Creates,
+ JSName,
+ Native,
+ JavaScriptIndexingBehavior;
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void SqlStatementCallback(
+ SqlTransaction transaction, SqlResultSet resultSet);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void SqlStatementErrorCallback(
+ SqlTransaction transaction, SqlError error);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void SqlTransactionCallback(SqlTransaction transaction);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+typedef void SqlTransactionErrorCallback(SqlError error);
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Native("Database")
+class SqlDatabase extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory SqlDatabase._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ /// Checks if this type is supported on the current platform.
+ static bool get supported => JS('bool', '!!(window.openDatabase)');
+
+ final String version;
+
+ @JSName('changeVersion')
+ /**
+ * Atomically update the database version to [newVersion], asynchronously
+ * running [callback] on the [SqlTransaction] representing this
+ * [changeVersion] transaction.
+ *
+ * If [callback] runs successfully, then [successCallback] is called.
+ * Otherwise, [errorCallback] is called.
+ *
+ * [oldVersion] should match the database's current [version] exactly.
+ *
+ * See also:
+ *
+ * * [Database.changeVersion](http://www.w3.org/TR/webdatabase/#dom-database-changeversion) from W3C.
+ */
+ void _changeVersion(String oldVersion, String newVersion,
+ [SqlTransactionCallback callback,
+ SqlTransactionErrorCallback errorCallback,
+ VoidCallback successCallback]) native;
+
+ @JSName('changeVersion')
+ /**
+ * Atomically update the database version to [newVersion], asynchronously
+ * running [callback] on the [SqlTransaction] representing this
+ * [changeVersion] transaction.
+ *
+ * If [callback] runs successfully, then [successCallback] is called.
+ * Otherwise, [errorCallback] is called.
+ *
+ * [oldVersion] should match the database's current [version] exactly.
+ *
+ * See also:
+ *
+ * * [Database.changeVersion](http://www.w3.org/TR/webdatabase/#dom-database-changeversion) from W3C.
+ */
+ Future<SqlTransaction> changeVersion(String oldVersion, String newVersion) {
+ var completer = new Completer<SqlTransaction>();
+ _changeVersion(oldVersion, newVersion, (value) {
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ @JSName('readTransaction')
+ void _readTransaction(SqlTransactionCallback callback,
+ [SqlTransactionErrorCallback errorCallback,
+ VoidCallback successCallback]) native;
+
+ @JSName('readTransaction')
+ Future<SqlTransaction> readTransaction() {
+ var completer = new Completer<SqlTransaction>();
+ _readTransaction((value) {
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+
+ void transaction(SqlTransactionCallback callback,
+ [SqlTransactionErrorCallback errorCallback,
+ VoidCallback successCallback]) native;
+
+ @JSName('transaction')
+ Future<SqlTransaction> transaction_future() {
+ var completer = new Completer<SqlTransaction>();
+ transaction((value) {
+ applyExtension('SQLTransaction', value);
+ completer.complete(value);
+ }, (error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SQLError")
+class SqlError extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory SqlError._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ static const int CONSTRAINT_ERR = 6;
+
+ static const int DATABASE_ERR = 1;
+
+ static const int QUOTA_ERR = 4;
+
+ static const int SYNTAX_ERR = 5;
+
+ static const int TIMEOUT_ERR = 7;
+
+ static const int TOO_LARGE_ERR = 3;
+
+ static const int UNKNOWN_ERR = 0;
+
+ static const int VERSION_ERR = 2;
+
+ final int code;
+
+ final String message;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SQLResultSet")
+class SqlResultSet extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory SqlResultSet._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ final int insertId;
+
+ final SqlResultSetRowList rows;
+
+ final int rowsAffected;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Native("SQLResultSetRowList")
+class SqlResultSetRowList extends Interceptor
+ with ListMixin<Map>, ImmutableListMixin<Map>
+ implements List<Map> {
+ // To suppress missing implicit constructor warnings.
+ factory SqlResultSetRowList._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ int get length => JS("int", "#.length", this);
+
+ Map operator [](int index) {
+ if (JS("bool", "# >>> 0 !== # || # >= #", index, index, index, length))
+ throw new RangeError.index(index, this);
+ return this.item(index);
+ }
+
+ void operator []=(int index, Map value) {
+ throw new UnsupportedError("Cannot assign element of immutable List.");
+ }
+ // -- start List<Map> mixins.
+ // Map is the element type.
+
+ set length(int value) {
+ throw new UnsupportedError("Cannot resize immutable List.");
+ }
+
+ Map get first {
+ if (this.length > 0) {
+ return JS('Map', '#[0]', this);
+ }
+ throw new StateError("No elements");
+ }
+
+ Map get last {
+ int len = this.length;
+ if (len > 0) {
+ return JS('Map', '#[#]', this, len - 1);
+ }
+ throw new StateError("No elements");
+ }
+
+ Map get single {
+ int len = this.length;
+ if (len == 1) {
+ return JS('Map', '#[0]', this);
+ }
+ if (len == 0) throw new StateError("No elements");
+ throw new StateError("More than one element");
+ }
+
+ Map elementAt(int index) => this[index];
+ // -- end List<Map> mixins.
+
+ Map item(int index) {
+ return convertNativeToDart_Dictionary(_item_1(index));
+ }
+
+ @JSName('item')
+ _item_1(index) native;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+// http://www.w3.org/TR/webdatabase/#sqltransaction
+@deprecated // deprecated
+@Native("SQLTransaction")
+class SqlTransaction extends Interceptor {
+ // To suppress missing implicit constructor warnings.
+ factory SqlTransaction._() {
+ throw new UnsupportedError("Not supported");
+ }
+
+ @JSName('executeSql')
+ void _executeSql(String sqlStatement,
+ [List arguments,
+ SqlStatementCallback callback,
+ SqlStatementErrorCallback errorCallback]) native;
+
+ @JSName('executeSql')
+ Future<SqlResultSet> executeSql(String sqlStatement, [List arguments]) {
+ var completer = new Completer<SqlResultSet>();
+ _executeSql(sqlStatement, arguments, (transaction, resultSet) {
+ applyExtension('SQLResultSet', resultSet);
+ applyExtension('SQLResultSetRowList', resultSet.rows);
+ completer.complete(resultSet);
+ }, (transaction, error) {
+ completer.completeError(error);
+ });
+ return completer.future;
+ }
+}
diff --git a/tests/compiler/dart2js_extra/38005_test.dart b/tests/compiler/dart2js_extra/38005_test.dart
new file mode 100644
index 0000000..2789b31
--- /dev/null
+++ b/tests/compiler/dart2js_extra/38005_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {}
+
+int foo<T>() {
+ switch (T) {
+ case A:
+ return 42;
+ default:
+ return -1;
+ }
+}
+
+void main() {
+ Expect.equals(42, foo<A>());
+ Expect.equals(-1, foo<int>());
+}
diff --git a/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart b/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
index 402ff2d..e1baee5 100644
--- a/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
+++ b/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
@@ -68,13 +68,13 @@
c1a.m1;
c1a.m1 = 0;
- // ^^^^^^
- // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_SETTER
+ // ^^
+ // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_LOCAL
// [cfe] unspecified
c1a.m2;
// ^^
- // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] unspecified
c1a.m2 = 0;
@@ -87,7 +87,7 @@
// [cfe] unspecified
c1b.m1 = 0;
- // ^^^^^^
+ // ^^
// [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
// [cfe] unspecified
@@ -97,7 +97,7 @@
// [cfe] unspecified
c1b.m2 = 0;
- // ^^^^^^
+ // ^^
// [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
// [cfe] unspecified
}
@@ -119,14 +119,14 @@
this.m1;
this.m1 = 0;
- // ^^^^^^
- // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_SETTER
+ // ^^
+ // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
// [cfe] unspecified
this.m2 = 0;
this.m2;
// ^^
- // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] unspecified
// Check that `this.mc` refers to `C2.mc`.
diff --git a/tests/language_2/language_2_analyzer.status b/tests/language_2/language_2_analyzer.status
index bb945c5..cddcbd3 100644
--- a/tests/language_2/language_2_analyzer.status
+++ b/tests/language_2/language_2_analyzer.status
@@ -7,7 +7,6 @@
[ $compiler == dart2analyzer ]
generic_no_such_method_dispatcher_simple_test: Skip # failing-by-design: This test is just for kernel
large_class_declaration_test: Slow
-regress_23408_test: Skip # don't care about the static warning.
vm/debug_break_enabled_vm_test: Skip
vm/debug_break_vm_test/*: Skip
vm/regress_27201_test: SkipByDesign # Loads bad library, so will always crash.
diff --git a/tests/language_2/map_literal3_test.dart b/tests/language_2/map_literal3_test.dart
index 36827f6..a5d054c 100644
--- a/tests/language_2/map_literal3_test.dart
+++ b/tests/language_2/map_literal3_test.dart
@@ -40,35 +40,20 @@
"b": b,
}["b"]);
- // Make map grow. We currently don't have a way to construct
- // strings from an integer value, so we can't use a loop here.
var m = new Map();
Expect.equals(m.length, 0);
- m["1"] = 1;
- m["2"] = 2;
- m["3"] = 3;
- m["4"] = 4;
- m["5"] = 5;
- m["6"] = 6;
- m["7"] = 7;
- m["8"] = 8;
- m["9"] = 9;
- m["10"] = 10;
- m["11"] = 11;
- m["12"] = 12;
- m["13"] = 13;
- m["14"] = 14;
- m["15"] = 15;
- m["16"] = 16;
+ for (var i = 1; i <= 16; i++) {
+ m[i.toString()] = i;
+ }
Expect.equals(16, m.length);
- m.remove("1");
- m.remove("1"); // Remove element twice.
- m.remove("16");
+ Expect.equals(1, m.remove("1"));
+ Expect.isNull(m.remove("1")); // Remove element twice.
+ Expect.equals(16, m.remove("16"));
Expect.equals(14, m.length);
final cmap = const <String, num>{"a": 10, "b": 100, "a": 1000}; //# 01: compile-time error
final cmap2 = const <String, num>{"a": 10, "a": 100, "a": 1000}; //# 02: compile-time error
- var mmap = <String, num>{"a": 10, "b": 100, "a": 1000}; //# 03: compile-time error
+ var mmap = <String, num>{"a": 10, "b": 100, "a": 1000}; //# 03: ok
var mmap = <String, num>{"a": ctr(), "b": ctr(), "a": ctr()}; //# 04: compile-time error
Expect.equals(10, {"beta": 100, "alpha": 9 + 1}["alpha"]);
diff --git a/tests/language_2/vm/osr_nonempty_stack_test.dart b/tests/language_2/vm/osr_nonempty_stack_test.dart
index 9797e6e..a31df50 100644
--- a/tests/language_2/vm/osr_nonempty_stack_test.dart
+++ b/tests/language_2/vm/osr_nonempty_stack_test.dart
@@ -93,6 +93,12 @@
return x;
}
+List<int> globalList = [
+ 1,
+ for (int loc1 = 2; loc1 <= 100000; loc1++) loc1,
+ 100001
+];
+
main() {
int n = 20000;
int g = 457;
@@ -134,4 +140,10 @@
Expect.equals(e[i], expect);
if (++k == (n + 2)) k = 0;
}
+
+ Expect.isTrue(globalList != null);
+ Expect.equals(100001, globalList.length);
+ for (int i = 0; i < globalList.length; i++) {
+ Expect.equals(globalList[i], i + 1);
+ }
}
diff --git a/tests/lib_2/async/future_test.dart b/tests/lib_2/async/future_test.dart
index 515adca..9223646 100644
--- a/tests/lib_2/async/future_test.dart
+++ b/tests/lib_2/async/future_test.dart
@@ -1248,7 +1248,7 @@
UglyFuture(int badness)
: _result = (badness == 0) ? 42 : new UglyFuture(badness - 1);
Future<S> then<S>(action(value), {Function onError}) {
- var c = new Completer();
+ var c = new Completer<S>();
c.complete(new Future.microtask(() => action(_result)));
return c.future;
}
diff --git a/tests/lib_2/lib_2_kernel.status b/tests/lib_2/lib_2_kernel.status
index 23463b5..2aeba0c 100644
--- a/tests/lib_2/lib_2_kernel.status
+++ b/tests/lib_2/lib_2_kernel.status
@@ -68,9 +68,9 @@
[ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
isolate/message4_test: Crash # Timeout and sporadic crash (issue 33824)
-mirrors/dynamic_load_test: Crash
-mirrors/library_uri_io_test: Skip # Timeout
-mirrors/library_uri_package_test: Skip # Timeout
+mirrors/dynamic_load_test: Skip # Reload has an effect similar to deleting the dynamically loaded library
+mirrors/immutable_collections_test: Pass, Slow
+mirrors/mirrors_reader_test: Pass, Slow
[ $compiler == app_jitk || $compiler == dartk || $compiler == dartkb || $compiler == dartkp ]
html/*: SkipByDesign
diff --git a/tests/standalone_2/io/server_socket_exception_test.dart b/tests/standalone_2/io/server_socket_exception_test.dart
index f6c0993..16d1c34 100644
--- a/tests/standalone_2/io/server_socket_exception_test.dart
+++ b/tests/standalone_2/io/server_socket_exception_test.dart
@@ -28,10 +28,9 @@
Expect.equals(true, !wrongExceptionCaught);
// Test invalid host.
- ServerSocket
- .bind("__INVALID_HOST__", 0)
- .then((server) {})
- .catchError((e) => e is SocketException);
+ ServerSocket.bind("__INVALID_HOST__", 0).then((server) {
+ Expect.fail('Connection succeeded.');
+ }).catchError((e) => Expect.isTrue(e is SocketException));
});
}
diff --git a/tools/VERSION b/tools/VERSION
index e822ddc..da78ef9 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -33,7 +33,7 @@
MAJOR 2
MINOR 6
PATCH 0
-PRERELEASE 0
+PRERELEASE 1
PRERELEASE_PATCH 0
ABI_VERSION 14
OLDEST_SUPPORTED_ABI_VERSION 13
diff --git a/tools/approve_results.dart b/tools/approve_results.dart
index ebf1dd1..dc39a52 100755
--- a/tools/approve_results.dart
+++ b/tools/approve_results.dart
@@ -99,7 +99,9 @@
bool get isApproved => result == null || result == approvedResult;
List<String> get flakyModes =>
flakinessData != null ? flakinessData["outcomes"].cast<String>() : null;
- bool get isFlake => flakinessData != null && flakyModes.contains(result);
+ bool get isFlake =>
+ resultData != null && resultData["flaky"] ||
+ flakinessData != null && flakyModes.contains(result);
}
/// Loads the results file as as a map if the file exists, otherwise returns the