Skip to content

introduce a more fine-grained rewrite phase model#302

Merged
jenshalm merged 31 commits intomasterfrom
rewrite-phase
Jun 30, 2022
Merged

introduce a more fine-grained rewrite phase model#302
jenshalm merged 31 commits intomasterfrom
rewrite-phase

Conversation

@jenshalm
Copy link
Contributor

This refactoring addresses a long-standing issue where the internal AST rewriting that happens between parsing and rendering introduced chicken-and-egg scenarios that led to unexpected results for users in some edge cases. In the past there were always options to introduce workarounds when a related issue surfaced (like in #263). However, a new issue was reported recently (#289) where applying duct tape was no longer possible, and it was time for a bigger refactoring.

The key ideas that should solve the vast majority of related issues for users without the need for them to do anything or even understand the underlying topics were the following two:

  • Introduce a third rewrite phase in addition to the existing two. The phase model now consists of:

    • RewritePhase.Build the first phase run after parsing and the only phase where new link targets can be introduced safely.
    • RewritePhase.Resolve the second phase which is mostly reserved for internal use (e.g. running the link resolver).
    • RewritePhase.Render(OutputContext) the final phase run before rendering, which is specific to the selected output format and therefore parameterized. Rules and directives run in this phase get to see an "almost complete" AST. It is therefore the best place for extensions that produce navigation artefacts for example.
  • Adapt the default phases that user-defined rules and directives are run in. The default depends on how a rule or directive is constructed and primarily distinguishes between rules and directives that have access to a DocumentCursor and those that don't (the distinction is easy to make by the APIs that users call to create them).

    • If a rule or directive does not have access to a DocumentCursor it is impossible that it is used for tasks like generation of navigation structures and therefore it is run in the first phase by default. This means it is free to introduce new structure elements (even headers) itself.
    • If the rule or directive does have access to a DocumentCursor it is treated differently and run in the last phase by default. This way the extension gets to see an "almost complete" version of the AST which is the best phase for tasks like generating navigation. Issues like Headers created in custom directives disappear #289 existed as previously all rules and directives were run in this phase even when there clearly was no need to.

Fixes #289

jenshalm added 30 commits June 2, 2022 23:04
# Conflicts:
#	core/shared/src/main/scala/laika/api/builder/OperationConfig.scala
@jenshalm jenshalm added this to the 0.19.0 milestone Jun 23, 2022
@jenshalm jenshalm merged commit 0e623e2 into master Jun 30, 2022
@jenshalm jenshalm deleted the rewrite-phase branch July 3, 2022 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Headers created in custom directives disappear

1 participant