Skip to content

Tag-alias resolution is global at runtime — a framework's templates should resolve tags in their own context, not the application's #63

Description

@hugithordarson

Raised from work on the Parsley template editor and the tag-library format design.

The flaw

Parsley resolves tag shortcuts and element replacements against a single global registry (ParsleyTagRegistry — a static HashMap built once from every parsley-tag-aliases.properties on the flat app classpath, merged via ClassLoader.getResources(...)). The parser calls ParsleyTagRegistry.resolve(name) with no scope: the same global answer regardless of which template is being parsed.

Consequence: if a framework declares link = FrameworkLink and the consuming application declares link = AppLink, one wins globally at runtime — including for the framework's own templates, which were written and tested expecting FrameworkLink. A library's behavior silently changes based on what the app that consumes it happens to declare.

In the development environment this doesn't surface, because the editor resolves per-project (each project reads its own classpath's alias files). So the IDE and the runtime disagree — and worse, the runtime disagrees with itself across frameworks.

Conflicts are uncommon today, but this becomes more likely as reusable frameworks and custom-tag usage grow in the ecosystem. Worth getting the model right before the ecosystem grows into the flaw.

Important nuance: global-ness is sometimes the feature

The naive fix — "resolve each template in its declaring framework's context" — would break the mechanism that motivated aliases in the first place. WOString = ERXWOString is an element replacement: ERExtensions wants it applied everywhere, including inside other frameworks' templates. If frameworks only saw their own aliases, that global upgrade would stop working.

So the real axis is which aliases are global-by-intent vs scoped-by-intent, which maps onto two things currently unified as "just an alias":

  • Element replacements (WOString -> ERXWOString) — "upgrade this element everywhere." Global is correct.
  • Tag shortcuts / custom tags (link -> SomeComponent) — a naming convenience. Scoped is correct.

The conflict is a shortcut leaking across a boundary where a replacement's global semantics were assumed for both. A fix likely needs these to diverge along the scoping axis (even if they remain one file format).

Why this is an ng-objects concern, not a Parsley one

Parsley just resolves a name against whatever registry it's handed — scoping is not its job. The hard parts are all runtime-architecture:

  1. Template -> owning-framework attribution at parse time. Tractable: the parser knows the component; a component maps to a bundle/framework. But ng-objects currently has no bundleForClass / framework-attribution mechanism — this has to be built first.
  2. Per-framework alias views — the genuinely involved part. At runtime there is one flat classpath and one classloader (no OSGi-style per-bundle isolation), so "what does framework X see" is not recoverable from classloaders — the dependency graph isn't present at runtime. It must be declared: each library states its identity + dependencies, and the visibility graph is built from those declarations. This is a real subsystem, not a small patch.

Suggested direction (for when this is revisited)

  • Near-term / cheap: give each library a declared identity + explicit precedence in the alias format, so conflicts are declared and deterministic rather than a classpath-order accident (getResources order is explicitly unspecified). This is also the prerequisite for the real fix — those dependency declarations are what a visibility graph would be built from.
  • The real fix, later: per-framework resolution scope, built on those declarations, applied at parse time via component->bundle attribution, plus an explicit global-replacement vs scoped-shortcut distinction so ERXWOString-style replacements keep working.
  • Namespacing (<erx:link> vs <app:link>, JSP/JSF-style) is collision-proof by construction but taxes Parsley's clean <wo:link>/inline syntax — a fallback, not the primary direction.

This connects directly to the tag-library format precedence/scoping work (see the survey + deep-dive in the wolips proposals/ directory). Filing to revisit later; not blocking anything today.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions