feat: v3.0 for typeset (breaking) - #67
Open
rohanjsh wants to merge 12 commits into
Open
Conversation
Updates the package to version 3.0.0-beta.1, introducing a breaking release focused on parser/renderer architecture, configuration standardization, and safer AutoLink controls. The update includes: - Introduction of new configuration options such as `TypeSetConfig`, `TypeSetStyle`, and `TypeSetAutoLinkConfig` - Restructuring of the `TypeSet` and `TypeSetEditingController` to utilize the new configuration model - Changes to the underline delimiter syntax from `#text#` to `__text__` - Removal of legacy parser/controller internals and style parameters - Updates the README and CONTRIBUTING files with comprehensive documentation and contribution guidelines - Adds a migration guide to facilitate upgrading from v2.x to v3.0.0
Introduces a new parser and renderer for handling rich text formatting. The parser converts marked-up text into an abstract syntax tree (AST), supporting styles like bold, italic, underline, and strikethrough, as well as code blocks and autolinking of URLs. The renderer then transforms this AST into Flutter's InlineSpan objects for display. Also introduces a config provider to customize text rendering.
Adds AST node definitions for text, code, links, and styled spans to represent the parsed structure. Introduces configuration models for global settings, autolinking, and text styles, providing flexibility in customizing the typesetting behavior. Removes the previous style enum and value model in favor of the new configuration approach.
This commit introduces a new `TypeSet` widget that leverages a configuration object for styling and autolinking, providing greater flexibility and customization. It deprecates the old implementation by removing the old files, and introduces new ones. The new implementation utilizes `Text.rich` and introduces a `TypeSetEditingController` for applying formatting to editable text fields, enhancing the user experience when creating and modifying formatted text. Context menus are also added to easily style text.
There was a problem hiding this comment.
Pull request overview
Prepares TypeSet for the v3.0.0 (breaking) release by replacing the legacy span-based parser/controller with an AST parse → AutoLink → render pipeline and introducing centralized configuration APIs for rendering, editing, and link behavior.
Changes:
- Introduces
TypeSetConfig/TypeSetStyle/TypeSetAutoLinkConfig, plus scoped/global config mechanisms. - Replaces legacy parsing/rendering internals with new AST nodes, parser, AutoLink pass, and renderer.
- Updates example app, tests, and documentation (README/migration/changelog/contributing), and removes
url_launcherintegration.
Reviewed changes
Copilot reviewed 48 out of 49 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| test/src/view/typeset_widget.dart | Updates test demo widget usage to pass TypeSetConfig (AutoLink recognizer via config). |
| test/src/view/typeset_test.dart | Removes legacy TypesetParser tests; keeps widget smoke tests. |
| test/src/view/typeset_editing_controller_test.dart | Updates editing controller tests for new delimiter behavior and AutoLink rendering expectations. |
| test/src/view/typeset_context_menus_test.dart | Updates context menu test expectations (underline delimiter change; link option removed). |
| test/src/models/style_type_value_model_test.dart | Removes tests for deleted legacy model. |
| test/src/core/typeset_reserved_test.dart | Updates reserved delimiter expectations (escape/backslash, underline __, sets). |
| test/src/core/typeset_renderer_test.dart | Adds renderer + widget integration tests for new pipeline. |
| test/src/core/typeset_parser_test.dart | Rewrites parser tests for AST output and AutoLink behavior. |
| test/src/core/typeset_controller_test.dart | Removes tests for deleted legacy controller. |
| pubspec.yaml | Bumps to 3.0.0-beta.1, updates metadata, removes url_launcher. |
| lib/typeset.dart | Updates public exports to new config + reserved/style APIs. |
| lib/src/view/typeset_ext.dart | Switches string extension API to accept TypeSetConfig instead of per-style params. |
| lib/src/view/typeset_editing_controller.dart | Replaces inline parsing with AST parse + renderer (show delimiters) and config resolution. |
| lib/src/view/typeset_context_menus.dart | Reworks context menu styles and wrapping logic; removes link menu option. |
| lib/src/view/typeset.dart | Replaces legacy parser usage with AST parser + renderer and config resolution. |
| lib/src/models/typeset_style.dart | Adds centralized style configuration model. |
| lib/src/models/typeset_reserved.dart | Adds new reserved delimiter constants (underline __, escape \). |
| lib/src/models/typeset_global_config.dart | Adds global singleton config holder (test reset supported). |
| lib/src/models/typeset_config.dart | Adds central config object + defaults factory. |
| lib/src/models/typeset_autolink_config.dart | Adds AutoLink policy (schemes/domains/validator/recognizer builder). |
| lib/src/models/style_type_value_model.dart | Removes legacy model. |
| lib/src/models/style_type_enum.dart | Removes legacy enum. |
| lib/src/models/ast/typeset_nodes.dart | Adds AST node model (text/code/style/link nodes). |
| lib/src/core/typeset_reserved.dart | Removes legacy reserved constants (including link markers/font-size regex). |
| lib/src/core/typeset_parser.dart | Removes legacy TextSpan parser implementation (and url_launcher integration). |
| lib/src/core/typeset_controller.dart | Removes legacy controller-based manipulation pipeline. |
| lib/src/core/typeset_config_provider.dart | Adds inherited widget for subtree-scoped config. |
| lib/src/core/renderer/typeset_renderer.dart | Adds AST → InlineSpan renderer with delimiter-visibility support. |
| lib/src/core/parser/typeset_parser.dart | Adds new inline parser producing AST and optional AutoLink post-pass. |
| lib/src/core/parser/typeset_autolink_pass.dart | Adds AutoLink transformation pass over AST. |
| example/windows/flutter/generated_plugins.cmake | Removes url_launcher plugin registration. |
| example/windows/flutter/generated_plugin_registrant.cc | Removes url_launcher plugin registration. |
| example/macos/Flutter/GeneratedPluginRegistrant.swift | Removes url_launcher plugin registration. |
| example/linux/flutter/generated_plugins.cmake | Removes url_launcher plugin registration. |
| example/linux/flutter/generated_plugin_registrant.cc | Removes url_launcher plugin registration. |
| example/lib/main.dart | Reworks example UI and demonstrates config + scoped editing/preview flow. |
| example/ios/Runner/Info.plist | Reorders/adds keys (scene manifest/indirect input events). |
| example/ios/Runner/AppDelegate.swift | Updates plugin registration to implicit engine delegate path. |
| example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme | Adds custom LLDB init file. |
| example/ios/Runner.xcodeproj/project.pbxproj | Updates iOS deployment target to 13.0 and removes embed pods frameworks phase. |
| example/ios/Podfile.lock | Updates lockfile to remove url_launcher iOS pod. |
| example/ios/Podfile | Updates commented platform version to 13.0. |
| example/ios/Flutter/AppFrameworkInfo.plist | Removes MinimumOSVersion entry. |
| doc/UNDER_THE_HOOD.md | Adds detailed explanation of the new pipeline and config precedence. |
| README.md | Rewrites docs for v3 config model, new syntax, and migration links. |
| MIGRATION.md | Adds 2.x → 3.0.0 migration guide for breaking API/syntax changes. |
| CONTRIBUTING.md | Adds contribution and release workflow guidance. |
| CHANGELOG.md | Adds 3.0.0-beta.1 changelog entry and restructures historical entries. |
| .pubignore | Adds publish ignore list for legacy files and artifacts. |
Comments suppressed due to low confidence (8)
lib/src/models/typeset_autolink_config.dart:70
TypeSetAutoLinkConfig.operator==comparesallowedSchemeswith==, butSetequality in Dart is identity-based. Two configs with the same scheme values but different set instances will compare as unequal, which affectsupdateShouldNotifyand any equality-based logic. Consider using deep set equality (e.g.,allowedSchemes.length == other.allowedSchemes.length && allowedSchemes.containsAll(other.allowedSchemes)) and aligninghashCodeaccordingly.
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is TypeSetAutoLinkConfig &&
runtimeType == other.runtimeType &&
allowedSchemes == other.allowedSchemes &&
allowedDomains == other.allowedDomains &&
customValidator == other.customValidator &&
linkRecognizerBuilder == other.linkRecognizerBuilder;
@override
int get hashCode =>
allowedSchemes.hashCode ^
allowedDomains.hashCode ^
customValidator.hashCode ^
linkRecognizerBuilder.hashCode;
lib/src/view/typeset_context_menus.dart:58
- The “already styled” guard returns early whenever the selected text starts and ends with a delimiter. This incorrectly treats selections that are only delimiters (e.g. selecting
_or__) as already-styled text, preventing formatting actions even though there’s no wrapped content. Consider requiringselectionText.length > delimiter.length * 2(or at least>= delimiter.length * 2 + 1) before treating it as styled.
.pubignore:38 - Several ignore patterns look unintended:
_.iml,_.ipr,_.log,_.pycwon’t match typical filenames (likely meant*.iml,*.ipr,*.log,*.pyc). Also the escaped patterns like\*.iws/\*.swpmatch a literal*in gitignore-style syntax rather than acting as a wildcard. Consider switching to standard wildcard patterns so these files are actually excluded fromdart pub publish.
# IDE/editor metadata
.idea/
.vscode/
_.iml
_.ipr
\*.iws
# Misc local artifacts
.DS_Store
_.log
_.pyc
\*.swp
README.md:6
- The build status badge links to the issues page rather than the GitHub Actions workflow runs, so users clicking it won’t reach the build results. Consider updating the link target to the workflow (e.g.,
/actions/workflows/main.yaml) or the Actions page.
[](https://pub.dev/packages/typeset)
[](https://pub.dev/packages/very_good_analysis)
[](https://github.com/rohanjsh/typeset/issues)
lib/src/view/typeset.dart:97
TypeSetConfigdocs sayautoLinkConfig: nullmeans “use scoped or global defaults”, buteffectiveConfig = config ?? scopedConfig ?? TypeSetGlobalConfig.instancetreats a partially-specified localconfigas overriding the entire config. This makes it impossible to override onlystylewhile inheriting AutoLink policy (and vice versa), and it diverges from the documented precedence behavior. Consider resolving an effective config by layering/merging (global defaults → provider → local), filling null fields from the next fallback rather than replacing the whole object.
lib/src/view/typeset_editing_controller.dart:65TypeSetConfigis documented as allowing null fields to fall back to scoped/global defaults, buteffectiveConfig = config ?? scopedConfig ?? TypeSetGlobalConfig.instancedoesn't merge fields. A localconfigthat only setsstylewill silently drop any scoped/globalautoLinkConfig(and vice versa). Consider composing the effective config by merging non-null fields from (global → provider → local) instead of picking a single object.
lib/src/core/typeset_config_provider.dart:29TypeSetConfigProvider.maybeOfcurrently falls back toTypeSetConfig.defaults()and ignoresTypeSetGlobalConfig.instance. This is inconsistent with the documented precedence (local → provider → global → defaults) and can surprise callers that expect global defaults to apply when no provider is in the tree. Consider either (a) includingTypeSetGlobalConfig.instancein the fallback chain, or (b) renaming/documentingmaybeOfto make it clear it bypasses global config.
/// Gets the configuration from the nearest ancestor provider.
static TypeSetConfig? of(BuildContext context) {
return context
.dependOnInheritedWidgetOfExactType<TypeSetConfigProvider>()
?.config;
}
/// Gets the configuration from the nearest ancestor provider, or the default.
static TypeSetConfig maybeOf(BuildContext context) {
return context
.dependOnInheritedWidgetOfExactType<TypeSetConfigProvider>()
?.config ??
TypeSetConfig.defaults();
}
lib/src/models/typeset_autolink_config.dart:18
TypeSetAutoLinkConfig.allowedSchemesis a mutableSet<String>but the class is marked@immutable. As written, callers can mutate the set after constructing the config, changing behavior at runtime and making equality/hashCode unreliable. Consider defensively copying to an unmodifiable set in the constructor/copyWith (e.g.,Set.unmodifiable(...)) and documenting that the input set must not be mutated.
const TypeSetAutoLinkConfig({
this.allowedSchemes = const {'http', 'https'},
this.allowedDomains,
this.customValidator,
this.linkRecognizerBuilder,
});
/// Allowed URL schemes (default: http, https). Empty set disables autolink.
final Set<String> allowedSchemes;
/// Optional regex pattern for domain allowlisting.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This was referenced Feb 24, 2026
Introduces a compiled document model and cache to optimize rendering performance across the library. This update adds a runtime session for managing gesture recognizer lifecycles and implements hierarchical configuration resolution across theme, global, scoped, and local layers. The editing controller is enhanced with safety guards for large text and improved composing range support, while the parser receives refinements for autolink boundaries and balanced closing delimiters.
Rewrites the README, Migration Guide, and Under the Hood documentation for improved clarity and detail. Optimizes the parser and autolink pass to use index-based scanning and text runs, significantly reducing string allocations during document compilation. Updates the minimum Flutter SDK requirement to 3.10.0 and bumps the package version.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Status
IN DEVELOPMENT
Description
This pull request prepares for the 3.0.0 release of TypeSet, introducing a major overhaul to its configuration, parser/renderer architecture, and documentation. The update emphasizes a new centralized configuration API, breaking changes to syntax and widget/controller parameters, and improved documentation for migration and contribution. Below are the most important changes:
Major API and Architecture Changes
TypeSetConfig,TypeSetStyle, andTypeSetAutoLinkConfigfor centralized and safer widget/controller configuration; parser and renderer are now structured as an AST pipeline. (CHANGELOG.mdCHANGELOG.mdL1-R180)CHANGELOG.mdCHANGELOG.mdL1-R180)Breaking Changes and Migration
#text#to__text__; removed several constructor parameters fromTypeSetandTypeSetEditingController; removedStyleTypeEnum.linkfrom context menus. (CHANGELOG.md[1]MIGRATION.md[2]MIGRATION.mdMIGRATION.mdR1-R121)Documentation and Project Maintenance
README.mdto reflect the new configuration model, usage, and migration steps; added references to new documentation files. (README.mdREADME.mdL1-R185)CONTRIBUTING.mdfile with clear guidelines for development, pull requests, and the release process. (CONTRIBUTING.mdCONTRIBUTING.mdR1-R58).pubignorefile to exclude legacy files, build artifacts, and IDE/editor metadata from package publishing. (.pubignore.pubignoreR1-R38)Type of Change