Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ jobs:
run: mkdir logs

- name: Build (affected)
run: npx nx affected -t build --parallel=3
run: ./node_modules/.bin/nx affected -t build --parallel=3

- name: Confirm the build hasn't changed any files
run: ./scripts/check-pristine-state package-lock.json

# TODO(Issue 6.1): replace the two checks below with
# npx nx run backpack-harness:lint
# ./node_modules/.bin/nx run backpack-harness:lint
# once the backpack-harness lib is created.
- name: Check React versions
run: npm run check-react-versions
Expand All @@ -85,13 +85,13 @@ jobs:
run: npm run check-bpk-dependencies

- name: Lint (affected)
run: npx nx affected -t lint --parallel=3
run: ./node_modules/.bin/nx affected -t lint --parallel=3

- name: Typecheck (affected)
run: npx nx affected -t typecheck --parallel=3
run: ./node_modules/.bin/nx affected -t typecheck --parallel=3

- name: Tests (affected)
run: bash -c "set -o pipefail; npx nx affected -t test --parallel=3 |& tee 'logs/test.log'"
run: bash -c "set -o pipefail; ./node_modules/.bin/nx affected -t test --parallel=3 |& tee 'logs/test.log'"

- name: Tar and compress logs
run: |
Expand Down
15 changes: 13 additions & 2 deletions .github/workflows/sync-figma-code-connect.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,30 @@ jobs:
code-connect:
name: Code Connect
runs-on: ubuntu-latest
permissions:
contents: read
# Skip on PRs from forks where FIGMA_TOKEN is unavailable.
if: github.event_name == 'push' || github.repository == github.event.pull_request.head.repo.full_name
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: '.nvmrc'

- name: Install dependencies
run: npm ci

- name: Validate Code Connect (dry run)
if: github.event_name == 'pull_request'
run: npx --package @figma/code-connect figma connect publish --dry-run
run: ./node_modules/.bin/figma connect publish --dry-run
env:
FIGMA_ACCESS_TOKEN: ${{ secrets.FIGMA_TOKEN }}

- name: Publish Code Connect
if: github.event_name == 'push'
run: npx --package @figma/code-connect figma connect publish
run: ./node_modules/.bin/figma connect publish
env:
FIGMA_ACCESS_TOKEN: ${{ secrets.FIGMA_TOKEN }}
4 changes: 2 additions & 2 deletions .github/workflows/sync-figma-variables.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
env:
FIGMA_VARIABLES_SYNC_TOKEN: ${{ secrets.FIGMA_VARIABLES_SYNC_TOKEN }}
FIGMA_FILE_KEY: ${{ github.event.inputs.file_key || secrets.FIGMA_FILE_KEY }}
run: npm run tokens:fetch
run: ./node_modules/.bin/nx run backpack-token-sync:tokens-fetch

- name: Stage 2 - Build CSS from DTCG tokens
run: npm run tokens:build-css
run: ./node_modules/.bin/nx run backpack-token-sync:tokens-build-css
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ yarn.lock
# Ignore css assets as these should be built on demand from sass
*.css
!packages/backpack-web/src/bpk-stylesheets/base.css
!token-sync/css/*.css
!libs/backpack-token-sync/css/*.css
/packages/backpack-web/src/bpk-stylesheets/normalize.scss
.copilot-progress

Expand Down
File renamed without changes.
18 changes: 9 additions & 9 deletions token-sync/README.md → libs/backpack-token-sync/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# token-sync
# backpack-token-sync

A small CLI that syncs design tokens from the Backpack Foundations & Components
Figma file into the Backpack codebase, in two stages:
Expand All @@ -15,12 +15,12 @@ flowchart LR
fetch --> xform
end

subgraph tokens["token-sync/tokens/"]
subgraph tokens["libs/backpack-token-sync/tokens/"]
pj["primitives.json"] ~~~ mf["manifest.json"]
bl["backpack.light.json"] ~~~ bd["backpack.dark.json"]
end

subgraph css["token-sync/css/"]
subgraph css["libs/backpack-token-sync/css/"]
pc["primitives.css<br/>:root { }"]
lc["theme-backpack-light.css<br/>:root { }"]
dc["theme-backpack-dark.css<br/>:root[data-theme='dark'] { }"]
Expand All @@ -44,7 +44,7 @@ token with the **Variables — Read-only** scope, and copy it (Figma only shows

The token is never committed. There are two places it needs to live:

- **Local dev** — copy `token-sync/.env.example` to `token-sync/.env` and fill in:
- **Local dev** — copy `libs/backpack-token-sync/.env.example` to `libs/backpack-token-sync/.env` and fill in:

```
FIGMA_VARIABLES_SYNC_TOKEN=<token from step 1>
Expand All @@ -67,7 +67,7 @@ The token is never committed. There are two places it needs to live:
Fetches the `Primitives` and `Backpack` collections from the Figma
[Variables REST API](https://www.figma.com/developers/api#variables) and writes
deterministic [DTCG](https://design-tokens.github.io/community-group/format/)
JSON files to `token-sync/tokens/`.
JSON files to `libs/backpack-token-sync/tokens/`.

From the repo root:

Expand All @@ -79,7 +79,7 @@ npm run tokens:fetch
Output:

```text
token-sync/tokens/
libs/backpack-token-sync/tokens/
├─ primitives.json # raw colour/spacing/… literals
├─ backpack.light.json # semantic tokens, Light mode
├─ backpack.dark.json # semantic tokens, Dark mode
Expand Down Expand Up @@ -109,7 +109,7 @@ place depending on whether you're running locally or in CI.

[Style Dictionary](https://styledictionary.com/) v5 reads the DTCG files above
and emits one CSS file per theme plus a theme-independent primitives sheet to
`token-sync/css/`.
`libs/backpack-token-sync/css/`.

From the repo root, **after** running Stage 1:

Expand All @@ -120,7 +120,7 @@ npm run tokens:build-css
Output:

```text
token-sync/css/
libs/backpack-token-sync/css/
├─ primitives.css # :root { --bpk-spacing-…: <value>; … }
├─ theme-backpack-light.css # :root { --bpk-…: <light value>; }
└─ theme-backpack-dark.css # :root[data-theme="dark"] { --bpk-…: <dark value>; }
Expand Down Expand Up @@ -155,7 +155,7 @@ alongside whichever theme sheets you use.
be `Xpx` (e.g. `"16px"`) or a DTCG alias; other units or bare numbers are
rejected so they can't be silently miscalculated during `px → rem` conversion
(base: `1rem = 16px`).
- **The CSS lives outside `token-sync/tokens/`** so Stage 1's directory wipe
- **The CSS lives outside `libs/backpack-token-sync/tokens/`** so Stage 1's directory wipe
doesn't clobber it.

### Adding a new theme
Expand Down
33 changes: 33 additions & 0 deletions libs/backpack-token-sync/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Backpack - Skyscanner's Design System
*
* Copyright 2016 Skyscanner Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

module.exports = {
rootDir: __dirname,
// The workspace's babel.config.js lives at the repo root (../..). With jest's
// rootDir scoped to this project, Babel would look for config from here and
// miss it, so tell babel-jest to resolve the config by walking up.
transform: {
'^.+\\.[jt]sx?$': ['babel-jest', { rootMode: 'upward' }],
},
testEnvironment: 'node',
testRegex: 'src/.*-test\\.[jt]sx?$',
transformIgnorePatterns: [
'node_modules/(?!bpk|@skyscanner|d3-.*|internmap)',
],
verbose: true,
};
7 changes: 7 additions & 0 deletions libs/backpack-token-sync/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "bpk-token-sync",
"version": "0.0.0",
"private": true,
"description": "Internal CLI that syncs design tokens from the Backpack Foundations & Components Figma file into DTCG JSON and CSS custom properties.",
"license": "Apache-2.0"
}
105 changes: 105 additions & 0 deletions libs/backpack-token-sync/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
{
"name": "backpack-token-sync",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/backpack-token-sync/src",
"projectType": "library",
"tags": ["scope:internal", "type:tooling"],
"targets": {
"tokens-fetch": {
"executor": "nx:run-commands",
"options": {
"command": "tsx src/index.ts",
"cwd": "{projectRoot}"
},
"inputs": [
"{projectRoot}/src/**/*",
"{projectRoot}/.env",
"{projectRoot}/.env.example",
{ "env": "FIGMA_VARIABLES_SYNC_TOKEN" },
{ "env": "FIGMA_FILE_KEY" },
{ "env": "DTCG_OUTPUT_DIR" }
],
"outputs": ["{projectRoot}/tokens"],
"cache": false
},
"tokens-build-css": {
"executor": "nx:run-commands",
"options": {
"command": "tsx src/build-css-cli.ts",
"cwd": "{projectRoot}"
},
"inputs": [
"{projectRoot}/src/**/*",
"{projectRoot}/tokens/**/*",
{ "env": "DTCG_OUTPUT_DIR" },
{ "env": "CSS_OUTPUT_DIR" }
],
"outputs": ["{projectRoot}/css"],
"cache": true
},
"tokens-sync": {
"executor": "nx:run-commands",
"options": {
"commands": [
"nx run backpack-token-sync:tokens-fetch",
"nx run backpack-token-sync:tokens-build-css"
],
"parallel": false
}
},
"lint-js": {
"executor": "nx:run-commands",
"options": {
"command": "eslint libs/backpack-token-sync --ext .js,.jsx,.ts,.tsx",
"cwd": "{workspaceRoot}"
},
"inputs": [
"{projectRoot}/**/*.{js,jsx,ts,tsx}",
"{workspaceRoot}/.eslintrc*",
"{workspaceRoot}/.eslintignore"
],
"cache": true
},
"lint": {
"executor": "nx:run-commands",
"options": {
"commands": ["nx run backpack-token-sync:lint-js"],
"parallel": false
},
"cache": true
},
"typecheck": {
"executor": "nx:run-commands",
"options": {
"command": "tsc --build libs/backpack-token-sync/tsconfig.lib.json",
"cwd": "{workspaceRoot}"
},
"inputs": [
"{projectRoot}/**/*.ts",
"{projectRoot}/tsconfig*.json",
"{workspaceRoot}/tsconfig.base.json"
],
"outputs": [
"{projectRoot}/.tsbuildinfo",
"{workspaceRoot}/dist/out-tsc/libs/backpack-token-sync"
],
"cache": true
},
"test": {
"executor": "nx:run-commands",
"options": {
"command": "jest --config libs/backpack-token-sync/jest.config.js",
"cwd": "{workspaceRoot}",
"env": {
"TZ": "Etc/UTC"
}
},
"inputs": [
"default",
"{projectRoot}/jest.config.js",
"{workspaceRoot}/scripts/jest/**/*"
],
"cache": true
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import { formatFatalError } from './sync-helpers';
const scriptDir = path.dirname(fileURLToPath(import.meta.url));

// Default layout:
// token-sync/tokens/ ← Stage 1 DTCG output (`npm run tokens:fetch`)
// token-sync/css/ ← Stage 2 CSS output (`npm run tokens:build-css`)
// libs/backpack-token-sync/tokens/ ← Stage 1 DTCG output (`npm run tokens:fetch`)
// libs/backpack-token-sync/css/ ← Stage 2 CSS output (`npm run tokens:build-css`)
// CSS sits outside `tokens/` so Stage 1's directory-clear doesn't wipe it.
// Both paths overridable via env vars.
const DEFAULT_TOKENS_DIR = path.resolve(scriptDir, '../tokens');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import {
// CLI is spawned via tsx (not imported) to keep SD's ESM runtime out of
// jest's CJS babel transform.

const REPO_ROOT = path.resolve(__dirname, '../..');
const REPO_ROOT = path.resolve(__dirname, '../../..');
const CLI_ENTRY = path.resolve(__dirname, 'build-css-cli.ts');
// Use the project-local tsx so the test doesn't depend on a globally
// installed binary.
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ describe('assertUniqueFileNames', () => {
describe('assertSafeOutputDir', () => {
it('accepts a subdirectory of the current working directory', () => {
expect(() =>
assertSafeOutputDir(path.join(process.cwd(), 'token-sync', 'tokens')),
assertSafeOutputDir(path.join(process.cwd(), 'libs', 'backpack-token-sync', 'tokens')),
).not.toThrow();
});

Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ describe('style-dictionary-config', () => {
const tokenWithPath = (filePath: string) => ({ filePath }) as unknown as TransformedToken;

it.each([
['/repo/token-sync/tokens/backpack.day.json'],
['/repo/libs/backpack-token-sync/tokens/backpack.day.json'],
['tokens/backpack.day.json'], // relative path
])('accepts %s', (filePath) => {
expect(filter(tokenWithPath(filePath))).toBe(true);
});

it.each([
['/repo/token-sync/tokens/primitives.json'],
['/repo/token-sync/tokens/backpack.night.json'],
['/repo/libs/backpack-token-sync/tokens/primitives.json'],
['/repo/libs/backpack-token-sync/tokens/backpack.night.json'],
['/repo/backpack.day.json.bak'], // extension mismatch
['/repo/some-backpack.day.json'], // prefix mismatch
])('rejects %s', (filePath) => {
Expand All @@ -77,8 +77,8 @@ describe('style-dictionary-config', () => {
});

describe('buildStyleDictionaryConfigs', () => {
const tokensDir = '/repo/token-sync/tokens';
const buildDir = '/repo/token-sync/tokens/css';
const tokensDir = '/repo/libs/backpack-token-sync/tokens';
const buildDir = '/repo/libs/backpack-token-sync/tokens/css';
const cssTransforms = ['attribute/cti', 'name/kebab', 'size/pxToRem'];
const baseOpts = {
tokensDir,
Expand Down Expand Up @@ -189,8 +189,8 @@ describe('style-dictionary-config', () => {

describe('makeWebPrimitivesTokenFilter', () => {
const filter = makeWebPrimitivesTokenFilter();
const primitivesPath = '/repo/token-sync/tokens/primitives.json';
const semanticPath = '/repo/token-sync/tokens/backpack.light.json';
const primitivesPath = '/repo/libs/backpack-token-sync/tokens/primitives.json';
const semanticPath = '/repo/libs/backpack-token-sync/tokens/backpack.light.json';

it.each<[string, object, boolean]>([
['Spacing (dimension, $type)', { filePath: primitivesPath, path: ['Spacing', 'md'], $type: 'dimension' }, true],
Expand Down Expand Up @@ -600,12 +600,12 @@ describe('style-dictionary-config', () => {
it('renders one line per violation with file basename and JSON-stringified value', () => {
const message = formatDimensionViolations([
{
filePath: '/abs/repo/token-sync/tokens/backpack.day.json',
filePath: '/abs/repo/libs/backpack-token-sync/tokens/backpack.day.json',
tokenPath: 'Component.Button.Dimension.padding-h',
value: '16em',
},
{
filePath: '/abs/repo/token-sync/tokens/primitives.json',
filePath: '/abs/repo/libs/backpack-token-sync/tokens/primitives.json',
tokenPath: 'Spacing.md',
value: 16,
},
Expand Down
Loading
Loading