Skip to content

Commit

Permalink
Change build strategy with templating via common build target config …
Browse files Browse the repository at this point in the history
…pattern
  • Loading branch information
vnphanquang committed Dec 6, 2024
1 parent 877ebea commit f3e0ce7
Show file tree
Hide file tree
Showing 44 changed files with 576 additions and 590 deletions.
16 changes: 16 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Editor configuration, see https://editorconfig.org

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = tab
indent_size = 2
trim_trailing_whitespace = true
max_line_length = 100

[*.yaml]
indent_style = space

1 change: 1 addition & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
- main
paths:
- "scripts/**/*"
- "tests/**/*"
- ".github/workflows/tests.yaml"
pull_request:
branches:
Expand Down
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
## 1.3.0 (2024-11-25)
# Changelog

## 1.4.0

### Minor Changes

- [#14](https://github.com/evilmartians/harmony/pull/14) [`d3f6327`](https://github.com/evilmartians/harmony/commit/d3f6327d0113be26d1c3cc0468987700784726fe) Thanks [@vnphanquang](https://github.com/vnphanquang)! - set pacakge as ESM-first, prioritize ESM exports as `.js`, update CommonJS exports as `.cjs`, fix [publint](https://publint.dev/@evilmartians/[email protected]) recommendations

## 1.3.0 (2024-11-25)

- Add support for Tailwind v4

## 1.2.0 (2023-11-25)
Expand Down
5 changes: 3 additions & 2 deletions deno.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"tasks": {
"build": "deno run --allow-read --allow-write scripts/build.ts",
"publint": "deno run --allow-read --allow-env npm:publint",
"test": "deno test --allow-read --allow-write",
"publint": "deno lint dist && deno check dist && deno run --allow-read --allow-env npm:publint",
"test": "deno test --allow-read --allow-write --watch",
"update-snapshots": "deno test --allow-read --allow-write -- --update",
"changesets": "deno run -A npm:@changesets/cli",
"ci:test": "deno test -A --clean --coverage=coverage --junit-path=coverage/junit.xml",
Expand All @@ -20,6 +20,7 @@
},
"nodeModulesDir": "auto",
"imports": {
"@lambdalisue/sandbox": "jsr:@lambdalisue/sandbox@^2.0.1",
"@std/assert": "jsr:@std/assert@^1.0.8",
"@std/path": "jsr:@std/path@^1.0.8",
"@std/testing": "jsr:@std/testing@^1.0.5"
Expand Down
11 changes: 11 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"devDependencies": {
"@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "^2.27.10",
"mustache": "^4.2.0",
"publint": "^0.2.12",
"zod": "^3.23.8"
},
Expand Down
107 changes: 8 additions & 99 deletions scripts/build.ts
Original file line number Diff line number Diff line change
@@ -1,102 +1,11 @@
import * as z from "zod";
import * as path from "@std/path";
import { buildTailwindPalette } from "./targets/tailwind.ts";
import { buildBasicPalette } from "./targets/base.ts";
import { ExportTarget, PaletteWithFallback } from "./types.ts";
import { buildCssVars } from "./targets/cssVariables.ts";
import { buildTailwindv4Palette } from "./targets/tailwind-v4.ts";
import { build } from "./builder.ts";
import base from "./targets/base/base.config.ts";
import css from "./targets/css/css.config.ts";
import tailwind from "./targets/tailwind/tailwind.config.ts";
import source from "../source.json" with { type: "json" };

//
// Config
//
const SOURCE_FILE = "./source.json";
const DIST_DIR = path.join(Deno.cwd(), "dist");
const EXPORT_TARGETS = [
{
targetDir: "base",
target: buildBasicPalette,
},
{
targetDir: "tailwind",
target: buildTailwindPalette,
},
{
targetDir: "tailwind",
target: buildTailwindv4Palette,
},
{
targetDir: "css",
target: buildCssVars,
},
];
const configs = [base, css, tailwind];
const dir = path.join(Deno.cwd(), "dist");

//
// SOURCE_FILE schema
//
const SourceSchema = z.record(
z.string().regex(/\w+\/\d+/).toLowerCase().describe(
'Color name and shade. Example: "red/500"',
),
z.object({
$oklch: z.string().describe(
'Color in Oklch format. Example: "oklch(98.83% 0.005 20)"',
),
$srgbFallback: z.string().describe(
'Fallback color in sRGB format. Example: "#ffffff"',
),
}),
);

//
// Main
//
await createDistDir(DIST_DIR);
const palette = await loadPalette(SOURCE_FILE);
await Promise.all(
EXPORT_TARGETS.map(({ targetDir, target }) =>
runExportTarget(path.join(DIST_DIR, targetDir), target, palette)
),
);

//
// Helper functions
//
async function loadPalette(fileName: string): Promise<PaletteWithFallback> {
const content = await Deno.readTextFile(fileName);
const sourcePalette = SourceSchema.parse(JSON.parse(content.toString()));

const result: PaletteWithFallback = {};

for (const [key, value] of Object.entries(sourcePalette)) {
const [name, shade] = key.split("/") as [string, string];
if (!result[name]) {
result[name] = {};
}
result[name][shade] = {
oklch: value.$oklch,
rgbFallback: value.$srgbFallback,
};
}

return result;
}

async function runExportTarget(
targetDir: string,
target: ExportTarget,
palette: PaletteWithFallback,
) {
await Deno.mkdir(targetDir, { recursive: true });
await target({ targetDir, palette });
}

async function createDistDir(dir: string) {
try {
await Deno.remove(dir, { recursive: true });
} catch (err) {
if (!(err instanceof Deno.errors.NotFound)) {
throw err;
}
}
await Deno.mkdir(dir);
}
await build(source, dir, configs);
80 changes: 80 additions & 0 deletions scripts/builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import * as z from "zod";
import { BuildConfig, PaletteWithFallback } from "./types.ts";
import mustache from "mustache";
import * as path from "@std/path";

//
// SOURCE_FILE schema
//
const SourceSchema = z.record(
z.string().regex(/\w+\/\d+/).toLowerCase().describe(
'Color name and shade. Example: "red/500"',
),
z.object({
$oklch: z.string().describe(
'Color in Oklch format. Example: "oklch(98.83% 0.005 20)"',
),
$srgbFallback: z.string().describe(
'Fallback color in sRGB format. Example: "#ffffff"',
),
}),
);

export type PaletteSource = z.infer<typeof SourceSchema>;

export function defineBuildConfig<C extends BuildConfig>(config: C): C {
return config;
}

export async function build(
source: PaletteSource,
dir: string,
configs: BuildConfig[],
): Promise<string[]> {
// STEP 1: parse palette from source
const parsed = SourceSchema.parse(source);

// STEP 2: prepare palette into disgestive array for easier processing during build
const map = new Map<string, PaletteWithFallback[number]>();
for (const [key, value] of Object.entries(parsed)) {
const [colorName, shadeName] = key.split("/");
let color = map.get(colorName);
if (!color) {
color = { colorName, shades: [] };
map.set(colorName, color);
}
color.shades.push({
shadeName,
oklch: value.$oklch,
srgbFallback: value.$srgbFallback,
});
}
const palette: PaletteWithFallback = Array.from(map.values());

// STEP 3: clean output dir to avoid stale files
try {
await Deno.remove(dir, { recursive: true });
} catch (err) {
if (!(err instanceof Deno.errors.NotFound)) {
throw err;
}
}

// STEP 4: build targets
const filepaths = await Promise.all(configs.flatMap((config) => {
const target = typeof config === "function" ? config(palette) : config;
return target.outputs.map(async (output) => {
const template = await Deno.readTextFile(output.templatePath);
const vars = output.templateVars ?? { palette };
const content = mustache.render(template, vars);
const targetDir = path.join(dir, target.dir);
const targetFile = path.join(targetDir, output.file);
await Deno.mkdir(targetDir, { recursive: true });
await Deno.writeTextFile(targetFile, content);

return targetFile;
});
}));

return filepaths;
}
20 changes: 20 additions & 0 deletions scripts/figma.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import source from "../source.json" with { type: "json" };

const variables = {};
const colors = ["red", "orange", "yellow", "emerald", "sky", "sand"];

for (const [key, value] of Object.entries(source)) {
let [color, shade] = key.toLowerCase().split("/");
if (!colors.includes(color)) continue;

if (!(color in variables)) {
variables[color] = {};
}
variables[color][shade] = {
$scopes: ['ALL_SCOPES'],
$type: 'color',
$value: value.$value,
}
}

console.log(JSON.stringify(variables));
44 changes: 0 additions & 44 deletions scripts/targets/__snapshots__/base_test.ts.snap

This file was deleted.

Loading

0 comments on commit f3e0ce7

Please sign in to comment.