Skip to content
Merged
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
2 changes: 2 additions & 0 deletions tools/extract-tokens/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ ts_library(
devmode_module = "commonjs",
tsconfig = ":tsconfig.json",
deps = [
"//tools/highlight-files:sources",
"@npm//@types/node",
"@npm//sass",
],
Expand All @@ -19,6 +20,7 @@ nodejs_binary(
name = "extract-tokens",
data = [
":extract_tokens_lib",
"@npm//highlight.js",
"@npm//sass",
],
entry_point = ":extract-tokens.ts",
Expand Down
53 changes: 49 additions & 4 deletions tools/extract-tokens/extract-tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {readFileSync, writeFileSync} from 'fs';
import {pathToFileURL} from 'url';
import {relative, join, dirname} from 'path';
import {compileString} from 'sass';
import {highlightCodeBlock} from '../highlight-files/highlight-code-block';

/** Information extracted for a single token from the theme. */
interface ExtractedToken {
Expand Down Expand Up @@ -31,6 +32,16 @@ interface Token {
derivedFrom?: string;
}

/** Information extracted from a theme file. */
interface ThemeData {
/** Name of the theme file. */
name: string;
/** Name of the `overrides` mixin within the file. */
overridesMixin: string;
/** Tokens that can be used in the `overrides` mixin. */
tokens: Token[];
}

// Script that extracts the tokens from a specific Bazel target.
if (require.main === module) {
const [packagePath, outputPath, ...inputFiles] = process.argv.slice(2);
Expand All @@ -52,20 +63,19 @@ if (require.main === module) {
throw new Error(`Could not find theme files in ${packagePath}`);
}

const themes: {name: string; overridesMixin: string; tokens: Token[]}[] = [];
const themes: ThemeData[] = [];

themeFiles.forEach(theme => {
const tokens = extractTokens(theme.filePath);
themes.push({
name: theme.mixinPrefix,
// This can be derived from the `name` already, but we want the source
// of truth to be in this repo, instead of whatever page consumes the data.
overridesMixin: `${theme.mixinPrefix}-overrides`,
tokens,
tokens: extractTokens(theme.filePath),
});
});

writeFileSync(outputPath, JSON.stringify(themes));
writeFileSync(outputPath, JSON.stringify({example: getUsageExample(themes), themes}));
}

/**
Expand Down Expand Up @@ -137,6 +147,41 @@ function extractTokens(themePath: string): Token[] {
});
}

/**
* Generates a highlighted code snippet that illustrates how an overrides mixin can be used.
* @param themes Themes that were extracted from a specific entrypoint. One of these themes will
* be used as an example.
*/
function getUsageExample(themes: ThemeData[]): string | null {
const mixin = themes.find(theme => theme.tokens.length > 0);

if (!mixin) {
return null;
}

// Pick out a couple of color tokens to show as examples.
const firstToken = mixin.tokens.find(token => token.type === 'color');
const secondToken = mixin.tokens.find(token => token.type === 'color' && token !== firstToken);

if (!firstToken) {
return null;
}

const lines = [
`@use '@angular/material' as mat;`,
``,
`// Customize the entire app. Change :root to your selector if you want to scope the styles.`,
`:root {`,
` @include mat.${mixin.overridesMixin}((`,
` ${firstToken.overridesName}: orange,`,
...(secondToken ? [` ${secondToken.overridesName}: red,`] : []),
` ));`,
`}`,
];

return highlightCodeBlock(lines.join('\n'), 'scss');
}

/**
* Generates the code that can be added around a theme file in order to extract its tokens.
* @param srcPath Absolute path to the source root.
Expand Down
Loading