Skip to content

Commit

Permalink
add scope by type node
Browse files Browse the repository at this point in the history
  • Loading branch information
mck committed Dec 12, 2024
1 parent 5729170 commit 6f239b9
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/thick-lemons-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tokens-studio/graph-engine-nodes-figma": patch
---

Add new node to add a variables scope by the token type.
4 changes: 3 additions & 1 deletion packages/nodes-figma/src/nodes/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import codeSyntax from "./codeSyntax.js";
import publish from "./publish.js";
import scopeAll from "./scopeAll.js";
import scopeByType from "./scopeByType.js";
import scopeColor from "./scopeColor.js";
import scopeNumber from "./scopeNumber.js";
import scopeString from "./scopeString.js";

export const nodes = [
codeSyntax,
publish,
scopeAll,
scopeByType,
scopeColor,
scopeNumber,
scopeString,
codeSyntax,
];
87 changes: 87 additions & 0 deletions packages/nodes-figma/src/nodes/scopeByType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { FigmaScope } from "../types/scopes.js";
import {
INodeDefinition,
Node,
ToInput,
ToOutput,
} from "@tokens-studio/graph-engine";
import { SingleToken } from "@tokens-studio/types";
import { TokenSchema } from "@tokens-studio/graph-engine-nodes-design-tokens/schemas/index.js";
import { mergeTokenExtensions } from "../utils/tokenMerge.js";

export default class NodeDefinition extends Node {
static title = "Scope By Type";
static type = "studio.tokens.figma.scopeByType";
static description = "Automatically sets Figma scopes based on token type";

declare inputs: ToInput<{
token: SingleToken;
}>;
declare outputs: ToOutput<{
token: SingleToken;
}>;

constructor(props: INodeDefinition) {
super(props);

this.addInput("token", {
type: {
...TokenSchema,
description: "The design token to automatically scope",
},
});

this.addOutput("token", {
type: TokenSchema,
});
}

private getScopesByType(token: SingleToken): FigmaScope[] {
switch (token.type) {
case "color":
return ["ALL_FILLS", "STROKE_COLOR", "EFFECT_COLOR"];
case "dimension":
return [
"GAP",
"WIDTH_HEIGHT",
"CORNER_RADIUS",
"STROKE_FLOAT",
"EFFECT_FLOAT",
"PARAGRAPH_INDENT",
];
case "spacing":
return ["GAP", "WIDTH_HEIGHT"];
case "borderRadius":
return ["CORNER_RADIUS"];
case "fontFamilies":
return ["FONT_FAMILY"];
case "fontWeights":
return ["FONT_WEIGHT"];
case "fontSizes":
return ["FONT_SIZE"];
case "lineHeights":
return ["LINE_HEIGHT"];
case "letterSpacing":
return ["LETTER_SPACING"];
case "paragraphSpacing":
return ["PARAGRAPH_SPACING"];
case "opacity":
return ["OPACITY"];
case "sizing":
return ["WIDTH_HEIGHT"];
default:
return [];
}
}

execute(): void | Promise<void> {
const { token } = this.getAllInputs();
const newScopes = this.getScopesByType(token);

const modifiedToken = mergeTokenExtensions(token, {
scopes: newScopes,
});

this.outputs.token.set(modifiedToken);
}
}
118 changes: 118 additions & 0 deletions packages/nodes-figma/tests/scopeByType.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { Graph } from "@tokens-studio/graph-engine";
import { SingleToken } from "@tokens-studio/types";
import { describe, expect, test } from "vitest";
import Node from "../src/nodes/scopeByType.js";

describe("nodes/scopeByType", () => {
test("adds color scopes to color token", async () => {
const graph = new Graph();
const node = new Node({ graph });

const mockToken = {
name: "test",
value: "#ff0000",
type: "color",
} as SingleToken;

node.inputs.token.setValue(mockToken);
await node.execute();

expect(node.outputs.token.value).toEqual({
...mockToken,
$extensions: {
"com.figma": {
scopes: ["ALL_FILLS", "STROKE_COLOR", "EFFECT_COLOR"],
},
},
});
});

test("adds dimension scopes to dimension token", async () => {
const graph = new Graph();
const node = new Node({ graph });

const mockToken = {
name: "test",
value: "16px",
type: "dimension",
} as SingleToken;

node.inputs.token.setValue(mockToken);
await node.execute();

expect(node.outputs.token.value).toEqual({
...mockToken,
$extensions: {
"com.figma": {
scopes: [
"GAP",
"WIDTH_HEIGHT",
"CORNER_RADIUS",
"STROKE_FLOAT",
"EFFECT_FLOAT",
"PARAGRAPH_INDENT",
],
},
},
});
});

test("adds font-related scopes to typography tokens", async () => {
const graph = new Graph();
const node = new Node({ graph });

const mockToken = {
name: "test",
value: "Inter",
type: "fontFamilies",
} as SingleToken;

node.inputs.token.setValue(mockToken);
await node.execute();

expect(node.outputs.token.value).toEqual({
...mockToken,
$extensions: {
"com.figma": {
scopes: ["FONT_FAMILY"],
},
},
});
});

test("preserves existing extensions and merges scopes", async () => {
const graph = new Graph();
const node = new Node({ graph });

const mockToken = {
name: "test",
value: "#ff0000",
type: "color",
$extensions: {
"com.figma": {
scopes: ["TEXT_FILL"],
otherProp: true,
},
"other.extension": {
someProp: "value",
},
},
} as unknown as SingleToken;

node.inputs.token.setValue(mockToken);
await node.execute();

expect(node.outputs.token.value).toEqual({
...mockToken,
$extensions: {
"com.figma": {
scopes: ["TEXT_FILL", "ALL_FILLS", "STROKE_COLOR", "EFFECT_COLOR"],
otherProp: true,
},
"other.extension": {
someProp: "value",
},
},
});
});
});

0 comments on commit 6f239b9

Please sign in to comment.