Skip to content

Allow partial application of input - #762

Merged
drwpow merged 5 commits into
terrazzoapp:mainfrom
mrginglymus:allow-partial-apply
Jul 1, 2026
Merged

drwpow merged 5 commits into
terrazzoapp:mainfrom
mrginglymus:allow-partial-apply

Conversation

@mrginglymus

@mrginglymus mrginglymus commented May 19, 2026 •

Copy link
Copy Markdown
Contributor

Changes

  • add resolveAliases option to Resolver#apply API
  • ensure inline aliasing step respects resolveAlias

Why?

This now allows you to do:

const tokens = resolver.apply({}, { sets: ['a-set'], modifiers: [], resolveAliases: false });

and the result will contain only tokens declared in a-set. The same is possible for modifiers.

This is of great benefit when writing plugins that need to output only the tokens declared in a given set/modifier (e.g., in the case of a css class per context per modifier).

@changeset-bot

changeset-bot Bot commented May 19, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a57d858

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@terrazzo/parser Minor
@terrazzo/plugin-css-in-js Major
@terrazzo/plugin-css Major
@terrazzo/plugin-js Major
@terrazzo/plugin-sass Major
@terrazzo/plugin-swift Major
@terrazzo/plugin-tailwind Major
@terrazzo/plugin-token-listing Major
@terrazzo/plugin-vanilla-extract Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@mrginglymus
mrginglymus force-pushed the allow-partial-apply branch from 6c59968 to bf13511 Compare May 19, 2026 14:42
@mrginglymus

Copy link
Copy Markdown
Contributor Author

(obviously will add tests if the general principle is approved)

@drwpow

drwpow commented May 19, 2026

Copy link
Copy Markdown
Collaborator

Yup I’m on board with this! I think it’s the user’s choice to want to only act on a subset of a resolver, the resolver design isn’t dependent on it being irreducible at every level. To me this is the same as simply deleting part of the document anyway, which should be the author’s choice to do so.

@mrginglymus

Copy link
Copy Markdown
Contributor Author

Added a couple of simple tests. I've added my go-to blue-orange/light-dark resolver for testing more intricate usage.

@mrginglymus

Copy link
Copy Markdown
Contributor Author

One limitation of this is that it still wont work if you have an $extends that references a token not in the current set of files.

However, solving this would probably require something a bit more sophisticated implementation wise, whereby the root document is created from merging all sources, but recording in which source each token was declared. Then, at token resolution time, only resolving tokens that come from sources on the allow list.

Comment thread packages/parser/test/resolver.test.ts Outdated
});

describe('partial application', () => {
let resolver: Resolver;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a general rule we should try to not share state between tests. It’s a really hard mistake to undo when tests now have to execute in a certain order otherwise the entire suite breaks. Even if this is “safe” as-written, it only takes one modification or two here (likely by another author that doesn’t understand) the suite is poisoned with state contamination.

Instead, let’s move this to a pure loadResolver() helper that’s called within each test. Then each test sets up what it needs, and doesn’t affect other tests, and we still are DRY without sharing state.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just miss fixtures from pytest...will update :)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I didn’t realize it came from Python! Yeah I’ve just spent almost 10 years untangling leaky state from large test suites 🙃. Even in a smaller project like this library, it still turns into a real timesink when it breaks, unfortunately (especially because JS test runners like Vitest operate using a lot more magic than one might think)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/wildly off topic

pytest has a full dependency injection framework, so you never need to use an explicit beforeEach but instead you'd do something like:

@fixture
def resolver():
  # parse your resolver here
  return resolver

@test
def test_resolver(resolver):
  # resolver fixture injected by name
  assert resolver

happy days. The fixtures can have different scopes to share resources (and save processing time), cleanups that will run even if tests fail. Oh, and it uses native python assertions with some horrific byteweaving to add in rich failure messages.

@mrginglymus
mrginglymus force-pushed the allow-partial-apply branch from e779eed to c4b8459 Compare June 8, 2026 09:51
@mrginglymus
mrginglymus requested a review from drwpow June 8, 2026 09:58
@drwpow

drwpow commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

One limitation of this is that it still wont work if you have an $extends that references a token not in the current set of files.

That’s fine for now IMO. The two flavors of that—DTCG alias and JSON Schema $ref—both are expected to err if the resolution fails, and resolution is up to the user to manage. If it doesn’t resolve with partial inputs, then I think that’s desirable behavior for it to err as if that token never existed in the first place.

Comment thread packages/parser/src/types.ts Outdated
export type ResolverApplicationOptions = {
sets?: string[];
modifiers?: string[];
resolveAliases?: boolean;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add this to the documentation for the JS API? I want to make sure I’m understanding when I want this to be true or false. A short section & example would be great if you can provide one!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@drwpow done - did some drive-by polishing of some adjacent dusty bits, but would welcome a redraft my redraft.

@mrginglymus
mrginglymus requested a review from drwpow June 10, 2026 10:23

@drwpow drwpow left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing, thank you for adding! Good with this merging, would you mind adding a minor changeset (see comment) so we can release it? Thanks!

const r = createResolver(resolver);

for (const input of r.inputPermutations) {
for (const input of r.listPermutations() ?? [{}]) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good catch, ty!

}
```

It’s up to you to specify all the permutations desired. `.getAllInputPermutations()` will return an array of all possible inputs for the specified modifiers.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦 Had quite a few old references to some early things that got renamed, I see. Thanks again

@mrginglymus
mrginglymus requested a review from drwpow June 13, 2026 09:12

@drwpow drwpow left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

@drwpow
drwpow merged commit a05196b into terrazzoapp:main Jul 1, 2026
4 checks passed
@github-actions github-actions Bot mentioned this pull request Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants