0">
8 |
9 | {{ngForm.dirty}}
10 |
11 |
12 |
13 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ngast/test/cli_tester.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 | import 'dart:io';
3 |
4 | import 'package:ngast/ngast.dart';
5 |
6 | RecoveringExceptionHandler exceptionHandler = RecoveringExceptionHandler();
7 | Iterable
tokenize(String html) {
8 | exceptionHandler.exceptions.clear();
9 | return const NgLexer().tokenize(html, exceptionHandler);
10 | }
11 |
12 | String untokenize(Iterable tokens) => tokens
13 | .fold(StringBuffer(), (buffer, token) => buffer..write(token.lexeme))
14 | .toString();
15 |
16 | void main() {
17 | String input;
18 | while (true) {
19 | input = stdin.readLineSync(encoding: utf8)!;
20 | if (input == 'QUIT') {
21 | break;
22 | }
23 | try {
24 | var tokens = tokenize(input);
25 | var fixed = untokenize(tokens);
26 | if (exceptionHandler.exceptions.isEmpty) {
27 | print('CORRECT(UNCHANGED): $input');
28 | } else {
29 | print('ORGNL: $input');
30 | print('FIXED: $fixed');
31 | print('ERRORS:');
32 | for (var e in exceptionHandler.exceptions) {
33 | var context = input.substring(e.offset!, e.offset! + e.length!);
34 | print('${e.errorCode.message} :: $context at ${e.offset}');
35 | }
36 | }
37 | } catch (e) {
38 | print(e);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ngast/test/e2e/e2e_template_tests.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:ngast/ngast.dart';
4 | import 'package:path/path.dart' as p;
5 | import 'package:test/test.dart';
6 |
7 | void main() {
8 | var parse = const NgParser().parse;
9 | var templatesDir = p.join('test', 'e2e', 'templates');
10 |
11 | // Just assert that we can parse all of these templates without failing.
12 | Directory(templatesDir).listSync().forEach((file) {
13 | if (file is File) {
14 | test('should parse ${p.basenameWithoutExtension(file.path)}', () {
15 | parse(file.readAsStringSync(), sourceUrl: file.absolute.path);
16 | });
17 | }
18 | });
19 | }
20 |
--------------------------------------------------------------------------------
/ngast/test/e2e/templates/fixed_material_tab_strip.html:
--------------------------------------------------------------------------------
1 |
6 |
21 |
--------------------------------------------------------------------------------
/ngast/test/e2e/templates/material_button.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 |
--------------------------------------------------------------------------------
/ngast/test/e2e/templates/material_checkbox.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 |
18 |
19 |
20 |
21 | {{label}}
22 |
23 |
24 |
--------------------------------------------------------------------------------
/ngast/test/e2e/templates/material_chip.html:
--------------------------------------------------------------------------------
1 |
6 |
7 | {{label}}
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ngast/test/e2e/templates/material_chips.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ngast/test/e2e/templates/material_dialog.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
11 |
12 |
{{error}}
13 |
14 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ngast/test/e2e/templates/material_popup.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
33 |
34 |
--------------------------------------------------------------------------------
/ngast/test/e2e/templates/material_progress.html:
--------------------------------------------------------------------------------
1 |
6 |
18 |
--------------------------------------------------------------------------------
/ngast/test/e2e/templates/material_toggle.html:
--------------------------------------------------------------------------------
1 |
6 |
29 |
--------------------------------------------------------------------------------
/ngast/test/e2e/templates/scoreboard.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/ngast/test/e2e/templates/scorecard.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/ngast/test/visitor_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:ngast/ngast.dart';
2 | import 'package:test/test.dart';
3 |
4 | void main() {
5 | // DesugarVisitor is tested by parser_test.dart
6 | var visitor = const HumanizingTemplateAstVisitor();
7 |
8 | test('should humanize a simple template and preserve inner spaces', () {
9 | var templateString = '';
10 | var template = parse(
11 | templateString,
12 | sourceUrl: '/test/visitor_test.dart#inline',
13 | );
14 | expect(
15 | template.map((t) => t.accept(visitor)).join(''),
16 | equals(templateString),
17 | );
18 | });
19 |
20 | test('should humanize a simple template *with* de-sugaring applied', () {
21 | var template = parse(
22 | '',
23 | sourceUrl: '/test/visitor_test.dart#inline',
24 | desugar: true,
25 | );
26 | expect(
27 | template.map((t) => t.accept(visitor)).join(''),
28 | equalsIgnoringWhitespace(r'''
29 |
30 | '''),
31 | );
32 | });
33 | }
34 |
--------------------------------------------------------------------------------
/ngcompiler/.pubignore:
--------------------------------------------------------------------------------
1 | pubspec_overrides.yaml
2 |
--------------------------------------------------------------------------------
/ngcompiler/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2017, the Dart project authors. All rights reserved.
2 | Redistribution and use in source and binary forms, with or without
3 | modification, are permitted provided that the following conditions are
4 | met:
5 |
6 | * Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | * Redistributions in binary form must reproduce the above
9 | copyright notice, this list of conditions and the following
10 | disclaimer in the documentation and/or other materials provided
11 | with the distribution.
12 | * Neither the name of Google Inc. nor the names of its
13 | contributors may be used to endorse or promote products derived
14 | from this software without specific prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 |
--------------------------------------------------------------------------------
/ngcompiler/README.md:
--------------------------------------------------------------------------------
1 | [](https://pub.dev/packages/ngcompiler)
2 | [](https://github.com/angulardart-community/angular/actions/workflows/dart.yml)
3 | [](https://gitter.im/angulardart/community)
4 |
5 | Tooling for compiling [AngularDart](https://pub.dev/packages/ngdart).
6 |
--------------------------------------------------------------------------------
/ngcompiler/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: ../analysis_options.yaml
2 |
3 | analyzer:
4 | errors:
5 | implementation_imports: ignore
6 |
--------------------------------------------------------------------------------
/ngcompiler/dart_test.yaml:
--------------------------------------------------------------------------------
1 | # Include common configuration.
2 | include: ../tool/dart_test_repo.yaml
3 |
4 | # This repository has only VM tests.
5 | platforms:
6 | - vm
7 |
--------------------------------------------------------------------------------
/ngcompiler/example/README.md:
--------------------------------------------------------------------------------
1 | Not intended for public use. Please see the
2 | [`ngdart`](https://pub.dev/packages/ngdart) package for more info on
3 | AngularDart.
4 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/cli.dart:
--------------------------------------------------------------------------------
1 | /// Supports the compiler running in a command-line interface (CLI).
2 | ///
3 | /// Utilities and classes here are not directly related to the compilation
4 | /// pipeline, but instead are used to manage the process, logging, exception
5 | /// handling, and other related functionality.
6 | ///
7 | /// **NOTE**: This is not an externally stable API. Use at your own risk.
8 | @experimental
9 | library;
10 |
11 | import 'package:meta/meta.dart';
12 |
13 | export 'src/angular_compiler/cli/builder.dart';
14 | export 'src/angular_compiler/cli/flags.dart';
15 | export 'src/angular_compiler/cli/logging.dart';
16 | export 'src/angular_compiler/cli/messages.dart'
17 | show messages, SourceSpanMessageTuple;
18 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/angular_compiler/analyzer.dart:
--------------------------------------------------------------------------------
1 | export 'analyzer/common.dart';
2 | export 'analyzer/di/dependencies.dart';
3 | export 'analyzer/di/global_singleton_services.dart';
4 | export 'analyzer/di/injector.dart';
5 | export 'analyzer/di/modules.dart';
6 | export 'analyzer/di/providers.dart';
7 | export 'analyzer/di/tokens.dart';
8 | export 'analyzer/link.dart';
9 | export 'analyzer/types.dart';
10 | export 'analyzer/view/directive.dart';
11 | export 'analyzer/view/typed_reader.dart';
12 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/angular_compiler/analyzer/di/global_singleton_services.dart:
--------------------------------------------------------------------------------
1 | import '../link.dart';
2 |
3 | const _globalSingletonServices = [
4 | TypeLink(
5 | 'ApplicationRef',
6 | 'asset:ngdart/lib/src/core/application_ref.dart',
7 | ),
8 | TypeLink(
9 | 'AppViewUtils',
10 | 'asset:ngdart/lib/src/core/linker/app_view_utils.dart',
11 | ),
12 | TypeLink(
13 | 'NgZone',
14 | 'asset:ngdart/lib/src/core/zone/ng_zone.dart',
15 | ),
16 | TypeLink(
17 | 'Testability',
18 | 'asset:ngdart/lib/src/testability/implementation.dart',
19 | ),
20 | ];
21 |
22 | bool isGlobalSingletonService(TypeLink service) =>
23 | _globalSingletonServices.contains(service);
24 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/angular_compiler/cli/messages/messages.dart:
--------------------------------------------------------------------------------
1 | import '../messages.dart';
2 |
3 | /// URL of the AngularDart GitHub repository.
4 | const _github = 'https://github.com/angulardart-community/angular';
5 |
6 | /// Concrete implementation of [Messages] for external users.
7 | class $Messages extends Messages {
8 | const $Messages() : super.base();
9 |
10 | @override
11 | String get analysisFailureReasons =>
12 | 'Try the following when diagnosing the problem:\n'
13 | ' * Check your IDE or with the dartanalyzer for errors or warnings\n'
14 | ' * Check your "import" statements for missing or incorrect URLs\n'
15 | '\n'
16 | 'If you are still stuck, file an issue and include this error message:\n'
17 | '$urlFileBugs';
18 |
19 | @override
20 | final urlFileBugs = '$_github/issues/new';
21 |
22 | @override
23 | String removeGlobalSingletonService(String service) =>
24 | '"$service" is an app-wide, singleton service provided by the '
25 | 'framework that cannot be overridden or manually provided.\n'
26 | '\n'
27 | 'If you are providing this service to fix a missing provider error, you '
28 | "likely have created an injector that is disconnected from the app's "
29 | 'injector hierarchy. This can occur when instantiating an injector and '
30 | 'you omit the parent injector argument, or explicitly configure an empty '
31 | 'parent injector. Please check your injector constructors to make sure '
32 | "the current context's injector is passed as the parent.";
33 | }
34 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/angular_compiler/emitter/split_dart_emitter.dart:
--------------------------------------------------------------------------------
1 | import 'package:code_builder/code_builder.dart';
2 |
3 | // Unlike the default [DartEmitter], this has two output buffers, which is used
4 | // transitionally since other parts of the AngularDart compiler write code based
5 | // on the existing "Output AST" format (string-based).
6 | //
7 | // Once/if all code is using code_builder, this can be safely removed.
8 | class SplitDartEmitter extends DartEmitter {
9 | final StringSink? _writeImports;
10 |
11 | SplitDartEmitter(
12 | this._writeImports, {
13 | super.allocator,
14 | }) : super(orderDirectives: false, useNullSafetySyntax: true);
15 |
16 | @override
17 | StringSink visitDirective(Directive spec, [StringSink? output]) {
18 | // Always write import/export directives to a separate buffer.
19 | return super.visitDirective(spec, _writeImports);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/aria_attributes.dart:
--------------------------------------------------------------------------------
1 | // https://www.w3.org/TR/wai-aria-1.1/#state_prop_def
2 | const _ariaAttributes = {
3 | 'aria-activedescendant',
4 | 'aria-atomic',
5 | 'aria-autocomplete',
6 | 'aria-busy',
7 | 'aria-checked',
8 | 'aria-colcount',
9 | 'aria-colindex',
10 | 'aria-colspan',
11 | 'aria-controls',
12 | 'aria-current',
13 | 'aria-describedat',
14 | 'aria-describedby',
15 | 'aria-disabled',
16 | 'aria-dropeffect',
17 | 'aria-errormessage',
18 | 'aria-expanded',
19 | 'aria-flowto',
20 | 'aria-grabbed',
21 | 'aria-haspopup',
22 | 'aria-hidden',
23 | 'aria-invalid',
24 | 'aria-keyshortcuts',
25 | 'aria-label',
26 | 'aria-labelledby',
27 | 'aria-level',
28 | 'aria-live',
29 | 'aria-modal',
30 | 'aria-multiline',
31 | 'aria-multiselectable',
32 | 'aria-orientation',
33 | 'aria-owns',
34 | 'aria-placeholder',
35 | 'aria-posinset',
36 | 'aria-pressed',
37 | 'aria-readonly',
38 | 'aria-relevant',
39 | 'aria-required',
40 | 'aria-roledescription',
41 | 'aria-rowcount',
42 | 'aria-rowindex',
43 | 'aria-rowspan',
44 | 'aria-selected',
45 | 'aria-setsize',
46 | 'aria-sort',
47 | 'aria-valuemax',
48 | 'aria-valuemin',
49 | 'aria-valuenow',
50 | 'aria-valuetext'
51 | };
52 |
53 | /// Returns true if input is a valid ARIA attribute.
54 | bool isAriaAttribute(String attribute) => _ariaAttributes.contains(attribute);
55 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/chars.dart:
--------------------------------------------------------------------------------
1 | const ngSpace = '\uE500';
2 |
3 | String replaceNgSpace(String value) {
4 | return value.replaceAll(ngSpace, ' ');
5 | }
6 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/compiler_utils.dart:
--------------------------------------------------------------------------------
1 | import 'compile_metadata.dart';
2 |
3 | const moduleSuffix = '.dart';
4 |
5 | String templateModuleUrl(CompileTypeMetadata type) {
6 | var moduleUrl = type.moduleUrl!;
7 | var urlWithoutSuffix =
8 | moduleUrl.substring(0, moduleUrl.length - moduleSuffix.length);
9 | return '$urlWithoutSuffix.template$moduleSuffix';
10 | }
11 |
12 | String stylesModuleUrl(String stylesheetUrl, bool shim) {
13 | return shim
14 | ? '$stylesheetUrl.shim$moduleSuffix'
15 | : '$stylesheetUrl$moduleSuffix';
16 | }
17 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/html_tags.dart:
--------------------------------------------------------------------------------
1 | HtmlTagDefinition getHtmlTagDefinition(String tagName) {
2 | var result = _tagDefinitions[tagName.toLowerCase()];
3 | return result ?? const HtmlTagDefinition();
4 | }
5 |
6 | class HtmlTagDefinition {
7 | final String? implicitNamespacePrefix;
8 | final bool isVoid;
9 |
10 | const HtmlTagDefinition({this.implicitNamespacePrefix, this.isVoid = false});
11 | }
12 | // see http://www.w3.org/TR/html51/syntax.html#optional-tags
13 |
14 | // This implementation does not fully conform to the HTML5 spec.
15 | const _tagDefinitions = {
16 | 'base': HtmlTagDefinition(isVoid: true),
17 | 'meta': HtmlTagDefinition(isVoid: true),
18 | 'area': HtmlTagDefinition(isVoid: true),
19 | 'embed': HtmlTagDefinition(isVoid: true),
20 | 'link': HtmlTagDefinition(isVoid: true),
21 | 'img': HtmlTagDefinition(isVoid: true),
22 | 'input': HtmlTagDefinition(isVoid: true),
23 | 'param': HtmlTagDefinition(isVoid: true),
24 | 'hr': HtmlTagDefinition(isVoid: true),
25 | 'br': HtmlTagDefinition(isVoid: true),
26 | 'source': HtmlTagDefinition(isVoid: true),
27 | 'track': HtmlTagDefinition(isVoid: true),
28 | 'wbr': HtmlTagDefinition(isVoid: true),
29 | 'col': HtmlTagDefinition(isVoid: true),
30 | 'svg': HtmlTagDefinition(implicitNamespacePrefix: 'svg'),
31 | 'math': HtmlTagDefinition(implicitNamespacePrefix: 'math'),
32 | };
33 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/i18n/message.dart:
--------------------------------------------------------------------------------
1 | import 'package:collection/collection.dart';
2 |
3 | import 'metadata.dart';
4 |
5 | const _map = MapEquality();
6 |
7 | /// An internationalized message.
8 | class I18nMessage {
9 | /// Arguments that appear as interpolations in [text].
10 | ///
11 | /// These are currently only used to support HTML nested within this message.
12 | final Map args;
13 |
14 | /// Metadata used for internationalization of this message.
15 | final I18nMetadata metadata;
16 |
17 | /// The message text to be translated for different locales.
18 | final String text;
19 |
20 | /// Creates an internationalized message from [text] with [metadata].
21 | ///
22 | /// Any arguments that appear as interpolations in [text] should be mapped
23 | /// to their value in [args].
24 | I18nMessage(
25 | this.text,
26 | this.metadata, {
27 | this.args = const {},
28 | });
29 |
30 | /// Whether this message contains nested HTML.
31 | bool get containsHtml => args.isNotEmpty;
32 |
33 | @override
34 | int get hashCode => metadata.hashCode ^ text.hashCode ^ _map.hash(args);
35 |
36 | @override
37 | bool operator ==(Object other) =>
38 | other is I18nMessage &&
39 | other.metadata == metadata &&
40 | other.text == text &&
41 | _map.equals(other.args, args);
42 | }
43 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/js_split_facade.dart:
--------------------------------------------------------------------------------
1 | /// A [String.split] implementation that is like JS' implementation.
2 | ///
3 | /// See https://dartpad.dartlang.org/37a53b0d5d4cced6c7312b2b965ed7fd.
4 | List jsSplit(String s, RegExp regExp) {
5 | var parts = [];
6 | var lastEnd = 0;
7 | for (var match in regExp.allMatches(s)) {
8 | parts.add(s.substring(lastEnd, match.start));
9 | lastEnd = match.end;
10 | for (var i = 0, len = match.groupCount; i < len; i++) {
11 | parts.add(match.group(i + 1)!);
12 | }
13 | }
14 | parts.add(s.substring(lastEnd));
15 | return parts;
16 | }
17 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/optimize_ir/merge_events.dart:
--------------------------------------------------------------------------------
1 | import 'package:ngcompiler/v1/src/compiler/ir/model.dart' as ir;
2 |
3 | /// Combines multiple [ir.EventHandlers] together as an optimization.
4 | ///
5 | /// In the case that multiple bindings on a directive or element target the same
6 | /// event name, we can merge these handlers into a single method.
7 | List mergeEvents(List events) {
8 | final visitedEvents = {};
9 | for (var event in events) {
10 | var eventName = (event.target as ir.BoundEvent).name;
11 | var handler = visitedEvents[eventName];
12 | if (handler == null) {
13 | visitedEvents[eventName] = event;
14 | continue;
15 | }
16 | visitedEvents[eventName] = _merge(handler, event);
17 | }
18 | return visitedEvents.values.toList();
19 | }
20 |
21 | ir.Binding _merge(ir.Binding handler, ir.Binding event) => ir.Binding(
22 | target: handler.target,
23 | source: (handler.source as ir.EventHandler)
24 | .merge(event.source as ir.EventHandler));
25 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/optimize_ir/optimize_lifecycles.dart:
--------------------------------------------------------------------------------
1 | import 'package:ngcompiler/v1/src/compiler/ir/model.dart' as ir;
2 |
3 | /// Optimizes lifecycle hooks in the directive.
4 | ///
5 | /// If there are no inputs declared, then nothing can every change for the
6 | /// matched directive. Thus, we do not need to call the `ngAfterChanges`
7 | /// lifecycle hook.
8 | ir.MatchedDirective optimizeLifecycles(ir.MatchedDirective directive) {
9 | if (directive.inputs.isNotEmpty ||
10 | !directive.hasLifecycle(ir.Lifecycle.afterChanges)) {
11 | return directive;
12 | }
13 |
14 | return ir.MatchedDirective(
15 | lifecycles: directive.lifecycles
16 | .where((lifecycle) => lifecycle != ir.Lifecycle.afterChanges)
17 | .toSet(),
18 | providerSource: directive.providerSource,
19 | inputs: directive.inputs,
20 | outputs: directive.outputs,
21 | hasInputs: directive.hasInputs,
22 | hasHostProperties: directive.hasHostProperties,
23 | isComponent: directive.isComponent,
24 | isOnPush: directive.isOnPush,
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/parse_util.dart:
--------------------------------------------------------------------------------
1 | import 'package:ngast/ngast.dart';
2 | import 'package:ngcompiler/v2/context.dart';
3 | import 'package:source_span/source_span.dart';
4 |
5 | /// Collects parsing exceptions from `ngast`, converting to [BuildError].
6 | ///
7 | /// See [throwErrorsIfAny].
8 | class AstExceptionHandler extends RecoveringExceptionHandler {
9 | /// Contents of the source file.
10 | final String _contents;
11 |
12 | /// URL to the source file.
13 | final String _sourceUrl;
14 |
15 | /// Directive that is being compiled.
16 | final String _directiveName;
17 |
18 | AstExceptionHandler(
19 | this._contents,
20 | this._sourceUrl,
21 | this._directiveName,
22 | );
23 |
24 | /// Converts and throws [exceptions] as a [BuildError].
25 | ///
26 | /// If no [exceptions] were collected during parsing no error is thrown.
27 | void throwErrorsIfAny() {
28 | if (exceptions.isEmpty) {
29 | return;
30 | }
31 | final sourceFile = SourceFile.fromString(_contents, url: _sourceUrl);
32 | throw BuildError.fromMultiple(
33 | exceptions.map(
34 | (e) => BuildError.forSourceSpan(
35 | sourceFile.span(e.offset!, e.offset! + e.length!),
36 | e.errorCode.message,
37 | ),
38 | ),
39 | 'Errors in $_sourceUrl while compiling component $_directiveName',
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/schema/element_schema_registry.dart:
--------------------------------------------------------------------------------
1 | import 'package:ngcompiler/v1/src/compiler/security.dart';
2 |
3 | abstract class ElementSchemaRegistry {
4 | bool hasProperty(String tagName, String propName);
5 | bool hasAttribute(String tagName, String attributeName);
6 | bool hasEvent(String tagName, String eventName);
7 | String getMappedPropName(String propName);
8 | TemplateSecurityContext securityContext(String tagName, String propName);
9 | }
10 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/security.dart:
--------------------------------------------------------------------------------
1 | /// A [TemplateSecurityContext] specifies a category of security vulnerabilities
2 | /// if the content is not sanitized.
3 | ///
4 | /// Examples: A DOM property that is used as a url is classified as having
5 | /// the Url [HtmlSecurityContext].
6 | ///
7 | /// [innerHTML] that could cause Cross Site Scripting (XSS) security bugs when
8 | /// improperly handled is classified as HTML.
9 | enum TemplateSecurityContext {
10 | /// No security implication.
11 | none,
12 |
13 | /// Context for free form html content.
14 | html,
15 |
16 | /// Context for element style.
17 | style,
18 |
19 | /// Link such as a,href.
20 | url,
21 |
22 | /// Url pointing to a resource to be loaded.
23 | resourceUrl,
24 | }
25 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/source_module.dart:
--------------------------------------------------------------------------------
1 | /// [outputUrl] and the generated [sourceCode] related to view compilation.
2 | class DartSourceOutput {
3 | final String outputUrl;
4 | final String sourceCode;
5 |
6 | DartSourceOutput({
7 | required this.outputUrl,
8 | required this.sourceCode,
9 | });
10 | }
11 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/style_url_resolver.dart:
--------------------------------------------------------------------------------
1 | class StyleWithImports {
2 | final String style;
3 | final List styleUrls;
4 | StyleWithImports(this.style, this.styleUrls);
5 | }
6 |
7 | /// Whether [url] resides within the current package or a dependency.
8 | bool isStyleUrlResolvable(String? url) {
9 | if (url == null || url.isEmpty || url[0] == '/') return false;
10 | var schemeMatch = _urlWithSchemaRe.firstMatch(url);
11 | return schemeMatch == null ||
12 | schemeMatch[1] == 'package' ||
13 | schemeMatch[1] == 'asset';
14 | }
15 |
16 | /// Rewrites style sheets by resolving and removing the @import urls that
17 | /// are either relative or don't have a `package:` scheme
18 | StyleWithImports extractStyleUrls(String baseUrl, String cssText) {
19 | Uri? baseUri;
20 | var foundUrls = [];
21 | var modifiedCssText = cssText.replaceAllMapped(_cssImportRe, (m) {
22 | var url = m[1] ?? m[2];
23 | if (!isStyleUrlResolvable(url)) {
24 | // Do not attempt to resolve non-package absolute URLs with URI scheme
25 | return m[0]!;
26 | }
27 | baseUri ??= Uri.parse(baseUrl);
28 | foundUrls.add(baseUri!.resolve(url!).toString());
29 | return '';
30 | });
31 | return StyleWithImports(modifiedCssText, foundUrls);
32 | }
33 |
34 | final _cssImportRe = RegExp(r'@import\s+(?:url\()?\s*(?:(?:['
35 | "'"
36 | r'"]([^'
37 | "'"
38 | r'"]*))|([^;\)\s]*))[^;]*;?');
39 | final _urlWithSchemaRe = RegExp('^([^:/?#]+):');
40 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/stylesheet_compiler/builder.dart:
--------------------------------------------------------------------------------
1 | import 'package:build/build.dart';
2 | import 'package:ngcompiler/v1/cli.dart';
3 |
4 | import 'processor.dart';
5 |
6 | const _cssExtension = '.css';
7 | const _shimmedStylesheetExtension = '.css.shim.dart';
8 | const _nonShimmedStylesheetExtension = '.css.dart';
9 |
10 | /// Pre-compiles CSS stylesheet files to Dart code for Angular 2.
11 | class StylesheetCompiler implements Builder {
12 | final CompilerFlags _flags;
13 |
14 | const StylesheetCompiler(this._flags);
15 |
16 | @override
17 | final buildExtensions = const {
18 | _cssExtension: [
19 | _shimmedStylesheetExtension,
20 | _nonShimmedStylesheetExtension,
21 | ],
22 | };
23 |
24 | @override
25 | Future build(BuildStep buildStep) async {
26 | final outputs = await processStylesheet(
27 | buildStep,
28 | buildStep.inputId,
29 | _flags,
30 | );
31 | outputs.forEach(buildStep.writeAsString);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/ngcompiler/lib/v1/src/compiler/stylesheet_compiler/processor.dart:
--------------------------------------------------------------------------------
1 | import 'package:build/build.dart';
2 | import 'package:ngcompiler/v1/cli.dart';
3 | import 'package:ngcompiler/v1/src/compiler/module/ng_compiler_module.dart';
4 | import 'package:ngcompiler/v1/src/compiler/source_module.dart';
5 | import 'package:ngcompiler/v1/src/source_gen/common/url_resolver.dart';
6 |
7 | Future