├── .prettierrc.json ├── .npmignore ├── .gitignore ├── vite.config.ts ├── src ├── definitions │ ├── Alias.ts │ ├── GroupProperties.ts │ ├── JSONTokenTree.ts │ ├── TokenSignature.ts │ ├── JSONSignatures.ts │ └── tokenTypes.ts ├── utils │ ├── matchIsTokenTypeName.ts │ ├── matchIsAliasValue.ts │ ├── matchIsGroup.ts │ ├── matchIsToken.ts │ ├── extractAliasPath.ts │ └── captureAliasPath.ts └── index.ts ├── tests ├── tsconfig.json ├── utils │ ├── matchIsAliasValue.spec.ts │ ├── matchIsTokenTypeName.spec.ts │ ├── extractAlias.spec.ts │ ├── matchIsGroup.spec.ts │ ├── matchIsToken.spec.ts │ └── captureAliasPath.spec.ts └── definitions │ └── jsonTokenTree.spec.ts ├── tsconfig.json ├── .github └── workflows │ ├── build-and-test.yml │ └── npm-publish.yml ├── package.json ├── LICENSE ├── CONTRIBUTING.md └── README.md /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | coverage 3 | node_modules 4 | src 5 | tests 6 | 7 | .prettierrc.json 8 | vite.config.ts 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | .idea 4 | .vscode 5 | 6 | .env.* 7 | .npmrc 8 | 9 | node_modules 10 | dist 11 | coverage 12 | 13 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config'; 2 | 3 | export default defineConfig({ 4 | test: { 5 | globals: false, 6 | }, 7 | }); 8 | -------------------------------------------------------------------------------- /src/definitions/Alias.ts: -------------------------------------------------------------------------------- 1 | export type AliasValue = `{${string}}`; 2 | 3 | export type WithAliasValue = T | AliasValue; 4 | 5 | export const ALIAS_PATH_SEPARATOR = '.'; 6 | -------------------------------------------------------------------------------- /src/definitions/GroupProperties.ts: -------------------------------------------------------------------------------- 1 | import type { JSONObject } from './JSONSignatures.js'; 2 | import type { TokenTypeName } from './tokenTypes.js'; 3 | 4 | export type GroupProperties = { 5 | $type?: TokenTypeName; 6 | $description?: string; 7 | $extensions?: JSONObject; 8 | }; 9 | -------------------------------------------------------------------------------- /tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "rootDir": "../", 7 | "noEmit": true 8 | }, 9 | "include": [".", "../src"], 10 | "exclude": ["../dist"] 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/matchIsTokenTypeName.ts: -------------------------------------------------------------------------------- 1 | import { TokenTypeName, tokenTypeNames } from '../definitions/tokenTypes.js'; 2 | 3 | export function matchIsTokenTypeName(value: unknown): value is TokenTypeName { 4 | return ( 5 | typeof value === 'string' && tokenTypeNames.includes(value as TokenTypeName) 6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /src/definitions/JSONTokenTree.ts: -------------------------------------------------------------------------------- 1 | import type { DesignToken } from './tokenTypes.js'; 2 | import type { GroupProperties } from './GroupProperties.js'; 3 | 4 | export type JSONTokenTree = 5 | | (GroupProperties & { 6 | [key: string]: DesignToken | JSONTokenTree | GroupProperties; 7 | }) 8 | | DesignToken; 9 | -------------------------------------------------------------------------------- /src/utils/matchIsAliasValue.ts: -------------------------------------------------------------------------------- 1 | import { AliasValue } from '../definitions/Alias.js'; 2 | 3 | export function matchIsAliasValue(candidate: unknown): candidate is AliasValue { 4 | return ( 5 | typeof candidate === 'string' && 6 | candidate.startsWith('{') && 7 | candidate.endsWith('}') 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/matchIsGroup.ts: -------------------------------------------------------------------------------- 1 | import { JSONTokenTree } from '../definitions/JSONTokenTree.js'; 2 | 3 | export function matchIsGroup(value: unknown): value is JSONTokenTree { 4 | return ( 5 | typeof value === 'object' && 6 | value !== null && 7 | !Array.isArray(value) && 8 | !('$value' in value) 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /src/definitions/TokenSignature.ts: -------------------------------------------------------------------------------- 1 | import type { JSONObject, JSONValue } from './JSONSignatures.js'; 2 | 3 | export type TokenSignature = { 4 | $value: Value; 5 | $type?: Type; 6 | $deprecated?: boolean | string; 7 | $description?: string; 8 | $extensions?: JSONObject; 9 | }; 10 | -------------------------------------------------------------------------------- /src/utils/matchIsToken.ts: -------------------------------------------------------------------------------- 1 | import { TokenSignature } from '../definitions/TokenSignature.js'; 2 | import { TokenTypeName } from '../definitions/tokenTypes.js'; 3 | import { JSONValue } from '../definitions/JSONSignatures.js'; 4 | 5 | export function matchIsToken( 6 | value: unknown, 7 | ): value is TokenSignature { 8 | return ( 9 | typeof value === 'object' && 10 | value !== null && 11 | !Array.isArray(value) && 12 | '$value' in value 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/utils/extractAliasPath.ts: -------------------------------------------------------------------------------- 1 | import { ALIAS_PATH_SEPARATOR, AliasValue } from '../definitions/Alias.js'; 2 | 3 | function makeExtractAliasPath(hasString: boolean) { 4 | return function extractAliasPath(aliasValue: AliasValue) { 5 | const stringPath = aliasValue.slice(1).slice(0, -1); 6 | return hasString ? stringPath : stringPath.split(ALIAS_PATH_SEPARATOR); 7 | }; 8 | } 9 | 10 | export const extractAliasPathAsString = makeExtractAliasPath(true); 11 | export const extractAliasPathAsArray = makeExtractAliasPath(false); 12 | -------------------------------------------------------------------------------- /src/definitions/JSONSignatures.ts: -------------------------------------------------------------------------------- 1 | export type JSONPrimitiveValue = string | number | boolean | null; 2 | export type JSONObject = { 3 | [name: string]: JSONValue; 4 | }; 5 | export type JSONArray = JSONValue[]; 6 | export type JSONValue = JSONPrimitiveValue | JSONArray | JSONObject; 7 | 8 | export type JSONValuePath = Array; 9 | 10 | export namespace Json { 11 | export type Value = JSONValue; 12 | export type Object = JSONObject; 13 | export type Array = JSONArray; 14 | export type Primitive = string | number | boolean | null; 15 | export type ValuePath = JSONValuePath; 16 | } 17 | -------------------------------------------------------------------------------- /tests/utils/matchIsAliasValue.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | import { matchIsAliasValue } from '../../src/utils/matchIsAliasValue.js'; 4 | 5 | describe.concurrent('matchIsAliasValue', () => { 6 | it('should return true if the value is an alias', () => { 7 | expect(matchIsAliasValue('{foo}')).toBe(true); 8 | }); 9 | it('should return false if the value is a string with no heading "{" character', () => { 10 | expect(matchIsAliasValue('foo')).toBe(false); 11 | }); 12 | it('should return false if the value is a number', () => { 13 | expect(matchIsAliasValue(1)).toBe(false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/utils/matchIsTokenTypeName.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | import { tokenTypeNames } from '../../src/definitions/tokenTypes.js'; 4 | 5 | import { matchIsTokenTypeName } from '../../src/utils/matchIsTokenTypeName.js'; 6 | 7 | describe.concurrent('matchIsTokenTypeName', () => { 8 | it('should return true if the value is a token type name', () => { 9 | for (const type of tokenTypeNames) { 10 | expect(matchIsTokenTypeName(type)).toBe(true); 11 | } 12 | }); 13 | it('should return false if the value is not a token type name', () => { 14 | expect(matchIsTokenTypeName('not a token type name')).toBe(false); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "exactOptionalPropertyTypes": true, 5 | "forceConsistentCasingInFileNames": true, 6 | "esModuleInterop": true, 7 | "skipLibCheck": true, 8 | "target": "es2022", 9 | "moduleDetection": "force", 10 | "isolatedModules": true, 11 | "noImplicitOverride": true, 12 | 13 | "module": "NodeNext", 14 | "moduleResolution": "NodeNext", 15 | "declaration": true, 16 | 17 | "lib": ["es2022"], 18 | 19 | "rootDir": "./src", 20 | "outDir": "./dist" 21 | }, 22 | "include": ["./src"], 23 | "exclude": ["./dist", "vite.config.ts", "./tests", "./**/*.spec.ts"] 24 | } 25 | -------------------------------------------------------------------------------- /tests/utils/extractAlias.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | import { 4 | extractAliasPathAsArray, 5 | extractAliasPathAsString, 6 | } from '../../src/utils/extractAliasPath.js'; 7 | 8 | describe('extractAlias', () => { 9 | describe('extractAliasPathAsString', () => { 10 | it('should return the alias path as a string', () => { 11 | expect(extractAliasPathAsString('{alias.path}')).toBe('alias.path'); 12 | }); 13 | }); 14 | describe('extractAliasPathAsArray', () => { 15 | it('should return the alias path as an array', () => { 16 | expect(extractAliasPathAsArray('{alias.path}')).toEqual([ 17 | 'alias', 18 | 'path', 19 | ]); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /tests/utils/matchIsGroup.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | import { matchIsGroup } from '../../src/utils/matchIsGroup.js'; 4 | 5 | describe.concurrent('matchIsGroup', () => { 6 | it('should return true if the value is an object without the "$value" property', () => { 7 | expect(matchIsGroup({ foo: 'bar' })).toBe(true); 8 | }); 9 | it('should return false if the value is an object with the "$value" property', () => { 10 | expect(matchIsGroup({ $value: 'any' })).toBe(false); 11 | }); 12 | it('should return false if the value is a string', () => { 13 | expect(matchIsGroup('a string')).toBe(false); 14 | }); 15 | it('should return false if the value is an array', () => { 16 | expect(matchIsGroup([])).toBe(false); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /tests/utils/matchIsToken.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | import { matchIsToken } from '../../src/utils/matchIsToken.js'; 4 | 5 | describe.concurrent('matchIsToken', () => { 6 | it('should return true if the value is an object with the "$value" property', () => { 7 | expect(matchIsToken({ $value: 'any' })).toBe(true); 8 | }); 9 | it('should return false if the value is an object without the "$value" property', () => { 10 | expect(matchIsToken({ foo: 'bar' })).toBe(false); 11 | }); 12 | it('should return false if the value is a string', () => { 13 | expect(matchIsToken('a string')).toBe(false); 14 | }); 15 | it('should return false if the value is an array', () => { 16 | expect(matchIsToken([])).toBe(false); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /.github/workflows/build-and-test.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build-and-test: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [20.x, 22.x, 24.x] 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | cache: 'npm' 25 | 26 | - name: Install dependencies 27 | run: npm ci 28 | 29 | - name: Build 30 | run: npm run build 31 | 32 | - name: Run tests 33 | run: npm test -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "design-tokens-format-module", 3 | "description": "A Typescript implementation of the Design Tokens Format Module specification", 4 | "keywords": [ 5 | "design token format module", 6 | "design tokens", 7 | "design system", 8 | "dtcg" 9 | ], 10 | "version": "0.11.1", 11 | "homepage": "https://github.com/nclsndr/design-tokens-format-module", 12 | "license": "MIT", 13 | "author": "Nico Andre", 14 | "type": "module", 15 | "scripts": { 16 | "test": "tsc --project tests/tsconfig.json || true && vitest", 17 | "build": "rm -rf dist && tsc --project tsconfig.json", 18 | "format": "prettier --write .", 19 | "tsc": "tsc" 20 | }, 21 | "main": "./dist/index.js", 22 | "exports": { 23 | ".": "./dist/index.js" 24 | }, 25 | "devDependencies": { 26 | "@types/node": "^20.14.10", 27 | "@vitest/coverage-v8": "^2.1.9", 28 | "prettier": "^3.5.3", 29 | "typescript": "^5.8.3", 30 | "vitest": "^2.1.9" 31 | } 32 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Nico Andre 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | type AliasValue, 3 | type WithAliasValue, 4 | ALIAS_PATH_SEPARATOR, 5 | } from './definitions/Alias.js'; 6 | export { type GroupProperties } from './definitions/GroupProperties.js'; 7 | export { type Json } from './definitions/JSONSignatures.js'; 8 | export { type JSONTokenTree } from './definitions/JSONTokenTree.js'; 9 | export { type TokenSignature } from './definitions/TokenSignature.js'; 10 | export { 11 | type Color, 12 | type Dimension, 13 | type FontFamily, 14 | type FontWeight, 15 | type Duration, 16 | type CubicBezier, 17 | type Number, 18 | type StrokeStyle, 19 | type Border, 20 | type Transition, 21 | type Shadow, 22 | type Gradient, 23 | type Typography, 24 | // Aggregated types 25 | type DesignToken, 26 | type TokenTypeName, 27 | // Utils 28 | type PickTokenByType, 29 | // Types constants 30 | tokenTypeNames, 31 | tokenTypeNamesMapping, 32 | // Enum-like values 33 | colorSpaceValues, 34 | fontWeightValues, 35 | strokeStyleStringValues, 36 | strokeStyleLineCapValues, 37 | } from './definitions/tokenTypes.js'; 38 | 39 | export { 40 | captureAliasPath, 41 | CAPTURE_ALIAS_PATH_ERRORS, 42 | } from './utils/captureAliasPath.js'; 43 | export { 44 | extractAliasPathAsString, 45 | extractAliasPathAsArray, 46 | } from './utils/extractAliasPath.js'; 47 | export { matchIsAliasValue } from './utils/matchIsAliasValue.js'; 48 | export { matchIsGroup } from './utils/matchIsGroup.js'; 49 | export { matchIsToken } from './utils/matchIsToken.js'; 50 | export { matchIsTokenTypeName } from './utils/matchIsTokenTypeName.js'; 51 | -------------------------------------------------------------------------------- /tests/utils/captureAliasPath.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | import { captureAliasPath } from '../../src/utils/captureAliasPath.js'; 4 | 5 | describe('captureAliasPath', () => { 6 | it('should return the alias path as a string when asString option is true', () => { 7 | expect(captureAliasPath('{alias.path}', true)).toStrictEqual({ 8 | status: 'ok', 9 | value: 'alias.path', 10 | }); 11 | }); 12 | it('should return the alias path as an array when asString option is false', () => { 13 | expect(captureAliasPath('{alias.path}', false)).toStrictEqual({ 14 | status: 'ok', 15 | value: ['alias', 'path'], 16 | }); 17 | }); 18 | it('should return the alias path as an array when no option is provided', () => { 19 | expect(captureAliasPath('{alias.path}')).toStrictEqual({ 20 | status: 'ok', 21 | value: ['alias', 'path'], 22 | }); 23 | }); 24 | it('should return an error when the value is not a string', () => { 25 | expect(captureAliasPath(123)).toStrictEqual({ 26 | status: 'error', 27 | error: { 28 | tag: 'TYPE_ERROR', 29 | message: 'Expected a string value. Got number.', 30 | }, 31 | }); 32 | }); 33 | it('should return an error when the value is not an alias', () => { 34 | expect(captureAliasPath('alias.path')).toStrictEqual({ 35 | status: 'error', 36 | error: { 37 | tag: 'FORMAT_ERROR', 38 | message: 39 | 'Expected a string value enclosed in curly braces, using dot notation: {path.to.token}. Got "alias.path".', 40 | }, 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/utils/captureAliasPath.ts: -------------------------------------------------------------------------------- 1 | import { 2 | extractAliasPathAsArray, 3 | extractAliasPathAsString, 4 | } from './extractAliasPath.js'; 5 | import { matchIsAliasValue } from './matchIsAliasValue.js'; 6 | 7 | export const CAPTURE_ALIAS_PATH_ERRORS = [ 8 | 'TYPE_ERROR', 9 | 'FORMAT_ERROR', 10 | ] as const; 11 | 12 | type ValidationError = { 13 | tag: (typeof CAPTURE_ALIAS_PATH_ERRORS)[number]; 14 | message: string; 15 | }; 16 | 17 | type Result = 18 | | { 19 | status: 'ok'; 20 | value: T; 21 | } 22 | | { 23 | status: 'error'; 24 | error: E; 25 | }; 26 | 27 | export function captureAliasPath( 28 | value: unknown, 29 | ): Result, ValidationError>; 30 | export function captureAliasPath( 31 | value: unknown, 32 | asString: AsString, 33 | ): Result, ValidationError>; 34 | export function captureAliasPath( 35 | value: unknown, 36 | asString?: AsString, 37 | ): Result, ValidationError> { 38 | if (typeof value !== 'string') { 39 | return { 40 | status: 'error', 41 | error: { 42 | tag: 'TYPE_ERROR', 43 | message: `Expected a string value. Got ${typeof value}.`, 44 | }, 45 | }; 46 | } 47 | 48 | if (!matchIsAliasValue(value)) { 49 | return { 50 | status: 'error', 51 | error: { 52 | tag: 'FORMAT_ERROR', 53 | message: `Expected a string value enclosed in curly braces, using dot notation: {path.to.token}. Got ${JSON.stringify(value)}.`, 54 | }, 55 | }; 56 | } 57 | 58 | return { 59 | status: 'ok', 60 | value: (asString !== true 61 | ? extractAliasPathAsArray(value) 62 | : extractAliasPathAsString(value)) as any, 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /tests/definitions/jsonTokenTree.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | import { JSONTokenTree } from '../../src/definitions/JSONTokenTree.js'; 4 | 5 | describe('JSONTokenTree', () => { 6 | it('should accept a literal token tree', () => { 7 | const tree: JSONTokenTree = { 8 | colors: { 9 | $type: 'color', 10 | blue: { 11 | $value: '#0000ff', 12 | }, 13 | lighten: { 14 | blue: { 15 | $value: '{colors.blue}', 16 | }, 17 | }, 18 | }, 19 | red: { 20 | $type: 'color', 21 | $value: { 22 | colorSpace: 'srgb', 23 | components: [0, 0, 0], 24 | }, 25 | }, 26 | }; 27 | 28 | expect(tree).toBeDefined(); 29 | }); 30 | it('should accept any of the token values when $type is not provided at the token level', () => { 31 | const tree: JSONTokenTree = { 32 | colors: { 33 | $type: 'color', 34 | blue: { 35 | $value: 'an invalid value', 36 | }, 37 | }, 38 | // @ts-expect-error 39 | red: { 40 | $type: 'color', 41 | $value: 'an invalid value', 42 | }, 43 | }; 44 | 45 | expect(tree).toBeDefined(); 46 | }); 47 | it('should accept a description and extensions at the root level', () => { 48 | const tree: JSONTokenTree = { 49 | $description: 'A description of the token tree', 50 | $extensions: { 51 | 'com.example': true, 52 | }, 53 | }; 54 | 55 | expect(tree).toBeDefined(); 56 | }); 57 | it('should accept a token at the root level', () => { 58 | const tree: JSONTokenTree = { 59 | $type: 'color', 60 | $value: { 61 | colorSpace: 'srgb', 62 | components: [0, 0, 0], 63 | alpha: 1, 64 | hex: '#000000', 65 | }, 66 | }; 67 | 68 | expect(tree).toBeDefined(); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Package to NPM 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: 'Version to publish (e.g., 1.0.0, patch, minor, major)' 8 | required: true 9 | default: 'patch' 10 | tag: 11 | description: 'NPM tag (e.g., latest, beta, next)' 12 | required: true 13 | default: 'latest' 14 | 15 | jobs: 16 | publish: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | with: 21 | # This ensures complete repo history for version management 22 | fetch-depth: 0 23 | 24 | - name: Setup Node.js 25 | uses: actions/setup-node@v4 26 | with: 27 | node-version: '20.x' 28 | registry-url: 'https://registry.npmjs.org' 29 | cache: 'npm' 30 | 31 | - name: Install dependencies 32 | run: npm ci 33 | 34 | - name: Set custom version 35 | id: set-version 36 | run: | 37 | # For semantic versioning keywords (patch, minor, major) 38 | if [[ "${{ github.event.inputs.version }}" =~ ^(patch|minor|major)$ ]]; then 39 | npm version ${{ github.event.inputs.version }} --no-git-tag-version 40 | # For explicit versions (e.g., 1.0.0) 41 | else 42 | npm version ${{ github.event.inputs.version }} --no-git-tag-version --allow-same-version 43 | fi 44 | echo "new_version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT 45 | 46 | - name: Build package 47 | run: npm run build 48 | 49 | - name: Run tests 50 | run: npm test 51 | 52 | - name: Publish to NPM 53 | run: npm publish --tag ${{ github.event.inputs.tag }} 54 | env: 55 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 56 | 57 | - name: Create Git tag 58 | run: | 59 | git config --local user.email "hello@nclsndr.com" 60 | git config --local user.name "nclsndr" 61 | git tag -a v${{ steps.set-version.outputs.new_version }} -m "Release v${{ steps.set-version.outputs.new_version }}" 62 | git push origin v${{ steps.set-version.outputs.new_version }} 63 | env: 64 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Design Tokens Format Module 2 | 3 | Thank you for your interest in contributing to the Design Tokens Format Module! This document provides guidelines and instructions to help you get started. 4 | 5 | ## Getting Started 6 | 7 | ### Prerequisites 8 | 9 | - Node.js (preferably the latest LTS version) 10 | - npm 11 | 12 | ### Setup 13 | 14 | 1. Fork the repository on GitHub 15 | 2. Clone your fork locally 16 | ```bash 17 | git clone https://github.com/YOUR-USERNAME/design-tokens-format-module.git 18 | cd design-tokens-format-module 19 | ``` 20 | 3. Add the original repository as an upstream remote 21 | ```bash 22 | git remote add upstream https://github.com/nclsndr/design-tokens-format-module.git 23 | ``` 24 | 4. Install dependencies 25 | ```bash 26 | npm install 27 | ``` 28 | 29 | ## Development Workflow 30 | 31 | 1. Create a new branch for your feature or bugfix 32 | ```bash 33 | git checkout -b feature/your-feature-name 34 | ``` 35 | or 36 | ```bash 37 | git checkout -b fix/issue-you-are-fixing 38 | ``` 39 | 40 | 2. Make your changes and commit them using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) 41 | 42 | We follow the Conventional Commits specification which provides a standardized format for commit messages: 43 | ``` 44 | ([optional scope]): 45 | 46 | [optional body] 47 | 48 | [optional footer(s)] 49 | ``` 50 | 51 | Common types include: 52 | - `feat`: A new feature 53 | - `fix`: A bug fix 54 | - `docs`: Documentation changes 55 | - `style`: Changes that don't affect the code's meaning (formatting, etc.) 56 | - `refactor`: Code changes that neither fix a bug nor add a feature 57 | - `test`: Adding or correcting tests 58 | - `chore`: Changes to the build process or auxiliary tools 59 | 60 | 3. Keep your branch updated with the upstream main branch 61 | ```bash 62 | git pull upstream main 63 | ``` 64 | 65 | ## Code Style and Formatting 66 | 67 | This project uses Prettier for code formatting. The configuration is defined in `.prettierrc.json`. 68 | 69 | ### Formatting Your Code 70 | 71 | Before submitting a pull request, make sure your code is properly formatted: 72 | 73 | ```bash 74 | # Format all files 75 | npm run format 76 | 77 | # Check formatting without modifying files 78 | npx prettier --check . 79 | ``` 80 | 81 | ## Testing 82 | 83 | The project uses Vitest for testing. Make sure to add tests for any new features or bug fixes. 84 | 85 | ### Running Tests 86 | 87 | ```bash 88 | # Run tests in watch mode during development 89 | npm run test 90 | 91 | # Run tests once (e.g., before submitting a PR) 92 | npm run test -- --run 93 | ``` 94 | 95 | ### Test Coverage 96 | 97 | To generate a test coverage report: 98 | 99 | ```bash 100 | npm run test -- --coverage 101 | ``` 102 | 103 | ## Building 104 | 105 | The project uses TypeScript for type safety and transpilation. 106 | 107 | ### Building the Project 108 | 109 | ```bash 110 | npm run build 111 | ``` 112 | 113 | This command cleans the `dist` directory and rebuilds the project according to the TypeScript configuration. 114 | 115 | ### Type Checking 116 | 117 | To run the TypeScript compiler without emitting files (useful for checking types): 118 | 119 | ```bash 120 | npm run tsc 121 | ``` 122 | 123 | ## Pull Requests 124 | 125 | 1. Push your changes to your fork 126 | ```bash 127 | git push origin your-branch-name 128 | ``` 129 | 130 | 2. Open a pull request against the main repository's `main` branch 131 | 132 | 3. Ensure your PR includes: 133 | - A clear description of the changes 134 | - Any relevant issue numbers (use "#123" to link to issue 123) 135 | - Updated or new tests covering your changes 136 | - Documentation updates if needed 137 | 138 | 4. Before opening a PR, make sure: 139 | - Tests pass: `npm run test -- --run` 140 | - The build succeeds: `npm run build` 141 | - Code is properly formatted: `npm run format` 142 | 143 | ## Code of Conduct 144 | 145 | Please be respectful and considerate of others when contributing to this project. We strive to maintain a welcoming and inclusive environment for everyone. 146 | 147 | ## Questions? 148 | 149 | If you have any questions or need help, feel free to open an issue or reach out to @nclsndr. 150 | 151 | Thank you for contributing to the Design Tokens Format Module! -------------------------------------------------------------------------------- /src/definitions/tokenTypes.ts: -------------------------------------------------------------------------------- 1 | import type { WithAliasValue } from './Alias.js'; 2 | import type { TokenSignature } from './TokenSignature.js'; 3 | 4 | // Type declaration following the https://tr.designtokens.org/format specification 5 | 6 | // 8.1 Color, following the https://tr.designtokens.org/color specification 7 | const colorTypeName = 'color'; 8 | export const colorSpaceValues = [ 9 | 'srgb', 10 | 'srgb-linear', 11 | 'hsl', 12 | 'hwb', 13 | 'lab', 14 | 'lch', 15 | 'oklab', 16 | 'oklch', 17 | 'display-p3', 18 | 'a98-rgb', 19 | 'prophoto-rgb', 20 | 'rec2020', 21 | 'xyz-d65', 22 | 'xyz-d50', 23 | ] as const; 24 | export namespace Color { 25 | export type TypeName = typeof colorTypeName; 26 | 27 | export type RawValue = { 28 | colorSpace: typeof colorSpaceValues[number]; 29 | components: [number | 'none', number | 'none', number | 'none']; 30 | alpha?: number; 31 | hex?: `#${string}`; 32 | }; 33 | export type Value = WithAliasValue; 34 | export type Token = TokenSignature; 35 | } 36 | 37 | // 8.2 Dimension 38 | const dimensionTypeName = 'dimension'; 39 | export namespace Dimension { 40 | export type TypeName = typeof dimensionTypeName; 41 | export type RawValue = { value: number; unit: 'px' | 'rem' }; 42 | export type Value = WithAliasValue; 43 | export type Token = TokenSignature; 44 | } 45 | 46 | // 8.3 Font Family 47 | const fontFamilyTypeName = 'fontFamily'; 48 | export namespace FontFamily { 49 | export type TypeName = typeof fontFamilyTypeName; 50 | export type RawValue = string | Array; 51 | export type Value = WithAliasValue; 52 | export type Token = TokenSignature; 53 | } 54 | 55 | // 8.4 Font Weight 56 | const fontWeightTypeName = 'fontWeight'; 57 | export const fontWeightValues = [ 58 | 'thin', 59 | 'hairline', 60 | 'extra-light', 61 | 'ultra-light', 62 | 'light', 63 | 'normal', 64 | 'regular', 65 | 'book', 66 | 'medium', 67 | 'semi-bold', 68 | 'demi-bold', 69 | 'bold', 70 | 'extra-bold', 71 | 'ultra-bold', 72 | 'black', 73 | 'heavy', 74 | 'extra-black', 75 | 'ultra-black', 76 | ] as const; 77 | export namespace FontWeight { 78 | export type TypeName = typeof fontWeightTypeName; 79 | export type RawValue = (typeof fontWeightValues)[number] | number; 80 | export type Value = WithAliasValue; 81 | export type Token = TokenSignature; 82 | } 83 | 84 | // 8.5 Duration 85 | const durationTypeName = 'duration'; 86 | export namespace Duration { 87 | export type TypeName = typeof durationTypeName; 88 | export type RawValue = { value: number; unit: 'ms' | 's' }; 89 | export type Value = WithAliasValue; 90 | export type Token = TokenSignature; 91 | } 92 | 93 | // 8.6 Cubic Bezier 94 | const cubicBezierTypeName = 'cubicBezier'; 95 | export namespace CubicBezier { 96 | export type TypeName = typeof cubicBezierTypeName; 97 | export type RawValue = [number, number, number, number]; 98 | export type Value = WithAliasValue; 99 | export type Token = TokenSignature; 100 | } 101 | 102 | // 8.7 Number 103 | const numberTypeName = 'number'; 104 | export namespace Number { 105 | export type TypeName = typeof numberTypeName; 106 | export type RawValue = number; 107 | export type Value = WithAliasValue; 108 | export type Token = TokenSignature; 109 | } 110 | 111 | /* 112 | 9. Composite Types 113 | https://tr.designtokens.org/format/#composite-types 114 | */ 115 | // 9.2 Stroke Style 116 | const strokeStyleTypeName = 'strokeStyle'; 117 | export const strokeStyleStringValues = [ 118 | 'solid', 119 | 'dashed', 120 | 'dotted', 121 | 'double', 122 | 'groove', 123 | 'ridge', 124 | 'outset', 125 | 'inset', 126 | ] as const; 127 | export const strokeStyleLineCapValues = ['round', 'butt', 'square'] as const; 128 | export namespace StrokeStyle { 129 | export type TypeName = typeof strokeStyleTypeName; 130 | export type RawValue = 131 | | (typeof strokeStyleStringValues)[number] 132 | | { 133 | dashArray: Dimension.Value[]; 134 | lineCap: (typeof strokeStyleLineCapValues)[number]; 135 | }; 136 | export type Value = WithAliasValue; 137 | export type Token = TokenSignature; 138 | } 139 | 140 | // 9.3 Border 141 | const borderTypeName = 'border'; 142 | export namespace Border { 143 | export type TypeName = typeof borderTypeName; 144 | export type RawValue = { 145 | color: Color.Value; 146 | width: Dimension.Value; 147 | style: StrokeStyle.Value; 148 | }; 149 | export type Value = WithAliasValue; 150 | export type Token = TokenSignature; 151 | } 152 | 153 | // 9.4 Transition 154 | const transitionTypeName = 'transition'; 155 | export namespace Transition { 156 | export type TypeName = typeof transitionTypeName; 157 | export type RawValue = { 158 | duration: Duration.Value; 159 | delay: Duration.Value; 160 | timingFunction: CubicBezier.Value; 161 | }; 162 | export type Value = WithAliasValue; 163 | export type Token = TokenSignature; 164 | } 165 | 166 | // 9.5 Shadow 167 | const shadowTypeName = 'shadow'; 168 | export namespace Shadow { 169 | export type TypeName = typeof shadowTypeName; 170 | export type RawValue = 171 | | Array<{ 172 | color: Color.Value; 173 | offsetX: Dimension.Value; 174 | offsetY: Dimension.Value; 175 | blur: Dimension.Value; 176 | spread: Dimension.Value; 177 | inset?: boolean; 178 | }> 179 | | { 180 | color: Color.Value; 181 | offsetX: Dimension.Value; 182 | offsetY: Dimension.Value; 183 | blur: Dimension.Value; 184 | spread: Dimension.Value; 185 | inset?: boolean; 186 | }; 187 | export type Value = WithAliasValue; 188 | export type Token = TokenSignature; 189 | } 190 | 191 | // 9.6 Gradient 192 | const gradientTypeName = 'gradient'; 193 | export namespace Gradient { 194 | export type TypeName = typeof gradientTypeName; 195 | export type RawValue = Array<{ 196 | color: Color.Value; 197 | position: Number.Value; 198 | }>; 199 | export type Value = WithAliasValue; 200 | export type Token = TokenSignature; 201 | } 202 | 203 | // 9.7 Typography 204 | const typographyTypeName = 'typography'; 205 | export namespace Typography { 206 | export type TypeName = typeof typographyTypeName; 207 | export type RawValue = { 208 | fontFamily: FontFamily.Value; 209 | fontSize: Dimension.Value; 210 | fontWeight: FontWeight.Value; 211 | letterSpacing: Dimension.Value; 212 | lineHeight: Number.Value; 213 | }; 214 | export type Value = WithAliasValue; 215 | export type Token = TokenSignature; 216 | } 217 | 218 | /* ------------------------------------------ 219 | Mapping Exports 220 | --------------------------------------------- */ 221 | export const tokenTypeNames = [ 222 | colorTypeName, 223 | dimensionTypeName, 224 | fontFamilyTypeName, 225 | fontWeightTypeName, 226 | durationTypeName, 227 | cubicBezierTypeName, 228 | numberTypeName, 229 | strokeStyleTypeName, 230 | borderTypeName, 231 | transitionTypeName, 232 | shadowTypeName, 233 | gradientTypeName, 234 | typographyTypeName, 235 | ] as const; 236 | 237 | export const tokenTypeNamesMapping = tokenTypeNames.reduce<{ 238 | [T in TokenTypeName]: T; 239 | }>((acc: any, t) => { 240 | acc[t] = t; 241 | return acc; 242 | }, {} as any); 243 | 244 | export type TokenTypeName = 245 | | Color.TypeName 246 | | Dimension.TypeName 247 | | FontFamily.TypeName 248 | | FontWeight.TypeName 249 | | Duration.TypeName 250 | | CubicBezier.TypeName 251 | | Number.TypeName 252 | | StrokeStyle.TypeName 253 | | Border.TypeName 254 | | Transition.TypeName 255 | | Shadow.TypeName 256 | | Gradient.TypeName 257 | | Typography.TypeName; 258 | 259 | export type DesignToken = 260 | | Color.Token 261 | | Dimension.Token 262 | | FontFamily.Token 263 | | FontWeight.Token 264 | | Duration.Token 265 | | CubicBezier.Token 266 | | Number.Token 267 | | StrokeStyle.Token 268 | | Border.Token 269 | | Transition.Token 270 | | Shadow.Token 271 | | Gradient.Token 272 | | Typography.Token; 273 | 274 | export type PickTokenByType = { 275 | color: Color.Token; 276 | dimension: Dimension.Token; 277 | fontFamily: FontFamily.Token; 278 | fontWeight: FontWeight.Token; 279 | duration: Duration.Token; 280 | cubicBezier: CubicBezier.Token; 281 | number: Number.Token; 282 | strokeStyle: StrokeStyle.Token; 283 | border: Border.Token; 284 | transition: Transition.Token; 285 | shadow: Shadow.Token; 286 | gradient: Gradient.Token; 287 | typography: Typography.Token; 288 | }[T]; 289 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Design Tokens Format Module 2 | 3 | *— A TypeScript implementation of the [Design Tokens Format Module](https://tr.designtokens.org/format/) specification along with some utility functions* 4 | 5 | ## Abstract 6 | 7 | This packages aims to provide the most agnostic JavaScript/TypeScript definitions from the [Design Tokens Format Module](https://tr.designtokens.org/format/) specification, for library developers and tooling creators. 8 | 9 | Join the conversation on the [W3C Design Tokens Community Group](https://github.com/design-tokens/community-group) repository. 10 | 11 | > ⚠️ Please note, the DTCG specification is NOT stable yet, breaking changes might occur in the future. 12 | 13 | ## Installation 14 | 15 | ### Using npm 16 | 17 | ```bash 18 | npm install design-tokens-format-module 19 | ``` 20 | 21 | ### Using yarn 22 | 23 | ```bash 24 | yarn add design-tokens-format-module 25 | ``` 26 | 27 | ### Using pnpm 28 | 29 | ```bash 30 | pnpm add design-tokens-format-module 31 | ``` 32 | 33 | ## Usage 34 | 35 | This module provides all the type definitions and the most basic helpers required to work with a JSON design token tree. 36 | 37 | ### Token tree 38 | 39 | Constrain a JSON object that represents a design token tree. 40 | 41 | ```typescript 42 | import { JSONTokenTree } from 'design-tokens-format-module'; 43 | 44 | const tokenTree = { 45 | color: { 46 | primary: { 47 | $type: 'color', 48 | $value: { 49 | colorSpace: 'srgb', 50 | components: [1, 0, 1], 51 | alpha: 1, 52 | }, 53 | }, 54 | }, 55 | spacing: { 56 | small: { 57 | $type: 'dimension', 58 | $value: { 59 | value: 8, 60 | unit: 'px', 61 | }, 62 | }, 63 | }, 64 | } satisfies JSONTokenTree; 65 | ``` 66 | 67 | ### Design Token 68 | 69 | Each design token type is available as a TypeScript namespace. 70 | 71 | ```typescript 72 | import { 73 | Color // Dimension, FontFamily... 74 | } from 'design-tokens-format-module'; 75 | 76 | declare function parseColorToken(token: unknown): Color.Token; 77 | declare function parseColorValue(tokens: unknown): Color.Value; 78 | declare function matchIsColorTokenTypeName( 79 | name: string, 80 | ): name is Color.TypeName; 81 | ``` 82 | 83 | #### Design token type names 84 | 85 | All token type names are available as a constant. 86 | 87 | ```typescript 88 | import { tokenTypeNames } from 'design-tokens-format-module'; 89 | 90 | for(const tokenTypeName of tokenTypeNames) { 91 | // color, dimension... 92 | } 93 | ``` 94 | 95 | ### All token types 96 | 97 | All token type signatures are available within a type union. 98 | 99 | ```typescript 100 | import { DesignToken } from 'design-tokens-format-module'; 101 | 102 | declare function parseDesignToken(token: unknown): DesignToken; 103 | ``` 104 | 105 | ### Matchers 106 | 107 | JSON values can be evaluated against the token signature 108 | 109 | ```typescript 110 | import { matchIsToken, matchIsTokenTypeName, matchIsAliasValue } from 'design-tokens-format-module'; 111 | 112 | function validateToken(token: unknown) { 113 | if (matchIsToken(token)) { 114 | const isValidType = matchIsTokenTypeName(token.$type ?? ''); 115 | if(matchIsAliasValue(token.$value)) { 116 | // ... 117 | } 118 | } 119 | // ... 120 | } 121 | ``` 122 | 123 | ### Alias utils 124 | 125 | Alias values can be validated and parsed. 126 | 127 | ```ts 128 | import { captureAliasPath } from 'design-tokens-format-module'; 129 | 130 | const result = captureAliasPath('{path.to.token}'); 131 | 132 | if(result.status === 'ok') { 133 | result.value // string[] 134 | } else { 135 | switch (result.error.tag) { 136 | case 'TYPE_ERROR': { 137 | result.error.message // Expected a string value. Got [x]. 138 | break; 139 | } 140 | case 'FORMAT_ERROR': { 141 | result.error.message // Expected an alias value. Got [x]. 142 | break; 143 | } 144 | } 145 | } 146 | ``` 147 | 148 | ### Enum-like constants 149 | 150 | Some token types have a fixed set of values. These are available as constants. 151 | 152 | ```typescript 153 | import { fontWeightValues, strokeStyleStringValues, strokeStyleLineCapValues } from 'design-tokens-format-module'; 154 | ``` 155 | 156 | ## Previous versions 157 | 158 | The packages goal has shifted from being a generic parser — which requires way more feedback — to a reliable source of truth for the DTCG implementations in the JavaScript land. 159 | 160 | > The features and APIs available before version 0.9.0 has been relocated to a [new location](https://github.com/nclsndr/design-tokens-tools/tree/main/packages/w3c-design-tokens-parser) where they get revamped and improved. 161 | 162 | ## Contributing 163 | 164 | If you find any typos, errors, or additional improvements, feel free to contribute to the project. 165 | 166 | ### Development 167 | 168 | Install dependencies. 169 | 170 | ```bash 171 | npm install 172 | ``` 173 | 174 | Run test in watch mode. 175 | 176 | ```bash 177 | npm run test 178 | ``` 179 | 180 | Please add tests to cover the new functionality or bug fix you are working upon. 181 | 182 | ### Before opening a PR 183 | 184 | We expect the tests and the build to pass for a PR to be reviewed and merged. 185 | 186 | ```bash 187 | npm run test --run 188 | ``` 189 | 190 | ```bash 191 | npm run build 192 | ``` 193 | 194 | ## API 195 | 196 | ### `AliasValue` (type) 197 | 198 | ```ts 199 | type AliasValue = `{${string}}`; 200 | ``` 201 | 202 | ### `Json` (namespace) 203 | 204 | ```ts 205 | namespace Json { 206 | export type Value = JSONValue; 207 | export type Object = JSONObject; 208 | export type Array = JSONArray; 209 | export type Primitive = string | number | boolean | null; 210 | } 211 | ``` 212 | ### JSONTokenTree (type) 213 | 214 | ```ts 215 | type JSONTokenTree = { 216 | [key: string]: DesignToken | JSONTokenTree | GroupProperties; 217 | } & GroupProperties; 218 | ``` 219 | 220 | ### `Color`,`Dimension`, ... (namespace) 221 | 222 | ```ts 223 | namespace TokenTypeName { 224 | export type TypeName = TypeName; 225 | export type Value = Value; 226 | export type Token = Token; 227 | } 228 | ``` 229 | 230 | ### `DesignToken` (type) 231 | 232 | ```ts 233 | type DesignToken = 234 | | ColorToken 235 | | DimensionToken 236 | // | ... 237 | ``` 238 | 239 | ### `TokenTypeName` (type) 240 | 241 | ```ts 242 | type TokenTypeName = 243 | | 'color' 244 | | 'dimension' 245 | // | ... 246 | ``` 247 | 248 | 249 | ### `captureAliasPath` (function) 250 | 251 | ```ts 252 | const CAPTURE_ALIAS_PATH_ERRORS = { 253 | TYPE_ERROR: 'Expected a string value.', 254 | // ... 255 | } as const; 256 | 257 | type ValidationError = { 258 | [k in keyof Writable]?: { 259 | message: string; 260 | }; 261 | }; 262 | 263 | type Result = 264 | | { 265 | status: 'ok'; 266 | value: T; 267 | error?: undefined; 268 | } 269 | | { 270 | status: 'error'; 271 | error: E; 272 | value?: undefined; 273 | }; 274 | 275 | declare function captureAliasPath( 276 | value: unknown, 277 | ): Result, ValidationError>; 278 | declare function captureAliasPath( 279 | value: unknown, 280 | asString: AsString, 281 | ): Result, ValidationError>; 282 | ``` 283 | 284 | Usage 285 | 286 | ```ts 287 | const result = captureAliasPath('{path.to.token}'); 288 | 289 | if(result.status === 'ok') { 290 | result.value // string[] 291 | } else { 292 | switch (result.error.tag) { 293 | case 'TYPE_ERROR': { 294 | result.error.message // Expected a string value. Got [x]. 295 | break; 296 | } 297 | case 'FORMAT_ERROR': { 298 | result.error.message // Expected an alias value. Got [x]. 299 | break; 300 | } 301 | } 302 | } 303 | ``` 304 | 305 | 306 | ### `matchIsAliasValue` (function) 307 | 308 | ```ts 309 | declare function matchIsAliasValue(candidate: unknown): candidate is AliasValue; 310 | ``` 311 | 312 | ### `matchIsGroup` (function) 313 | 314 | ```ts 315 | declare function matchIsGroup(candidate: unknown): candidate is JSONTokenTree; 316 | ``` 317 | 318 | ### `matchIsToken` (function) 319 | 320 | ```ts 321 | declare function matchIsToken(candidate: unknown): candidate is DesignToken; 322 | ``` 323 | 324 | ### `matchIsTokenTypeName` (function) 325 | 326 | ```ts 327 | declare function matchIsTokenTypeName(candidate: unknown): candidate is TokenTypeName; 328 | ``` 329 | 330 | 331 | ### `ALIAS_PATH_SEPARATOR` (constant) 332 | 333 | ```ts 334 | const ALIAS_PATH_SEPARATOR = '.'; 335 | ``` 336 | 337 | ### `tokenTypeNames` (constant) 338 | 339 | ```ts 340 | const tokenTypeNames = [ 341 | 'color', 342 | 'dimension', 343 | // ... 344 | ] as const; 345 | ``` 346 | 347 | ### `fontWeightValues` (constant) 348 | 349 | ```ts 350 | const fontWeightValues = [ 351 | 100, 352 | 'thin', 353 | 'hairline', 354 | // ... 355 | ] as const; 356 | ``` 357 | 358 | ### `strokeStyleStringValues` (constant) 359 | 360 | ```ts 361 | const strokeStyleStringValues = [ 362 | 'solid', 363 | 'dashed', 364 | // ... 365 | ] as const; 366 | ``` 367 | 368 | ### `strokeStyleLineCapValues` (constant) 369 | 370 | ```ts 371 | const strokeStyleLineCapValues = [ 372 | 'round', 373 | 'butt', 374 | // ... 375 | ] as const; 376 | ``` 377 | --------------------------------------------------------------------------------