diff --git a/examples/data_rules/.dart_tool/package_config.json b/examples/data_rules/.dart_tool/package_config.json index 2aa7b2ca..53f0edf2 100644 --- a/examples/data_rules/.dart_tool/package_config.json +++ b/examples/data_rules/.dart_tool/package_config.json @@ -386,7 +386,7 @@ "languageVersion": "2.17" } ], - "generated": "2023-01-13T14:36:21.478334Z", + "generated": "2023-01-14T21:01:26.976686Z", "generator": "pub", "generatorVersion": "2.17.6" -} +} \ No newline at end of file diff --git a/packages/sidecar/lib/sidecar.dart b/packages/sidecar/lib/sidecar.dart index f8a03686..fd2d5996 100644 --- a/packages/sidecar/lib/sidecar.dart +++ b/packages/sidecar/lib/sidecar.dart @@ -1,6 +1,6 @@ // Temporarily ignore ordering // ignore_for_file: directives_ordering - +// library sidecar; // is this needed any more? diff --git a/packages/sidecar_lints/example/analysis_options.yaml b/packages/sidecar_lints/example/analysis_options.yaml index 341d5688..bfc5d79a 100644 --- a/packages/sidecar_lints/example/analysis_options.yaml +++ b/packages/sidecar_lints/example/analysis_options.yaml @@ -2,4 +2,4 @@ include: package:lints/recommended.yaml analyzer: plugins: - - sidecar + # - sidecar diff --git a/website/sidecar/.dart_tool/package_config.json b/website/sidecar/.dart_tool/package_config.json index 34a0f61a..41be4a68 100644 --- a/website/sidecar/.dart_tool/package_config.json +++ b/website/sidecar/.dart_tool/package_config.json @@ -139,6 +139,12 @@ "packageUri": "lib/", "languageVersion": "2.17" }, + { + "name": "design_system_lints", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/design_system_lints-0.1.0-dev.11", + "packageUri": "lib/", + "languageVersion": "2.17" + }, { "name": "file", "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/file-6.1.4", @@ -321,7 +327,7 @@ }, { "name": "sidecar", - "rootUri": "../../../packages/sidecar", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/sidecar-0.1.0-dev.21", "packageUri": "lib/", "languageVersion": "2.17" }, @@ -331,12 +337,6 @@ "packageUri": "lib/", "languageVersion": "2.12" }, - { - "name": "sidecar_package_utilities", - "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/sidecar_package_utilities-0.1.0-dev.7", - "packageUri": "lib/", - "languageVersion": "2.12" - }, { "name": "source_gen", "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/source_gen-1.2.6", @@ -476,7 +476,7 @@ "languageVersion": "2.17" } ], - "generated": "2023-01-09T06:26:19.624577Z", + "generated": "2023-01-23T16:33:20.511367Z", "generator": "pub", "generatorVersion": "2.17.6" } diff --git a/website/sidecar/.packages b/website/sidecar/.packages index e744ede7..9c1791f9 100644 --- a/website/sidecar/.packages +++ b/website/sidecar/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2023-01-09 01:26:19.616588. +# Generated by pub on 2023-01-23 11:33:20.502685. _fe_analyzer_shared:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-47.0.0/lib/ analyzer:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/analyzer-4.7.0/lib/ analyzer_plugin:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/analyzer_plugin-0.11.1/lib/ @@ -27,6 +27,7 @@ convert:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/convert-3.1. coverage:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/coverage-1.6.1/lib/ crypto:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.2/lib/ dart_style:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/dart_style-2.2.4/lib/ +design_system_lints:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/design_system_lints-0.1.0-dev.11/lib/ file:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/file-6.1.4/lib/ fixnum:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/fixnum-1.0.1/lib/ freezed:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/freezed-2.2.0/lib/ @@ -57,9 +58,8 @@ shelf:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/shelf-1.4.0/li shelf_packages_handler:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/shelf_packages_handler-3.0.1/lib/ shelf_static:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/shelf_static-1.1.1/lib/ shelf_web_socket:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-1.0.3/lib/ -sidecar:../../packages/sidecar/lib/ +sidecar:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/sidecar-0.1.0-dev.21/lib/ sidecar_annotations:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/sidecar_annotations-0.1.0-dev.1/lib/ -sidecar_package_utilities:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/sidecar_package_utilities-0.1.0-dev.7/lib/ source_gen:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/source_gen-1.2.6/lib/ source_helper:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/source_helper-1.3.3/lib/ source_map_stack_trace:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-2.1.1/lib/ diff --git a/website/sidecar/.vscode/launch.json b/website/sidecar/.vscode/launch.json new file mode 100644 index 00000000..fa3ae764 --- /dev/null +++ b/website/sidecar/.vscode/launch.json @@ -0,0 +1,49 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "sidecar", + "request": "launch", + "type": "dart" + }, + { + "name": "snippets", + "cwd": "docs/usage/snippets", + "request": "launch", + "type": "dart" + }, + { + "name": "snippets (profile mode)", + "cwd": "docs/usage/snippets", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "snippets (release mode)", + "cwd": "docs/usage/snippets", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "bloc_feature_structure", + "program": "lib/src/tutorials/bloc_feature_structure/example/.dart_tool/sidecar/debug.dart", + "request": "launch", + "type": "dart", + "args": [ + "--enable-vm-service", + "--debug", + ] + }, + { + "name": "hello_world", + "cwd": "lib/src/tutorials/hello_world", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/website/sidecar/docs/concepts/_category_.json b/website/sidecar/docs/concepts/_category_.json new file mode 100644 index 00000000..135ca4e5 --- /dev/null +++ b/website/sidecar/docs/concepts/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Core Concepts", + "position": 3, + "link": { + "type": "generated-index" + } +} \ No newline at end of file diff --git a/website/sidecar/docs/concepts/integration_testing.mdx b/website/sidecar/docs/concepts/integration_testing.mdx new file mode 100644 index 00000000..cd60300e --- /dev/null +++ b/website/sidecar/docs/concepts/integration_testing.mdx @@ -0,0 +1,45 @@ +--- +title: Integration Testing +sidebar_position: 3 +description: "" +--- + +import CodeBlock from '@theme/CodeBlock'; +import testing from "!!raw-loader!./snippets/testing.dart"; +import { + trimSnippet, + generateSnippet, + CodeSnippet, +} from "../../src/components/CodeSnippet"; + +Sidecar ships with a series of test utilities that make it easy to write integration tests for Sidecar rules. + +When writing rule tests, we must create a string containing example code that we expect to trigger or not trigger a lint. + +The below snippet shows code that we would expect to show a lint for the `avoid_edge_insets_literal` rule from design_system_lints. The rule +is expected to find values used in an `EdgeInsets` constructor, and show a lint if that value is not annotated +with `@designSystem` (see [design_system_lints](https://pub.dev/packages/design_system_lints) for +a full explanation of these rules). + +{generateSnippet(testing, ['Content2'])} + +In this example, we would expect a lint to be reported underneath the `2.0` value. We can easily test for this, +by writing the following rule in the `test` directory of our rule package: + +{generateSnippet(testing, ['StartTest', 'TestEnd', 'RuleTest2' ])} + +Before we can run any rule test, we must first use the `setUpRules` function with the particular rule we're looking to test (here, `AvoidEdgeInsetsLiteral`). +We can then use the `ExpectedText` test utility to check if a lint is found over the particular code `2.0`. We also make +the test description `EdgeInsets.all`, as that's exactly the use case we're testing for. + +If we want to test that a lint is found when using a different instantiation of `EdgeInsets` (e.g. `EdgeInsets.only`), +we can create another test that checks each of the parameters given to `EdgeInsets.only` (i.e. `left`, `right`, `top`, `bottom`) +by writing 4 different `ExpectedText` values and providing them to our `ruleTest`: + +{generateSnippet(testing, ['Imports', 'StartTest', 'TestEnd', 'RuleTest3', 'Content3'])} + +Finally, if we write a test where we expect no lints (such as when our `EdgeInset` values are annotated with `@designSystem`), +we simply simply leave the `ExpectedText` array empty for our `ruleTest`: + +{generateSnippet(testing, ['Imports', 'StartTest', 'TestEnd', 'RuleTest1', 'Content1'])} + diff --git a/website/sidecar/docs/concepts/rule_creation_checklist.mdx b/website/sidecar/docs/concepts/rule_creation_checklist.mdx new file mode 100644 index 00000000..6522bf45 --- /dev/null +++ b/website/sidecar/docs/concepts/rule_creation_checklist.mdx @@ -0,0 +1,26 @@ +--- +title: Rule Creation Checklist +sidebar_position: 1 +description: "" +--- + +import CodeBlock from '@theme/CodeBlock'; +import { + trimSnippet, + CodeSnippet, +} from "../../src/components/CodeSnippet"; + +If you're creating a new lint rule and lints are not appearing in the IDE of an example project, + you can follow this checklist for requirements. + + +| Description | Examples | Lints Available | +|---------------------------------------------|---------|:----------------:| +| Rule has a unique RuleCode ID in snake_case | `LintCode('avoid_edge_insets_literal')` | ✅ | +| The Rule's ClassName is the PascalCase equivalent of the RuleCode ID | `class AvoidEdgeInsetsLiteral extends LintRule {...}` | ✅ | +| The `code.package` value matches the name given to the rule package | `LintCode(..., package: 'design_system_lints')` | ✅ | +| Lint Rule is exported from `lib/.dart` | | 🚧 | + + +It's recommended that you use the lints included in [`package:sidecar_lints`](https://pub.dev/packages/sidecar_lints) to enforce the above rules +on your Sidecar-based rule package. \ No newline at end of file diff --git a/website/sidecar/docs/concepts/snippets/testing.dart b/website/sidecar/docs/concepts/snippets/testing.dart new file mode 100644 index 00000000..57303732 --- /dev/null +++ b/website/sidecar/docs/concepts/snippets/testing.dart @@ -0,0 +1,66 @@ +/* SNIP Imports */ +import 'package:design_system_lints/design_system_lints.dart'; +import 'package:sidecar/test.dart'; +import 'package:test/test.dart'; + +/* SNIP Imports END */ +/* SNIP Content1 */ +const contentDesignSystem = ''' +import 'package:design_system_annotations/design_system_annotations.dart'; +import 'package:flutter/material.dart'; +@designSystem +class DesignSystemX { + static const value = 3.1; +} +final edgeInsets = EdgeInsets.all(DesignSystemX.value); +'''; +/* SNIP Content1 END */ +/* SNIP Content2 */ +const contentEdgeInsetsAll = ''' +import 'package:flutter/material.dart'; +class MyWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(2.0), + ); + } +} +'''; +/* SNIP Content2 END */ +/* SNIP Content3 */ +const contentEdgeInsetsOnly = ''' +import 'package:flutter/material.dart'; +class MyWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.only(left: 1.1, right: 1.2, top: 1.3, bottom: 1.4), + ); + } +} +'''; +/* SNIP Content3 END */ +/* SNIP StartTest */ +void main() { + group('avoid_edge_insets_literal:', () { + setUpRules([AvoidEdgeInsetsLiteral()]); +/* SNIP StartTest END */ +/* SNIP RuleTest1 */ + ruleTest('EdgeInsets using Design System', contentDesignSystem, []); +/* SNIP RuleTest1 END */ +/* SNIP RuleTest2 */ + ruleTest('EdgeInsets.all', contentEdgeInsetsAll, [ExpectedText('2.0')]); +/* SNIP RuleTest2 END */ +/* SNIP RuleTest3 */ + ruleTest('EdgeInsets.only', contentEdgeInsetsOnly, [ + ExpectedText('1.1'), + ExpectedText('1.2'), + ExpectedText('1.3'), + ExpectedText('1.4'), + ]); +/* SNIP RuleTest3 END */ + /* SNIP TestEnd */ + }); +} +/* SNIP TestEnd END */ diff --git a/website/sidecar/docs/concepts/snippets/type_checking.dart b/website/sidecar/docs/concepts/snippets/type_checking.dart new file mode 100644 index 00000000..43defce8 --- /dev/null +++ b/website/sidecar/docs/concepts/snippets/type_checking.dart @@ -0,0 +1,44 @@ +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:sidecar/sidecar.dart'; + +/* SNIP TypeChecker */ +// 1. Create the TypeChecker +const statelessWidget = + TypeChecker.fromPackage('StatelessWidget', package: 'flutter'); + +/* SNIP TypeChecker END */ +/* SNIP ClassStart */ +class MyLint extends LintRule { +/* SNIP ClassStart END */ + @override + LintCode get code => throw UnimplementedError(); + + @override + void initializeVisitor(NodeRegistry registry) { + // TODO: implement initializeVisitor + } + /* SNIP VisitMethod */ + @override + void visitInstanceCreationExpression(InstanceCreationExpression node) { + // 2. Use the TypeChecker to check the type of a particular AstNode + final returnType = node.constructorName.staticElement?.returnType; + if (statelessWidget.isAssignableFromType(returnType)) { + // do something + } + } + /* SNIP VisitMethod END */ + /* SNIP ClassEnd */ +} +/* SNIP ClassEnd END */ + +/* SNIP DartType */ +@override +void visitInstanceCreationExpression(InstanceCreationExpression node) { + // 2. Use the TypeChecker to check the type of a particular AstNode + const colorTypeChecker = TypeChecker.fromDart('Color', package: 'ui'); + final returnType = node.constructorName.staticElement?.returnType; + if (colorTypeChecker.isAssignableFromType(returnType)) { + // do something + } +} +/* SNIP DartType END */ diff --git a/website/sidecar/docs/concepts/type_checking.mdx b/website/sidecar/docs/concepts/type_checking.mdx new file mode 100644 index 00000000..756870f9 --- /dev/null +++ b/website/sidecar/docs/concepts/type_checking.mdx @@ -0,0 +1,35 @@ +--- +title: Type Checking +sidebar_position: 2 +description: "" +--- + +import CodeBlock from '@theme/CodeBlock'; +import dartTypeChecker from "!!raw-loader!./snippets/type_checking.dart"; +import { + generateSnippet, + CodeSnippet, +} from "../../src/components/CodeSnippet"; + +When creating a lint rule, you will often need to check if a node is of a certain type. +For example, you may want to find all class declarations which extend +`StatelessWidget` in order to perform some analysis on them. + +Unfortunately, we cannot just use the `is` keyword to check if a node is of a certain type, +because the analyzer can only provide us with `DartType` objects, which are not the same as +the `Type` objects we'd typically use when checking types in Dart programs. + +Fortunately, Sidecar ships with its own `TypeChecker` utility, which provides an easy +way for checking if an AstNode is of a certain type: + +{generateSnippet(dartTypeChecker, ['TypeChecker', 'ClassStart', 'ClassEnd', 'VisitMethod'])} + +There are two notable ways to create a TypeChecker: + +- `TypeChecker.fromName` - Used for non-Dart packages +- `TypeChecker.fromDartType` - Used for `dart` packages like `dart:core` or `dart:async` + + +{generateSnippet(dartTypeChecker, ['DartType'])} + +In both cases, the utility takes the name of the Type and the name of the Type's package. \ No newline at end of file diff --git a/website/sidecar/docs/core-concepts/_category_.json b/website/sidecar/docs/core-concepts/_category_.json deleted file mode 100644 index c9bd6311..00000000 --- a/website/sidecar/docs/core-concepts/_category_.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "label": "Core Concepts", - "position": 3, - "link": { - "type": "generated-index", - "description": "Learn how to use lint rules and other tools in your IDE and command line. For how-to guides on creating rules, see TODO." - } -} \ No newline at end of file diff --git a/website/sidecar/docs/core-concepts/how_it_works.mdx b/website/sidecar/docs/core-concepts/how_it_works.mdx deleted file mode 100644 index fbabeaea..00000000 --- a/website/sidecar/docs/core-concepts/how_it_works.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: How Sidecar Works -sidebar_position: 3 ---- diff --git a/website/sidecar/docs/core-concepts/main.dart b/website/sidecar/docs/core-concepts/main.dart deleted file mode 100644 index 17c84f4e..00000000 --- a/website/sidecar/docs/core-concepts/main.dart +++ /dev/null @@ -1,3 +0,0 @@ -/* SNIPPET START */ - -final x = Set(); diff --git a/website/sidecar/docs/core-concepts/publishing_rules.mdx b/website/sidecar/docs/core-concepts/publishing_rules.mdx deleted file mode 100644 index 8b82ac2c..00000000 --- a/website/sidecar/docs/core-concepts/publishing_rules.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Publishing a Rule Package -sidebar_position: 2 ---- \ No newline at end of file diff --git a/website/sidecar/docs/core-concepts/rules.mdx b/website/sidecar/docs/core-concepts/rules.mdx deleted file mode 100644 index 8f97bd4d..00000000 --- a/website/sidecar/docs/core-concepts/rules.mdx +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Creating a Rule -sidebar_position: 1 ---- - -import CodeBlock from '@theme/CodeBlock'; -import main from "!!raw-loader!./main.dart"; -import { - trimSnippet, - CodeSnippet, -} from "../../src/components/CodeSnippet"; - -Some imported code: - -{trimSnippet(main)} diff --git a/website/sidecar/docs/core-concepts/testing.mdx b/website/sidecar/docs/core-concepts/testing.mdx deleted file mode 100644 index 91511d9b..00000000 --- a/website/sidecar/docs/core-concepts/testing.mdx +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Testing -sidebar_position: 4 ---- - - -## Overview - -It's recommended for rule developers to take a TDD approach to writing rules, as it may help understand the boundaries of a particular use case. - diff --git a/website/sidecar/docs/intro.md b/website/sidecar/docs/intro.md index 30258843..542d7b66 100644 --- a/website/sidecar/docs/intro.md +++ b/website/sidecar/docs/intro.md @@ -1,20 +1,23 @@ --- sidebar_position: 1 +title: Introduction --- +:::caution -# Introduction +Sidecar is currently an experimental package and is not recommended to be used to create lints for production projects. -Sidecar is a framework for creating static analysis tools for Dart. - -It allows developers to create lint or quick assists that represent their app. +However, if you'd still like to proceed and create your own lints, these docs can certainly help get you started. +For any additional questions that you have, dont hesitate to reach out on [Discord](https://discord.gg/YhFS6V26Vg). +::: ## Getting Started -### Usage Guides - -Intended for end users of Sidecar-based rule packages. Contains information about... +Sidecar is a framework for creating custom lint and quick fix rules for Dart and Flutter projects. -### Developer Guide +For information on how to set up a rule package in order to display lints throughout your codebase or CLI, check out the [usage guides](category/usage-guides) +for setup steps and troublshooting tips. -Intended for individuals who wish to extend Sidecar and create their own rules. +If you want to create your own lint rules, we've created several [tutorials](category/tutorials) that break down the process of doing so. +But before diving in, its highly recommended that you fully understand the [core concepts](category/core-concepts) and usage guides of both +sidecar and [package:analyzer](https://pub.dev/packages/analyzer). diff --git a/website/sidecar/docs/tutorials/_category_.json b/website/sidecar/docs/tutorials/_category_.json index b84fc017..7a0df814 100644 --- a/website/sidecar/docs/tutorials/_category_.json +++ b/website/sidecar/docs/tutorials/_category_.json @@ -1,4 +1,8 @@ { "label": "Tutorials", - "position": 4 + "position": 4, + "link": { + "type": "generated-index", + "description": "Learn the process of creating your own lint rules. It's highly recommended that you start from Hello World and follow the rest in order, as each lesson builds upon concepts introduced in previous tutorials." + } } \ No newline at end of file diff --git a/website/sidecar/docs/tutorials/design_system_insets.mdx b/website/sidecar/docs/tutorials/_design_system_insets.mdx similarity index 86% rename from website/sidecar/docs/tutorials/design_system_insets.mdx rename to website/sidecar/docs/tutorials/_design_system_insets.mdx index 8b59f462..56198bd6 100644 --- a/website/sidecar/docs/tutorials/design_system_insets.mdx +++ b/website/sidecar/docs/tutorials/_design_system_insets.mdx @@ -1,6 +1,7 @@ --- title: Design System Insets sidebar_position: 5 +description: "" --- import CodeBlock from '@theme/CodeBlock'; @@ -12,6 +13,13 @@ import { CodeSnippet, } from "../../src/components/CodeSnippet"; +## Objective + +A design system is a standardization concept that abstracts the design specifics of an application into reusable components. +In a Flutter application, we could isolate any design specifics to a `theme.dart` file, and reference our theme anywhere +in our application. + + ### Learning Objectives - Multiple similar use cases (EdgeInsets.all, .only, .symmetric) diff --git a/website/sidecar/docs/tutorials/string_locator.mdx b/website/sidecar/docs/tutorials/_string_locator.mdx similarity index 55% rename from website/sidecar/docs/tutorials/string_locator.mdx rename to website/sidecar/docs/tutorials/_string_locator.mdx index 25061f9e..a03e371a 100644 --- a/website/sidecar/docs/tutorials/string_locator.mdx +++ b/website/sidecar/docs/tutorials/_string_locator.mdx @@ -1,6 +1,7 @@ --- title: String Locator -sidebar_position: 3 +sidebar_position: 2 +description: "" --- import CodeBlock from '@theme/CodeBlock'; @@ -9,13 +10,19 @@ import example from "!!raw-loader!../../../../examples/hello_world_rules/example import pubspec from "!!raw-loader!../../../../examples/hello_world_rules/pubspec.yaml"; import { trimSnippet, + generateSnippet, CodeSnippet, } from "../../src/components/CodeSnippet"; +## Introduction + +In the previous tutorial, we learned the basics of creating a LintRule and how to +enable rules in an example app. Now we'll take what we learned to come up with a +more real use case: finding any string that doesn't come from a translation library. ## Objective -Find all string literals used in 'Text' widgets +Find all string literals used in 'Text' widgets. ### Learning Objectives @@ -25,4 +32,7 @@ Find all string literals used in 'Text' widgets ### Notes: -- I dont love this example; without Refactoring features it may seem half-baked \ No newline at end of file +- I dont love this example; without Refactoring features it may seem half-baked +- However, we could use this as an opportunity to compare to existing packages that try to satisfy the same goal +- E.g. string_literal_finder (https://github.com/hpoul/string_literal_finder/issues?q=is%3Aissue+) +- e.g. localizely \ No newline at end of file diff --git a/website/sidecar/docs/tutorials/bloc_file_structure.mdx b/website/sidecar/docs/tutorials/bloc_file_structure.mdx index 190ecf53..eaa8a9b0 100644 --- a/website/sidecar/docs/tutorials/bloc_file_structure.mdx +++ b/website/sidecar/docs/tutorials/bloc_file_structure.mdx @@ -1,23 +1,152 @@ --- title: Bloc File Structure -sidebar_position: 2 +sidebar_position: 3 +description: "" --- import CodeBlock from '@theme/CodeBlock'; import ruleDefintion from "!!raw-loader!../../../../examples/hello_world_rules/lib/hello_world_rules.dart"; -import example from "!!raw-loader!../../../../examples/hello_world_rules/example/lib/example.dart"; -import pubspec from "!!raw-loader!../../../../examples/hello_world_rules/pubspec.yaml"; +import rule from "!!raw-loader!../../lib/src/tutorials/bloc_feature_structure/lib/bloc_outside_controller_layer.dart"; +import pubspec from "!!raw-loader!../../lib/src/tutorials/bloc_feature_structure/lib/step1a.yaml"; + import { trimSnippet, CodeSnippet, + generateSnippet, } from "../../src/components/CodeSnippet"; +> NOTE: This guide is a work in progress. + ## Overview -Prevent developers from putting bloc code in UI files. +Let's say we want to enforce all developers on our Flutter app to use a feature-first project structure. + +A typical feature-first folder structure for a Flutter app may look something like the following: + +``` +├── core +├── features +│ ├── cart +│ │ ├── data +│ │ │ ├── models +│ │ │ ├── repositories +│ │ │ ├── services +│ │ ├── domain +│ │ │ ├── entities +│ │ │ ├── repositories +│ │ ├── presentation +│ │ │ ├── controllers +│ │ │ ├── states +│ │ │ ├── widgets +``` +> *The above structure is roughly based on [this great architecture series](https://codewithandrea.com/articles/flutter-app-architecture-riverpod-introduction/) +> by Andrea Bizzotto.* + +In order to enforce the use of such a structure programmatically, we could implement any of the following cases: + +- only permit the declaration of widgets in the appropriate `widgets` folders +- prevent json serialization/deserialization from anywhere besides `data` layer +- enforce the use of dependency injection between layers +- only permit the declaration of business logic in `controllers` folder (such as `BlocBase` or `Notifier` classes) + +In this tutorial, we will focus on the latter case, specifically by disallowing the creation of BLoC classes in any folder besides +the presentation > controller layer. ### Learning Objectives -- Conditional lint rule -- Inspects path of ResolvedUnitResult -- Using context variables (like ```unit```) +- Using `visitCompilationUnit` and `unit` to check if a file is in the correct folder +- Performance Considerations when writing LintRules +- Using `TypeChecker` to check if a class declaration extends a particular type + + +## Define Requirements + +Determining the logic of a Lint rule can be tricky. For this feature-first BLoC rule, we want to prevent a developer from +creating a bloc class outside of presentation > controller, but this can possibly be done in different ways. +Additionally, we want to be mindful that the performance of all of our lints could be negatively affected if +just one lint rule is written in an inefficient way, so we need to write our lint in an efficient way. + +Therefore, the logic of our rule will be: + +1. Restrict our rule from executing on anything besides files contained in `**/presentation/controller/**` folders +2. Check if any particular class declaration extends `BlocBase` +3. OPTIONAL: Check if the particular file imports package:bloc before checking all class declarations for a BlocBase extension + +With requirements defined, we can move onto the build phase. + +## Declaring our Rule + +Lets start by creating a rule package `bloc_feature_structure` and adding `sidecar` +and `analyzer` to `pubspec.yaml`. + + +```bash +dart create bloc_feature_structure +``` + +{trimSnippet(pubspec, [''])} + +Our first course of action is to create our LintRule class and its respective LintCode. + + +{generateSnippet(rule, ['LINTCODE', 'ClassStart', 'CLASSEND', 'RuleImports'])} + +Just as we did in the previous tutorial, we ensure that the class name is the PascalCase representation of the LintCode.id +that we assign, and we also ensure that the LintCode.id is the snake_case representation of the class name. We also make sure +that the package name is the same as the package name in `pubspec.yaml`. + +> NOTE: These requirements can be referenced in the [rule creation checklist](/docs/concepts/rule_creation_checklist) + +## Implementing our Rule Logic + +### Using `visitCompilationUnit` to check a file path + +From here we can build out the first of our requirements: to only analyze files outside of the application folder. + +If you remember back to our feature-first project structure, we only want our rule to analyze files that are outside of the `presentation/controllers` +folder, since we should not be creating BLoC classes in any other folder. + +In Sidecar, rule execution is scoped to a single file, and we can use the `unit` context variable to see exactly what file +is being analyzed. We can use the package `glob` to check if the file path matches the particular `presentation/controllers` +folder we're filtering for. + + +{generateSnippet(rule, ['ClassStart', 'CLASSEND', 'VisitCompilationUnit', 'isApplicationFile'])} + +In this example, we create a `isControllerFile` variable that will store the result of our glob check. We can then use this variable +in our `visitClassDeclaration` method before proceeding with the rest of our logic. + +### Type-checking a class declaration + +Finally, we create our logic that checks if the class declaration extends `BlocBase` and if so, we report the lint. +Unfortunately, we cannot simply import `BlocBase` from `package:bloc` and use it to type check our class declaration, +as the analyzer does not provide us with a `Type` object to compare against. + +Instead, we must use the `TypeChecker` utility shipped in Sidecar, which gives us a simple way to check if an analyzed type +matches a particular type that we're looking for. + +> NOTE: If you're interested in learning more about the `TypeChecker` utility, you can read more about it [here](/docs/concepts/type_checking) + +{generateSnippet(rule, ['ClassStart', 'CLASSEND', 'isApplicationFile', 'visitClassDeclaration'])} + +### Performance Considerations + +The reason we don't handle the file-check logic directly in `visitClassDeclaration` is because we always want to avoid unnecessary computation +in the case that a particular file has multiple class declarations. If we were to instead check the file path in `visitClassDeclaration`, +we would be redundantly checking the file path every time, and this could be a performance bottleneck. + +When writing a lint rule, we want to make sure that we are only performing the necessary computation to ensure that our lint is as performant as possible. +This is necessary when developers expect lints to appear after every file change within fractions of a second in the code editor. + + +## Conclusion + +TODO + + \ No newline at end of file diff --git a/website/sidecar/docs/tutorials/design_system_methods.mdx b/website/sidecar/docs/tutorials/design_system_methods.mdx deleted file mode 100644 index e9750966..00000000 --- a/website/sidecar/docs/tutorials/design_system_methods.mdx +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: Design System Methods -sidebar_position: 7 ---- - -import CodeBlock from '@theme/CodeBlock'; -import ruleDefintion from "!!raw-loader!../../../../examples/hello_world_rules/lib/hello_world_rules.dart"; -import example from "!!raw-loader!../../../../examples/hello_world_rules/example/lib/example.dart"; -import pubspec from "!!raw-loader!../../../../examples/hello_world_rules/pubspec.yaml"; -import { - trimSnippet, - CodeSnippet, -} from "../../src/components/CodeSnippet"; - -### Learning Objectives - -- - diff --git a/website/sidecar/docs/tutorials/hello_world.mdx b/website/sidecar/docs/tutorials/hello_world.mdx index 0afd3615..f6baa5bf 100644 --- a/website/sidecar/docs/tutorials/hello_world.mdx +++ b/website/sidecar/docs/tutorials/hello_world.mdx @@ -1,11 +1,16 @@ --- title: Hello World sidebar_position: 1 +description: "" --- import CodeBlock from '@theme/CodeBlock'; import ruleDefintion from "!!raw-loader!../../../../examples/hello_world_rules/lib/hello_world_rules.dart"; import example from "!!raw-loader!../../../../examples/hello_world_rules/example/lib/example.dart"; +import step0 from "!!raw-loader!../../lib/src/tutorials/hello_world/lib/step0.dart"; +import step1 from "!!raw-loader!../../lib/src/tutorials/hello_world/lib/step1.dart"; +import step2 from "!!raw-loader!../../lib/src/tutorials/hello_world/lib/step2.dart"; +import step3 from "!!raw-loader!../../lib/src/tutorials/hello_world/lib/step3.dart"; import pubspec from "!!raw-loader!../../../../examples/hello_world_rules/pubspec.yaml"; import { trimSnippet, @@ -14,7 +19,7 @@ import { ## Overview -This tutorial will give you a brief introduction to creating rules. +This tutorial will give you an in-depth introduction to creating a basic rule. At the conclusion of the tutorial, we will have the following code showing a lint message. @@ -22,29 +27,138 @@ At the conclusion of the tutorial, we will have the following code showing a lin ### Learning Objectives -After completion, we will know how to do the following: +- Explore the basics of the ```LintRule``` class +- Create analyzer logic for our particular use case +- Requirements for declaring the rule so that it can be discovered by Sidecar +- Validating a LintRule within our IDE -- Explore the base ```Rule``` class which every rule must extend -- Declaring the rule in a way that allows it to be discovered by Sidecar -- Create a Lint Rule that appears in our IDE +## Defining a Rule -Let's get started. +### Creating a new Rule Package -## Creating a Rule Package +Our first step is to create a package for our lints to reside in, and add the necessary dependencies to our pubspec.yaml file. -- rule packages can contain 1 or more rules -- ```dart create hello_world_rules``` -- import Sidecar and analyzer packages +```bash +# create our package and open the directory +dart create hello_world_rules && cd hello_world_rules -## Defining our Rule +# add sidecar dependency +dart pub add sidecar -- explain the thought-process behind what we want the lint to do -- extend Rule base class and Lint -- use Simple String literal visitor -- LintCode explanation -- adding lint code to package's pubspec.yaml file +# add official package:analyzer +dart pub add analyzer +``` -## Validating our LintRule in IDE +> NOTE: version conflicts will arise if using a Dart SDK version thats not v2.17.0 -- Create an example app (dart command) -- add string \ No newline at end of file +Though a rule package can contain one or more rules, for this example we'll create a single Lint Rule. + +{trimSnippet(step0)} + +The summary of all Sidecar Rule requirements are: + +- [ ] every rule must have a unique rule ID (in snake_case) +- [ ] the class name of the Rule must match the rule ID (in PascalCase) +- [ ] the `code.package` parameter must match the name given to our rule package + + +### Defining the Logic for our use case + +For our paricular rule, we want to create a lint that simply outputs 'Hello world!' +any time we create code that has a string containing 'Is there anybody there?'. +Our requirements are therefore: + +- Analyze all Strings +- If the String value is equal to the text 'Is there anybody there?' then report a lint with the message 'Hello world!' + +In order to analyze all Strings in a particular file, we must override the `visitSimpleStringLiteral` method. + In later tutorials, we will cover how to determine which visit method(s) to use for a given use case. + + +{trimSnippet(step1)} + +The takeaway here is that the logic we write within this method will be executed for every String literal that appears in our codebase, +and the information of this code will be delivered via the `node` parameter of all visit methods. + +For our use case, we want to check if the particular String contains the code 'Is there anybody there?'. We do so easily by writing the following logic: + +{trimSnippet(step2)} + +The last thing we must do for our newly created Rule class is add our rule's `visitSimpleStringLiteral` method to Sidecar's NodeRegistry; +without this step, our visitor method will never be executed. + + +{trimSnippet(step3)} + +We've now fully defined our `HelloWorld` rule class! + +### Making our Rule Visible to Sidecar + +There are two other requirements that make our newly created rule visible to sidecar: + +- adding lint code to package's pubspec.yaml file (see: [sidecar_lints pubspec](https://github.com/pattobrien/sidecar/blob/master/packages/sidecar_lints/pubspec.yaml#L32)) +- ensuring the rule is available from lib/hello_world_rules.dart (see: [lib/sidecar_lints.dart](https://github.com/pattobrien/sidecar/blob/master/packages/sidecar_lints/lib/sidecar_lints.dart)) + +## Validating our LintRule in an IDE + +The best way to visually test if our lint is working is by creating an example package: + +```bash +# create new project within the root hello_world_rules directory +dart create example && cd example + +# add our new rules package from path +dart pub add hello_world_rules --path ../ +``` +We can now add our rule to our sidecar.yaml file: + + +And finally, we can enable sidecar in our analysis_options.yaml file: + +```yaml +analyzer: + plugins: + - sidecar +``` + +With our example app set up, all that's left to do is add our 'Is there anybody there?' string into a dart file, +and you should see a lint appear over the string. + +{trimSnippet(example)} + +Congrats! You've created your first lint rule. 🎉 + +## Conclusion + +This is a simple example of what it takes to create a custom lint rule using Sidecar. +On one hand, creating the logic to analyze code can be relatively straightforward, +only taking a few lines of code to write: + +``` + void visitSimpleStringLiteral(SimpleStringLiteral node) { + final stringValue = node.value; + if (stringValue == 'Is there anybody there?') { + reportAstNode(node, message: 'Hello world!'); + } + } +``` +On the otherhand, there are many individual requirements to abide by, and forgetting any +of them results in no lint appearing at all. + + +The [rule creation checklist](../concepts/rule_creation_checklist.mdx) makes it easy to ensure you've covered all the bases. +Additionally, it's highly recommended to use package:sidecar_lints to help ensure all of your rules are properly defined for Sidecar. + + diff --git a/website/sidecar/docs/tutorials/quick_fix.mdx b/website/sidecar/docs/tutorials/quick_fix.mdx deleted file mode 100644 index 00fd152f..00000000 --- a/website/sidecar/docs/tutorials/quick_fix.mdx +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: ??? -sidebar_position: 6 ---- - -import CodeBlock from '@theme/CodeBlock'; -import ruleDefintion from "!!raw-loader!../../../../examples/hello_world_rules/lib/hello_world_rules.dart"; -import example from "!!raw-loader!../../../../examples/hello_world_rules/example/lib/example.dart"; -import pubspec from "!!raw-loader!../../../../examples/hello_world_rules/pubspec.yaml"; -import { - trimSnippet, - CodeSnippet, -} from "../../src/components/CodeSnippet"; - -### Learning Objectives - -- Lints with QuickFixes - diff --git a/website/sidecar/docs/tutorials/riverpod_final_providers.mdx b/website/sidecar/docs/tutorials/riverpod_final_providers.mdx deleted file mode 100644 index dbb3a342..00000000 --- a/website/sidecar/docs/tutorials/riverpod_final_providers.mdx +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: Riverpod Final Providers -sidebar_position: 5 ---- - -import CodeBlock from '@theme/CodeBlock'; -import ruleDefintion from "!!raw-loader!../../../../examples/hello_world_rules/lib/hello_world_rules.dart"; -import example from "!!raw-loader!../../../../examples/hello_world_rules/example/lib/example.dart"; -import pubspec from "!!raw-loader!../../../../examples/hello_world_rules/pubspec.yaml"; -import { - trimSnippet, - CodeSnippet, -} from "../../src/components/CodeSnippet"; - -### Learning Objectives - -- Audience: Package Author - diff --git a/website/sidecar/docs/usage/_category_.json b/website/sidecar/docs/usage/_category_.json index 1e103372..97650cd9 100644 --- a/website/sidecar/docs/usage/_category_.json +++ b/website/sidecar/docs/usage/_category_.json @@ -3,6 +3,6 @@ "position": 1, "link": { "type": "generated-index", - "description": "Learn how to use lint rules and other tools in your IDE and command line. For how-to guides on creating rules, see TODO." + "description": "Learn the basics of enabling and customizing sidecar rules in your IDE or CLI." } } \ No newline at end of file diff --git a/website/sidecar/docs/usage/configuration.md b/website/sidecar/docs/usage/configuration.md deleted file mode 100644 index abe75d9c..00000000 --- a/website/sidecar/docs/usage/configuration.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -sidebar_position: 3 -sidebar_label: 'Configuration' ---- - -# Configuration (sidecar.yaml) - -TODO \ No newline at end of file diff --git a/website/sidecar/docs/usage/intial_setup.mdx b/website/sidecar/docs/usage/intial_setup.mdx index 3918670c..00981546 100644 --- a/website/sidecar/docs/usage/intial_setup.mdx +++ b/website/sidecar/docs/usage/intial_setup.mdx @@ -1,11 +1,15 @@ --- sidebar_position: 2 +title: IDE and CLI Setup +description: Setup rules for use within an IDE or CLI. --- import CodeBlock from '@theme/CodeBlock'; import main from "!!raw-loader!./snippets/configuration-simple.yaml"; import analysisOptions from "!!raw-loader!./snippets/analysis_options.yaml"; import pubspec from "!!raw-loader!./snippets/pubspec.yaml"; +import cliOutputImage from '../../static/img/cli_output.png'; + import { trimSnippet, CodeSnippet, @@ -14,18 +18,21 @@ import { # Initial Setup -There are 2 modes which Sidecar packages can be run within a Dart or Flutter Project: IDE Server or Cli mode. +Sidecar is used via Sidecar-based rule packages like [design_system_lints](https://pub.dev/packages/design_system_lints). + +There are 2 modes which these packages can be run within a Dart or Flutter Project: IDE Server or Cli mode. ## IDE Server Mode ### Requirements -- Dart SDK v2.17.0+ - Supported IDE with Extension for Dart Language Server +- Dart SDK v2.17.0+ ### Setup Instructions -To enable any Sidecar-based package (like [design_system_lints](https://pub.dev/packages/design_system_lints)) to display lints and assist recommendations within your IDE, perform the following setup steps: +To enable any Sidecar-based package like [design_system_lints](https://pub.dev/packages/design_system_lints) +to display lints and assist recommendations within your IDE, perform the following setup steps: 1. Depend on the lint package: @@ -35,11 +42,11 @@ To enable any Sidecar-based package (like [design_system_lints](https://pub.dev/ {trimSnippet(main)} -3. Enable the plugin to run by adding ```sidecar``` to the list of plugins in ```analysis_options.yaml``` +3. Enable the Sidecar plugin to run by adding ```sidecar``` to the list of plugins in ```analysis_options.yaml``` {trimSnippet(analysisOptions)} -After several seconds of start-up (and potentially a restart of your IDE), the lints should begin appearing in your editor. +That's all it takes! Your lints should begin appearing in your editor. ## CLI Mode @@ -54,4 +61,11 @@ dart pub global activate sidecar sidecar analyze ``` -> NOTE: If you have a particular CLI use case in mind and would like to give feedback, feel free to reach out on Github. +You should see analysis results appear for each file in your project: + +CLI Output example + + +### Contributing CLI Use Cases + +If you have a particular CLI use case in mind, your feedback would be greatly appreciated in the [Discord channel](https://discord.gg/YhFS6V26Vg) diff --git a/website/sidecar/docs/usage/playground.md b/website/sidecar/docs/usage/playground.md deleted file mode 100644 index 3e923b38..00000000 --- a/website/sidecar/docs/usage/playground.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -sidebar_position: 4 ---- - -# Playground \ No newline at end of file diff --git a/website/sidecar/docs/usage/snippets/.gitignore b/website/sidecar/docs/usage/snippets/.gitignore new file mode 100644 index 00000000..8d15be0b --- /dev/null +++ b/website/sidecar/docs/usage/snippets/.gitignore @@ -0,0 +1 @@ +.dart_tool/ \ No newline at end of file diff --git a/website/sidecar/docs/usage/troubleshooting.md b/website/sidecar/docs/usage/troubleshooting.md index 85800306..9ff48a71 100644 --- a/website/sidecar/docs/usage/troubleshooting.md +++ b/website/sidecar/docs/usage/troubleshooting.md @@ -1,10 +1,25 @@ --- sidebar_position: 4 +description: What to do when lints no longer update, RAM usage, etc. --- # Troubleshooting -In IDE-Server mode, Sidecar boots up using the ```analyzer_plugin``` APIs created by the Dart team. Due to the experimental nature of that package, there are some limitations that users should be aware of. +In IDE-Server mode, Sidecar boots up using the ```analyzer_plugin``` APIs created by the Dart team. +Due to the experimental nature of both Sidecar and analyzer_plugin, there are some limitations that users should be aware of. -- Performance (duplicated RAM resources) -- Lints stop updating (reboot server) +## Lints no longer updating + +When using a lint package, its possible that you experience unexpected problems, such as: + +- A particular file does not show lints +- Lints dont update when editing a file and/or lints are seen appearing over the wrong code + +While the remaining bugs are being ironed out, the recommended fix is to restart the analyzer server and/or restart your IDE +(can be done via Dart official extensions). +## Increased RAM resources + +Since the official Dart lints do not themselves use the analyzer_plugin architecture, +they are run on a separate isolate than Sidecar rules. Because both Dart programs must analyze the entire +Dart package and dependencies, enabling Sidecar is expected to have some increase in RAM resources +(expect around 25% increase, but no more than a 50% increase). diff --git a/website/sidecar/docusaurus.config.js b/website/sidecar/docusaurus.config.js index cd1bcf1e..5400e8ef 100644 --- a/website/sidecar/docusaurus.config.js +++ b/website/sidecar/docusaurus.config.js @@ -6,17 +6,17 @@ const darkCodeTheme = require('prism-react-renderer/themes/dracula'); /** @type {import('@docusaurus/types').Config} */ const config = { - title: 'Sidecar', - tagline: 'Dinosaurs are cool', - url: 'https://your-docusaurus-test-site.com', + title: 'Sidecar Analyzer', + tagline: 'Enable a more personalized developer experience within your IDE.', + url: 'https://sidecaranalyzer.dev', baseUrl: '/', onBrokenLinks: 'throw', onBrokenMarkdownLinks: 'warn', - favicon: 'img/favicon.ico', + // favicon: 'img/favicon.ico', // GitHub pages deployment config. // If you aren't using GitHub pages, you don't need these. - organizationName: 'facebook', // Usually your GitHub org/user name. + organizationName: 'pattobrien', // Usually your GitHub org/user name. projectName: 'sidecar', // Usually your repo name. // Even if you don't use internalization, you can use this field to set useful @@ -36,15 +36,15 @@ const config = { sidebarPath: require.resolve('./sidebars.js'), // Please change this to your repo. // Remove this to remove the "edit this page" links. - editUrl: - 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', + // editUrl: + // 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', }, blog: { showReadingTime: true, // Please change this to your repo. // Remove this to remove the "edit this page" links. - editUrl: - 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', + // editUrl: + // 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', }, theme: { customCss: require.resolve('./src/css/custom.scss'), @@ -60,11 +60,11 @@ const config = { defaultMode: "dark", }, navbar: { - title: 'Sidecar', - logo: { - alt: 'My Site Logo', - src: 'img/logo.svg', - }, + title: 'Sidecar Analyzer', + // logo: { + // alt: 'My Site Logo', + // src: 'img/logo.svg', + // }, items: [ // { // type: 'doc', @@ -109,12 +109,12 @@ const config = { // }, { label: 'Discord', - href: 'https://discordapp.com/invite/sidecar', - }, - { - label: 'Twitter', - href: 'https://twitter.com/docusaurus', + href: 'https://discord.gg/YhFS6V26Vg', }, + // { + // label: 'Twitter', + // href: 'https://twitter.com/pattobrien', + // }, ], }, { diff --git a/website/sidecar/lib/src/tutorials/design_system_insets/.gitignore b/website/sidecar/lib/src/tutorials/bloc_feature_structure/.gitignore similarity index 100% rename from website/sidecar/lib/src/tutorials/design_system_insets/.gitignore rename to website/sidecar/lib/src/tutorials/bloc_feature_structure/.gitignore diff --git a/website/sidecar/lib/src/tutorials/design_system_insets/CHANGELOG.md b/website/sidecar/lib/src/tutorials/bloc_feature_structure/CHANGELOG.md similarity index 100% rename from website/sidecar/lib/src/tutorials/design_system_insets/CHANGELOG.md rename to website/sidecar/lib/src/tutorials/bloc_feature_structure/CHANGELOG.md diff --git a/website/sidecar/lib/src/tutorials/design_system_insets/README.md b/website/sidecar/lib/src/tutorials/bloc_feature_structure/README.md similarity index 100% rename from website/sidecar/lib/src/tutorials/design_system_insets/README.md rename to website/sidecar/lib/src/tutorials/bloc_feature_structure/README.md diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/analysis_options.yaml b/website/sidecar/lib/src/tutorials/bloc_feature_structure/analysis_options.yaml new file mode 100644 index 00000000..cfe4967b --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/analysis_options.yaml @@ -0,0 +1,3 @@ +analyzer: + plugins: + # - sidecar diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/.gitignore b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/.gitignore new file mode 100644 index 00000000..3c8a1572 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/.gitignore @@ -0,0 +1,6 @@ +# Files and directories created by pub. +.dart_tool/ +.packages + +# Conventional directory for build output. +build/ diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/CHANGELOG.md b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/CHANGELOG.md new file mode 100644 index 00000000..effe43c8 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/README.md b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/README.md new file mode 100644 index 00000000..3816eca3 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/README.md @@ -0,0 +1,2 @@ +A sample command-line application with an entrypoint in `bin/`, library code +in `lib/`, and example unit test in `test/`. diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/analysis_options.yaml b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/analysis_options.yaml new file mode 100644 index 00000000..02fa8fa2 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/analysis_options.yaml @@ -0,0 +1,3 @@ +analyzer: + plugins: + - sidecar diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/lib/src/features/cart/application/cart_bloc.dart b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/lib/src/features/cart/application/cart_bloc.dart new file mode 100644 index 00000000..e56a265d --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/lib/src/features/cart/application/cart_bloc.dart @@ -0,0 +1,5 @@ +import 'package:bloc/bloc.dart'; + +class SomeBlocClass extends BlocBase { + SomeBlocClass(super.state); +} diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/lib/src/features/cart/presentation/view.dart b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/lib/src/features/cart/presentation/view.dart new file mode 100644 index 00000000..e56a265d --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/lib/src/features/cart/presentation/view.dart @@ -0,0 +1,5 @@ +import 'package:bloc/bloc.dart'; + +class SomeBlocClass extends BlocBase { + SomeBlocClass(super.state); +} diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/pubspec.yaml b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/pubspec.yaml new file mode 100644 index 00000000..3c2e54ab --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/pubspec.yaml @@ -0,0 +1,20 @@ +name: example +description: A sample command-line application. +version: 1.0.0 +publish_to: none + +environment: + sdk: ">=2.17.6 <3.0.0" + +dependencies: + bloc: ^8.1.0 + bloc_feature_structure: + path: ../ + +dev_dependencies: + lints: ^2.0.0 + test: ^1.16.0 + +dependency_overrides: + sidecar: + path: ../../../../../../../packages/sidecar/ diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/sidecar.yaml b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/sidecar.yaml new file mode 100644 index 00000000..4f44c957 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/example/sidecar.yaml @@ -0,0 +1,7 @@ +includes: + - "lib/**/*.dart" + +lints: + bloc_feature_structure: + rules: + bloc_outside_controller_layer: diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/lib/bloc_outside_controller_layer.dart b/website/sidecar/lib/src/tutorials/bloc_feature_structure/lib/bloc_outside_controller_layer.dart new file mode 100644 index 00000000..decd8f45 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/lib/bloc_outside_controller_layer.dart @@ -0,0 +1,57 @@ +/* SNIP RuleImports */ +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:sidecar/sidecar.dart'; +/* SNIP RuleImports END */ +/* SNIP GlobImport */ +import 'package:glob/glob.dart'; +/* SNIP GlobImport */ + +/* SNIP ClassStart */ +class BlocOutsideControllerLayer extends LintRule { + /* SNIP ClassStart END */ + /* SNIP LINTCODE */ + static const id = 'bloc_outside_controller_layer'; + static const package = 'bloc_feature_structure'; + static const message = 'Logic should be created in application folders.'; + + @override + LintCode get code => const LintCode(id, package: package); + /* SNIP LINTCODE END */ + + /* SNIP VisitCompilationUnit */ + @override + void visitCompilationUnit(CompilationUnit node) { + final controllersFolderGlob = Glob('**/features/**/controllers/**'); + isControllerFile = controllersFolderGlob.matches(unit.path); + } + + /* SNIP VisitCompilationUnit END */ + /* SNIP isApplicationFile */ + late final bool isControllerFile; + /* SNIP isApplicationFile END */ + + /* SNIP initializeVisitor */ + @override + void initializeVisitor(NodeRegistry registry) => + registry.addCompilationUnit(this); + /* SNIP initializeVisitor END */ + + /* SNIP visitClassDeclaration */ + @override + void visitClassDeclaration(ClassDeclaration node) { + // dont perform type analysis on files inside of controller folders + if (isControllerFile) return; + + // type check against the type of the declared class + final classType = node.declaredElement2?.thisType; + final blocBase = TypeChecker.fromPackage('BlocBase', package: 'bloc'); + if (!blocBase.isAssignableFromType(classType)) return; + + reportAstNode(node.name, message: message); + } + /* SNIP visitClassDeclaration END */ + /* SNIP CLASSEND */ +} +/* SNIP CLASSEND END */ + +/* SNIPPET END */ diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/lib/step1a.yaml b/website/sidecar/lib/src/tutorials/bloc_feature_structure/lib/step1a.yaml new file mode 100644 index 00000000..82adbc03 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/lib/step1a.yaml @@ -0,0 +1,12 @@ +name: bloc_feature_structure +version: 1.0.0 + +environment: + sdk: ">=2.17.0 <3.0.0" + +dependencies: + analyzer: ^4.7.0 + sidecar: ^0.1.0-dev.18 + +dev_dependencies: + sidecar_lints: ^0.1.0-dev.1 diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/lib/step3.dart b/website/sidecar/lib/src/tutorials/bloc_feature_structure/lib/step3.dart new file mode 100644 index 00000000..8f7c5b2e --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/lib/step3.dart @@ -0,0 +1,42 @@ +/* SNIPPET START */ +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:glob/glob.dart'; +import 'package:sidecar/sidecar.dart'; + +class BlocOutsideControllerLayer extends LintRule { + /* SKIP */ + // we can use variables for better code legibility + static const _id = 'bloc_outside_controller_layer'; + static const _package = 'bloc_feature_structure'; + static const _message = 'Logic should be created in application folders.'; + + @override + LintCode get code => const LintCode(_id, package: _package); + + @override + void visitCompilationUnit(CompilationUnit node) { + final applicationFolderGlob = Glob('**/features/**/application/**'); + isApplicationFile = applicationFolderGlob.matches(unit.path); + } + + late final bool isApplicationFile; + + @override + void initializeVisitor(NodeRegistry registry) => + registry.addCompilationUnit(this); + + /* SKIP END */ + @override + void visitClassDeclaration(ClassDeclaration node) { + // skip any files within an `application` folder + if (isApplicationFile) return; + + final blocBase = TypeChecker.fromPackage('BlocBase', package: 'bloc'); + final classType = node.declaredElement2?.thisType; + if (!blocBase.isAssignableFromType(classType)) return; + + reportAstNode(node.name, message: _message); + } +} + +/* SNIPPET END */ \ No newline at end of file diff --git a/website/sidecar/lib/src/tutorials/bloc_feature_structure/pubspec.yaml b/website/sidecar/lib/src/tutorials/bloc_feature_structure/pubspec.yaml new file mode 100644 index 00000000..dadf9dbc --- /dev/null +++ b/website/sidecar/lib/src/tutorials/bloc_feature_structure/pubspec.yaml @@ -0,0 +1,24 @@ +name: bloc_feature_structure +version: 1.0.0 +publish_to: none + +environment: + sdk: ">=2.17.6 <3.0.0" + +dependencies: + analyzer: ^4.7.0 + glob: ^2.1.1 + sidecar: ^0.1.0-dev.19 + +dev_dependencies: + sidecar_lints: ^0.1.0-dev.1 + +dependency_overrides: + sidecar: + path: ../../../../../../packages/sidecar/ + sidecar_lints: + path: ../../../../../../packages/sidecar_lints/ + +sidecar: + lints: + - bloc_outside_controller_layer diff --git a/website/sidecar/lib/src/tutorials/design_system_insets/.dart_tool/package_config.json b/website/sidecar/lib/src/tutorials/design_system_insets/.dart_tool/package_config.json new file mode 100644 index 00000000..4ba24a69 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/design_system_insets/.dart_tool/package_config.json @@ -0,0 +1,290 @@ +{ + "configVersion": 2, + "packages": [ + { + "name": "_fe_analyzer_shared", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-47.0.0", + "packageUri": "lib/", + "languageVersion": "2.17" + }, + { + "name": "analyzer", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/analyzer-4.7.0", + "packageUri": "lib/", + "languageVersion": "2.17" + }, + { + "name": "args", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/args-2.3.1", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "async", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/async-2.9.0", + "packageUri": "lib/", + "languageVersion": "2.14" + }, + { + "name": "boolean_selector", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.1", + "packageUri": "lib/", + "languageVersion": "2.17" + }, + { + "name": "collection", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/collection-1.17.0", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "convert", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/convert-3.1.0", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "coverage", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/coverage-1.6.2", + "packageUri": "lib/", + "languageVersion": "2.15" + }, + { + "name": "crypto", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.2", + "packageUri": "lib/", + "languageVersion": "2.14" + }, + { + "name": "file", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/file-6.1.4", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "frontend_server_client", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/frontend_server_client-2.1.3", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "glob", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/glob-2.1.1", + "packageUri": "lib/", + "languageVersion": "2.15" + }, + { + "name": "http_multi_server", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/http_multi_server-3.2.1", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "http_parser", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/http_parser-4.0.2", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "io", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/io-1.0.4", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "js", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/js-0.6.5", + "packageUri": "lib/", + "languageVersion": "2.16" + }, + { + "name": "lints", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/lints-2.0.1", + "packageUri": "lib/", + "languageVersion": "2.17" + }, + { + "name": "logging", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/logging-1.1.0", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "matcher", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.12", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "meta", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/meta-1.8.0", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "mime", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/mime-1.0.3", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "node_preamble", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/node_preamble-2.0.1", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "package_config", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/package_config-2.1.0", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "path", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/path-1.8.3", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "pool", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/pool-1.5.1", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "pub_semver", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/pub_semver-2.1.3", + "packageUri": "lib/", + "languageVersion": "2.17" + }, + { + "name": "shelf", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/shelf-1.4.0", + "packageUri": "lib/", + "languageVersion": "2.17" + }, + { + "name": "shelf_packages_handler", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/shelf_packages_handler-3.0.1", + "packageUri": "lib/", + "languageVersion": "2.14" + }, + { + "name": "shelf_static", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/shelf_static-1.1.1", + "packageUri": "lib/", + "languageVersion": "2.14" + }, + { + "name": "shelf_web_socket", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-1.0.3", + "packageUri": "lib/", + "languageVersion": "2.17" + }, + { + "name": "source_map_stack_trace", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-2.1.1", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "source_maps", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.10", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "source_span", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/source_span-1.9.1", + "packageUri": "lib/", + "languageVersion": "2.14" + }, + { + "name": "stack_trace", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "stream_channel", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.1", + "packageUri": "lib/", + "languageVersion": "2.14" + }, + { + "name": "string_scanner", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.1", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "term_glyph", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.1", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "test", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/test-1.21.4", + "packageUri": "lib/", + "languageVersion": "2.14" + }, + { + "name": "test_api", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/test_api-0.4.12", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "test_core", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/test_core-0.4.16", + "packageUri": "lib/", + "languageVersion": "2.14" + }, + { + "name": "typed_data", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.1", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "vm_service", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/vm_service-9.4.0", + "packageUri": "lib/", + "languageVersion": "2.15" + }, + { + "name": "watcher", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/watcher-1.0.2", + "packageUri": "lib/", + "languageVersion": "2.14" + }, + { + "name": "web_socket_channel", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-2.3.0", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "webkit_inspection_protocol", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/webkit_inspection_protocol-1.2.0", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "yaml", + "rootUri": "file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/yaml-3.1.1", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "design_system_insets", + "rootUri": "../", + "packageUri": "lib/", + "languageVersion": "2.17" + } + ], + "generated": "2023-01-21T18:56:20.527973Z", + "generator": "pub", + "generatorVersion": "2.17.6" +} diff --git a/website/sidecar/lib/src/tutorials/design_system_insets/.packages b/website/sidecar/lib/src/tutorials/design_system_insets/.packages new file mode 100644 index 00000000..21ff0d48 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/design_system_insets/.packages @@ -0,0 +1,53 @@ +# This file is deprecated. Tools should instead consume +# `.dart_tool/package_config.json`. +# +# For more info see: https://dart.dev/go/dot-packages-deprecation +# +# Generated by pub on 2023-01-21 13:56:20.522121. +_fe_analyzer_shared:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-47.0.0/lib/ +analyzer:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/analyzer-4.7.0/lib/ +args:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/args-2.3.1/lib/ +async:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/async-2.9.0/lib/ +boolean_selector:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.1/lib/ +collection:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/collection-1.17.0/lib/ +convert:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/convert-3.1.0/lib/ +coverage:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/coverage-1.6.2/lib/ +crypto:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.2/lib/ +file:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/file-6.1.4/lib/ +frontend_server_client:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/frontend_server_client-2.1.3/lib/ +glob:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/glob-2.1.1/lib/ +http_multi_server:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/http_multi_server-3.2.1/lib/ +http_parser:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/http_parser-4.0.2/lib/ +io:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/io-1.0.4/lib/ +js:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/js-0.6.5/lib/ +lints:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/lints-2.0.1/lib/ +logging:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/logging-1.1.0/lib/ +matcher:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.12/lib/ +meta:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/meta-1.8.0/lib/ +mime:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/mime-1.0.3/lib/ +node_preamble:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/node_preamble-2.0.1/lib/ +package_config:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/package_config-2.1.0/lib/ +path:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/path-1.8.3/lib/ +pool:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/pool-1.5.1/lib/ +pub_semver:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/pub_semver-2.1.3/lib/ +shelf:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/shelf-1.4.0/lib/ +shelf_packages_handler:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/shelf_packages_handler-3.0.1/lib/ +shelf_static:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/shelf_static-1.1.1/lib/ +shelf_web_socket:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-1.0.3/lib/ +source_map_stack_trace:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-2.1.1/lib/ +source_maps:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.10/lib/ +source_span:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/source_span-1.9.1/lib/ +stack_trace:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0/lib/ +stream_channel:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.1/lib/ +string_scanner:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.1/lib/ +term_glyph:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.1/lib/ +test:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/test-1.21.4/lib/ +test_api:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/test_api-0.4.12/lib/ +test_core:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/test_core-0.4.16/lib/ +typed_data:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.1/lib/ +vm_service:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/vm_service-9.4.0/lib/ +watcher:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/watcher-1.0.2/lib/ +web_socket_channel:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-2.3.0/lib/ +webkit_inspection_protocol:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/webkit_inspection_protocol-1.2.0/lib/ +yaml:file:///Users/pattobrien/.pub-cache/hosted/pub.dartlang.org/yaml-3.1.1/lib/ +design_system_insets:lib/ diff --git a/website/sidecar/lib/src/tutorials/design_system_insets/analysis_options.yaml b/website/sidecar/lib/src/tutorials/design_system_insets/analysis_options.yaml deleted file mode 100644 index dee8927a..00000000 --- a/website/sidecar/lib/src/tutorials/design_system_insets/analysis_options.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# This file configures the static analysis results for your project (errors, -# warnings, and lints). -# -# This enables the 'recommended' set of lints from `package:lints`. -# This set helps identify many issues that may lead to problems when running -# or consuming Dart code, and enforces writing Dart using a single, idiomatic -# style and format. -# -# If you want a smaller set of lints you can change this to specify -# 'package:lints/core.yaml'. These are just the most critical lints -# (the recommended set includes the core lints). -# The core lints are also what is used by pub.dev for scoring packages. - -include: package:lints/recommended.yaml - -# Uncomment the following section to specify additional rules. - -# linter: -# rules: -# - camel_case_types - -# analyzer: -# exclude: -# - path/to/excluded/files/** - -# For more information about the core and recommended set of lints, see -# https://dart.dev/go/core-lints - -# For additional information about configuring this file, see -# https://dart.dev/guides/language/analysis-options diff --git a/website/sidecar/lib/src/tutorials/design_system_insets/bin/design_system_insets.dart b/website/sidecar/lib/src/tutorials/design_system_insets/bin/design_system_insets.dart deleted file mode 100644 index 842b0044..00000000 --- a/website/sidecar/lib/src/tutorials/design_system_insets/bin/design_system_insets.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:design_system_insets/design_system_insets.dart' as design_system_insets; - -void main(List arguments) { - print('Hello world: ${design_system_insets.calculate()}!'); -} diff --git a/website/sidecar/lib/src/tutorials/design_system_insets/lib/design_system_insets.dart b/website/sidecar/lib/src/tutorials/design_system_insets/lib/design_system_insets.dart deleted file mode 100644 index f64ad726..00000000 --- a/website/sidecar/lib/src/tutorials/design_system_insets/lib/design_system_insets.dart +++ /dev/null @@ -1,3 +0,0 @@ -int calculate() { - return 6 * 7; -} diff --git a/website/sidecar/lib/src/tutorials/design_system_insets/test/design_system_insets_test.dart b/website/sidecar/lib/src/tutorials/design_system_insets/test/design_system_insets_test.dart deleted file mode 100644 index e7e5113a..00000000 --- a/website/sidecar/lib/src/tutorials/design_system_insets/test/design_system_insets_test.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:design_system_insets/design_system_insets.dart'; -import 'package:test/test.dart'; - -void main() { - test('calculate', () { - expect(calculate(), 42); - }); -} diff --git a/website/sidecar/lib/src/tutorials/hello_world/.gitignore b/website/sidecar/lib/src/tutorials/hello_world/.gitignore new file mode 100644 index 00000000..3c8a1572 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/hello_world/.gitignore @@ -0,0 +1,6 @@ +# Files and directories created by pub. +.dart_tool/ +.packages + +# Conventional directory for build output. +build/ diff --git a/website/sidecar/lib/src/tutorials/hello_world/README.md b/website/sidecar/lib/src/tutorials/hello_world/README.md new file mode 100644 index 00000000..3816eca3 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/hello_world/README.md @@ -0,0 +1,2 @@ +A sample command-line application with an entrypoint in `bin/`, library code +in `lib/`, and example unit test in `test/`. diff --git a/website/sidecar/lib/src/tutorials/hello_world/analysis_options.yaml b/website/sidecar/lib/src/tutorials/hello_world/analysis_options.yaml new file mode 100644 index 00000000..e69de29b diff --git a/website/sidecar/lib/src/tutorials/hello_world/lib/step0.dart b/website/sidecar/lib/src/tutorials/hello_world/lib/step0.dart new file mode 100644 index 00000000..4c2baf21 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/hello_world/lib/step0.dart @@ -0,0 +1,16 @@ +/* SNIPPET START */ +import 'package:sidecar/sidecar.dart'; + +class HelloWorld extends LintRule { + @override + LintCode get code => + const LintCode('hello_world', package: 'hello_world_rules'); + /* SKIP */ + + @override + void initializeVisitor(NodeRegistry registry) { + // TODO: implement initializeVisitor + } + /* SKIP END */ +} +/* SNIPPET END */ \ No newline at end of file diff --git a/website/sidecar/lib/src/tutorials/hello_world/lib/step1.dart b/website/sidecar/lib/src/tutorials/hello_world/lib/step1.dart new file mode 100644 index 00000000..27b7e3f2 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/hello_world/lib/step1.dart @@ -0,0 +1,22 @@ +/* SNIPPET START */ +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:sidecar/sidecar.dart'; + +class HelloWorld extends LintRule { + @override + void visitSimpleStringLiteral(SimpleStringLiteral node) { + // TODO: implement visitSimpleStringLiteral + super.visitSimpleStringLiteral(node); + } /* SKIP */ + + @override + // TODO: implement code + LintCode get code => throw UnimplementedError(); + + @override + void initializeVisitor(NodeRegistry registry) { + // TODO: implement initializeVisitor + } + /* SKIP END */ +} +/* SNIPPET END */ \ No newline at end of file diff --git a/website/sidecar/lib/src/tutorials/hello_world/lib/step2.dart b/website/sidecar/lib/src/tutorials/hello_world/lib/step2.dart new file mode 100644 index 00000000..937fb97c --- /dev/null +++ b/website/sidecar/lib/src/tutorials/hello_world/lib/step2.dart @@ -0,0 +1,24 @@ +/* SNIPPET START */ +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:sidecar/sidecar.dart'; + +class HelloWorld extends LintRule { + @override + void visitSimpleStringLiteral(SimpleStringLiteral node) { + final stringValue = node.value; + if (stringValue == 'Is there anybody there?') { + reportAstNode(node, message: 'Hello world!'); + } + } /* SKIP */ + + @override + // TODO: implement code + LintCode get code => throw UnimplementedError(); + + @override + void initializeVisitor(NodeRegistry registry) { + // TODO: implement initializeVisitor + } + /* SKIP END */ +} +/* SNIPPET END */ \ No newline at end of file diff --git a/website/sidecar/lib/src/tutorials/hello_world/lib/step3.dart b/website/sidecar/lib/src/tutorials/hello_world/lib/step3.dart new file mode 100644 index 00000000..24410ce6 --- /dev/null +++ b/website/sidecar/lib/src/tutorials/hello_world/lib/step3.dart @@ -0,0 +1,22 @@ +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:sidecar/sidecar.dart'; + +class HelloWorld extends LintRule { + @override + LintCode get code => + const LintCode('hello_world', package: 'hello_world_rules'); + + @override + void initializeVisitor(NodeRegistry registry) { + registry.addSimpleStringLiteral(this); + } + + @override + void visitSimpleStringLiteral(SimpleStringLiteral node) { + final stringValue = node.value; + if (stringValue == 'Is there anybody there?') { + reportAstNode(node, message: 'Hello world!'); + } + super.visitSimpleStringLiteral(node); + } +} diff --git a/website/sidecar/lib/src/tutorials/design_system_insets/pubspec.yaml b/website/sidecar/lib/src/tutorials/hello_world/pubspec.yaml similarity index 52% rename from website/sidecar/lib/src/tutorials/design_system_insets/pubspec.yaml rename to website/sidecar/lib/src/tutorials/hello_world/pubspec.yaml index f847bc9b..dfac75af 100644 --- a/website/sidecar/lib/src/tutorials/design_system_insets/pubspec.yaml +++ b/website/sidecar/lib/src/tutorials/hello_world/pubspec.yaml @@ -1,13 +1,16 @@ -name: design_system_insets +name: hello_world description: A sample command-line application. version: 1.0.0 +publish_to: none # homepage: https://www.example.com environment: - sdk: '>=2.17.6 <3.0.0' + sdk: ">=2.17.6 <3.0.0" -# dependencies: -# path: ^1.8.0 +dependencies: + analyzer: ^4.7.0 + sidecar: + path: ../../../../../../packages/sidecar/ dev_dependencies: lints: ^2.0.0 diff --git a/website/sidecar/pubspec.yaml b/website/sidecar/pubspec.yaml index d64c97ae..d4f2e1a4 100644 --- a/website/sidecar/pubspec.yaml +++ b/website/sidecar/pubspec.yaml @@ -11,18 +11,20 @@ environment: dependencies: analyzer: ^4.2.0 + design_system_lints: ^0.1.0-dev.11 freezed_annotation: ^2.1.0 # non-dart official package glob: ^2.1.0 json_annotation: ^4.6.0 meta: ^1.7.0 path: ^1.8.1 pub_semver: ^2.1.1 - sidecar: - path: ../../packages/sidecar/ + # sidecar: + # path: ../../packages/sidecar/ # sidecar_annotations: # path: ../../packages/sidecar_annotations/ # sidecar_package_utilities: # path: ../../packages/sidecar_package_utilities/ + sidecar: ^0.1.0-dev.21 source_span: ^1.8.0 test: ^1.16.0 diff --git a/website/sidecar/src/components/CodeSnippet/index.tsx b/website/sidecar/src/components/CodeSnippet/index.tsx index 6dc20239..d9683643 100644 --- a/website/sidecar/src/components/CodeSnippet/index.tsx +++ b/website/sidecar/src/components/CodeSnippet/index.tsx @@ -6,6 +6,48 @@ const SKIP_END = "/* SKIP END */"; const START_AT = "/* SNIPPET START */"; const END_AT = "/* SNIPPET END */"; +const SNIPPET_START = "/* SNIPPET START */"; +const SNIPPET_END = "/* SNIPPET END */"; + +// create a regexp that finds the text in between /* SNIP FOO */ and /* SNIP FOO END */; +// but not including the /* SNIP FOO */ and /* SNIP FOO END */ lines +const SNIP_CONTENT_REGEXP = /\/\* SNIP (\w+) \*\/([\s\S]*?)\/\* SNIP \1 END \*\//g + +// a regexp that finds all text thats not in between /* SKIP FOO */ and /* SKIP FOO END */; +// but not including the /* SKIP FOO */ and /* SKIP FOO END */ lines +const SKIP_CONTENT_REGEXP = /(?:\/\* SKIP \w+ \*\/[\s\S]*?\/\* SKIP \w+ END \*\/)|(?:[\s\S]*?)/g + + +export function generateSnippet(contents: string, snippets: string[]): string { + let matches: RegExpExecArray | null; + let matchedString = ''; + while ((matches = SNIP_CONTENT_REGEXP.exec(contents)) !== null) { + console.log(matches[1]); + if (snippets.includes(matches[1])) { + matchedString += matches[2] + ' '; + } + } + return matchedString; +} + + +// export function generateSnippet(contents: string, snippets: Array): string { +// const startAtIndex = contents.indexOf(START_AT); +// if (startAtIndex < 0) return contents; + +// let endAtIndex = contents.indexOf(END_AT); +// if (endAtIndex < 0) endAtIndex = undefined; + +// contents = contents +// .substring(startAtIndex + START_AT.length, endAtIndex) +// .trim(); + +// return contents.replace( +// /\n?(?:\/\* SNIP \*\/)(?:\n|.)+(?:\/\* SKIP END \*\/)/, +// "" +// ); +// } + export function trimSnippet(snippet: string): string { const startAtIndex = snippet.indexOf(START_AT); if (startAtIndex < 0) return snippet; diff --git a/website/sidecar/src/components/HomepageFeatures/index.tsx b/website/sidecar/src/components/HomepageFeatures/index.tsx index 07a73bb8..015113e9 100644 --- a/website/sidecar/src/components/HomepageFeatures/index.tsx +++ b/website/sidecar/src/components/HomepageFeatures/index.tsx @@ -11,31 +11,29 @@ type FeatureItem = { const FeatureList: FeatureItem[] = [ { title: 'Easy to Use', - Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, + Svg: require('@site/static/img/undraw_mobile_development.svg').default, description: ( <> - Docusaurus was designed from the ground up to be easily installed and - used to get your website up and running quickly. + Use custom lints and quick fixes just as easily as those included in the official Dart linter package. ), }, { - title: 'Focus on What Matters', - Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, + title: 'Customize Your DevX', + Svg: require('@site/static/img/undraw_development.svg').default, description: ( <> - Docusaurus lets you focus on your docs, and we'll do the chores. Go - ahead and move your docs into the docs directory. + Enforce rules that are perfectly tailored to your package or application. ), }, { - title: 'Powered by React', - Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, + title: 'Powered by Dart', + Svg: require('@site/static/img/undraw_computer_dart_flutter.svg').default, description: ( <> - Extend or customize your website layout by reusing React. Docusaurus can - be extended while reusing the same header and footer. + Sidecar was built around Dart and Flutter, so you can expect the same level of performance + as the native Dart SDK toolchain. ), }, diff --git a/website/sidecar/src/css/custom.scss b/website/sidecar/src/css/custom.scss index 2bc6a4cf..22dd425b 100644 --- a/website/sidecar/src/css/custom.scss +++ b/website/sidecar/src/css/custom.scss @@ -6,7 +6,7 @@ /* You can override the default Infima variables here. */ :root { - --ifm-color-primary: #2e8555; + --ifm-color-primary: #0175C2; --ifm-color-primary-dark: #29784c; --ifm-color-primary-darker: #277148; --ifm-color-primary-darkest: #205d3b; @@ -19,7 +19,7 @@ /* For readability concerns, you should choose a lighter palette in dark mode. */ [data-theme='dark'] { - --ifm-color-primary: #25c2a0; + --ifm-color-primary: #13B9FD; --ifm-color-primary-dark: #21af90; --ifm-color-primary-darker: #1fa588; --ifm-color-primary-darkest: #1a8870; @@ -27,4 +27,4 @@ --ifm-color-primary-lighter: #32d8b4; --ifm-color-primary-lightest: #4fddbf; --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); -} +} \ No newline at end of file diff --git a/website/sidecar/src/pages/index.tsx b/website/sidecar/src/pages/index.tsx index 305139fb..4195ff6a 100644 --- a/website/sidecar/src/pages/index.tsx +++ b/website/sidecar/src/pages/index.tsx @@ -8,7 +8,7 @@ import HomepageFeatures from '@site/src/components/HomepageFeatures'; import styles from './index.module.css'; function HomepageHeader() { - const {siteConfig} = useDocusaurusContext(); + const { siteConfig } = useDocusaurusContext(); return (
@@ -18,7 +18,7 @@ function HomepageHeader() { - Docusaurus Tutorial - 5min ⏱️ + Get Started
@@ -27,10 +27,10 @@ function HomepageHeader() { } export default function Home(): JSX.Element { - const {siteConfig} = useDocusaurusContext(); + const { siteConfig } = useDocusaurusContext(); return (
diff --git a/website/sidecar/static/img/cli_output.png b/website/sidecar/static/img/cli_output.png new file mode 100644 index 00000000..077e795c Binary files /dev/null and b/website/sidecar/static/img/cli_output.png differ diff --git a/website/sidecar/static/img/undraw_computer_dart_flutter.svg b/website/sidecar/static/img/undraw_computer_dart_flutter.svg new file mode 100644 index 00000000..10cc8d95 --- /dev/null +++ b/website/sidecar/static/img/undraw_computer_dart_flutter.svg @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/sidecar/static/img/undraw_development.svg b/website/sidecar/static/img/undraw_development.svg new file mode 100644 index 00000000..82e168c8 --- /dev/null +++ b/website/sidecar/static/img/undraw_development.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/sidecar/static/img/undraw_mobile_development.svg b/website/sidecar/static/img/undraw_mobile_development.svg new file mode 100644 index 00000000..5a823c11 --- /dev/null +++ b/website/sidecar/static/img/undraw_mobile_development.svg @@ -0,0 +1 @@ + \ No newline at end of file